Some C++ developers also use Python for their application development. There are several ways to integrate the two languages together. One way is to create Python extension modules containing C++ functions that implement new object types and functions. Another way is to use the Boost Python C++ library that enables interoperability between the Python and C++ languages. A third way is to use the productivity, resusability, and encapsulation of components to to integrate C++Builder and Python. In this chapter you’ll learn how to use the Python4Delphi open source components in your VCL applications.
Introduction to Python4Delphi (and C++Builder)
Python for Delphi (P4D) is a set of free components (MIT Open Source License), created by Kiriakos Vlahos author of the popular PyScripter Python IDE, that wrap up the Python DLL into Delphi. The components allow you to create or extend your Delphi and C++Builder applications to execute Python scripts, create new Python modules and new Python types. You can also create Python extensions as DLLs and much more.
You’ll find Python4Delphi on GitHub at https://github.com/pyscripter/python4delphi. The GitHub project includes a readme file, installation notes, supported platforms, how Python4Delphi finds your Python distributions, tutorials and demos.
Jim McKeeth recently hosted a webinar with Kiriakos, “Python for Delphi Developers Part 1 – Introduction” (replay is available on YouTube). A Part 2 Python for Delphi Developers will take place on Wednesday, October 14, 2020 at 7am Pacific Time. While this webinar series focuses on Delphi programming, it also provides information about the Python4Delphi components and Python programming that can help C++Builder developers.
While the webinar and Python4Delphi speaks to Delphi developers, C++Builder developers can compile and install the components for use in their Win32 and Win64 C++ VCL applications. To build and install the Python4Delphi components you can use all editions of C++Builder (community, professional, enterprise and architect) and RAD Studio (professional, enterprise and architect) for versions 10.3.3, 10.4 and 10.4.1. If you only have C++Builder, you’ll learn how to use the included Delphi DCC32 and DCC64 command line compilers to build the Delphi component package project and install the components.
Installing Python for Windows (32 and 64 bit)
Before you start using the Python4Delphi components in your C++Builder VCL applications you’ll need to make sure you have Python for Win32 and Win64 installed on your computer.
You can download and install releases of Python from the Python.org web site. For Win32 and Win64 you will find installers at https://www.python.org/downloads/windows/
To find Python distributions installed on your computer, use the “where python.exe” Windows command.
By default, Python for Win32 installs into the C:\Users\david\AppData\Local\Programs\Python\Python39-32\ folder (or wherever you tell the install to put the distribution).
By default, Python for Win64 installs into the C:\Users\david\AppData\Local\Programs\Python\Python39\ folder (or wherever you tell the install to put the distribution).
Installing Python4Delphi and Using the Components
The following are the steps I followed to download and build the Python4Delphi components for use with C++Builder 10.3.3, 10.4 and 10.4.1. While I used RAD Studio (which includes C++Builder and Delphi), you can also use C++Builder along with the Delphi command line compilers to compile and install the components.
Step 1 – Download the latest release of the Python4Delphi
Grab the python4delphi-master.zip file (https://github.com/pyscripter/python4delphi) and unzip it to your hard drive (I put it in my C:\Users\david\Documents\Embarcadero\Studio\Projects/ folder).
Step 2 – In the IDE open the Python_D package project file (RAD Studio editions)
In the C++Builder 10.4.1 RAD Studio IDE, open the Python_D.dproj package project file (you’ll find it in the “python4delphi-master\Packages\Delphi\Delphi 10.4+” folder).
Step 3 – Add an $IFDEF around the requires DesignIDE unit
Look at the Python_D.dpk source file, if you don’t see an $IFDEF around the DesignIDE unit, add it to avoid a compiler error when using the Win64 C++ compiler – DesignIDE is only required for Win32 since the IDE is a 32-bit Windows app.
Notice (in the source code above) that the LibSuffix Delphi compiler directive is set to “AUTO”. This can be done in source code or in the Project | Options | Description page (in the image below) to match the package file suffix with other compiled package files. The suffix is applied before the file extension. In drop down list, you can select the $(Auto) option for the suffix to represent the compiler version suffix for binary package files.
There is a separate Python_D.dpk package source file for versions 10.3 and earlier in the “python4delphi-master\Packages\Delphi\Delphi 10.3-” folder. In this package source file there are $IFDEFs to set the LIBSUFFIX for several recent Delphi compiler releases.
If you are going to use this earlier Python_D.dpk project you may need to comment out (or remove) the “{$R *.res}” statement at the front of the package source file (it may have already been removed in the latest commit of Python4Delphi).
Step 4a – Build and Install the Python4Delphi components with RAD Studio
There are two ways to build and install the components depending on whether you have RAD Studio or one of the C++Builder editions. If you only have C++Builder skip to “Step 4b” to learn how to use the Delphi command line compilers for Win32 and Win64.
Set the Python4Delphi Project Options for the Delphi Compiler | C/C++ Output file generation for Win32 and Win64 platform (all configurations – debug and release). Build and Install the Python4Delphi components for Win32 and Win64 targets.
Building and installing the components will make sure you have the generated C++ header files, package import library files and package static library files for your C++ VCL Win32 and Win64 projects.
From the help file: the “Generate all C++Builder files (including package libs)” option generates the package and all Delphi pieces, along with all necessary header files (.hpp), package import library file (.bpi), and package static library file (.lib and .a) for C++ projects. This is the default in desktop platforms.
Set the Delphi Compiler Search Path to include the Python4Delphi source directory so that the compiler will find any required include files and other files.
Step 4b – Use the Delphi command line compilers to Build and Installing the components
You can use batch files (or other script files) that run the Delphi command line compilers for Win32 (DCC32.exe) and Win64 (DCC64.exe). These Delphi compilers (included in the bin folder) will build the Python4Delphi package file and create the C++ header files, compiled package file, static library and other files required for use in your C++ applications.
CompilePython4DelphiPackage4Win32.bat
@ECHO OFF ECHO Compiling Python4Delphi Component Package for Win32 dcc32 Python_D.dpk ^ -I"C:\Users\david\Documents\Embarcadero\Studio\Projects\Python4Delphi\python4delphi-master\Source" ^ -LE"C:\Users\Public\Documents\Embarcadero\Studio\20.0\Bpl" ^ -LN"C:\Users\Public\Documents\Embarcadero\Studio\20.0\Dcp" ^ -NH"C:\Users\Public\Documents\Embarcadero\Studio\20.0\hpp\Win32" ^ -NB"C:\Users\Public\Documents\Embarcadero\Studio\20.0\Dcp" ^ -E"C:\Users\Public\Documents\Embarcadero\Studio\20.0\Dcp" ^ -JL ^ --lib-suffix:260 ^ -NSsystem;vcl;winapi;system.win ^ -u"c:\program files (x86)\embarcadero\studio\20.0\lib\win32\release" move /y "C:\Users\david\Documents\Embarcadero\Studio\Projects\Python4Delphi\python4delphi-master\Packages\Delphi\Delphi 10.3-\Python_D.lib" "C:\Users\Public\Documents\Embarcadero\Studio\20.0\Dcp\Python_D.lib" ECHO Completed Python4Delphi Component Package Win32 pause
CompilePython4DelphiPackage4Win64.bat
@ECHO OFF ECHO Compiling Python4Delphi Component Package for Win64 dcc64 Python_D.dpk ^ -I"C:\Users\david\Documents\Embarcadero\Studio\Projects\Python4Delphi\python4delphi-master\Source" ^ -LE"C:\Users\Public\Documents\Embarcadero\Studio\20.0\Bpl\Win64" ^ -LN"C:\Users\Public\Documents\Embarcadero\Studio\20.0\Dcp\Win64" ^ -NH"C:\Users\Public\Documents\Embarcadero\Studio\20.0\hpp\Win64" ^ -NB"C:\Users\Public\Documents\Embarcadero\Studio\20.0\Dcp\Win64" ^ -E"C:\Users\Public\Documents\Embarcadero\Studio\20.0\Dcp\Win64" ^ -JL ^ --lib-suffix:260 ^ -NSsystem;vcl;winapi;system.win ^ -u"c:\program files (x86)\embarcadero\studio\20.0\lib\win64\release" move /y "C:\Users\david\Documents\Embarcadero\Studio\Projects\Python4Delphi\python4delphi-master\Packages\Delphi\Delphi 10.3-\Python_D.a" "C:\Users\Public\Documents\Embarcadero\Studio\20.0\Dcp\Win64\Python_D.a" ECHO Completed Python4Delphi Component Package Win64 pause
Install he Python4Delphi Package
In the C++Builder IDE, use the Components | Install Packages menu item and click the “Add…” button.
Navigate to the C:\Users\Public\Documents\Embarcadero\Studio\21.0\Bpl folder (the number will depend on which version of C++Builder you have) and select the Design time package (BPL) file and click the Open button. This will add the package and components to the IDE. You’ll now see “Components for Python” in the list of Design time packages. Highlight the entry and click the Components button to display the list of components in the package.
Step 4c – Verify that the generated Python4Delphi files for C++ use are generated
After you compile the Python4Delphi package project for Win32 and Win64 target platforms the following files will be generated:
C:\Users\Public\Documents\Embarcadero\Studio\21.0\hpp\Win32
Python_D.hpp
PythonEngine.hpp
PythonGUIInputOutput.hpp
MethodCallBack.hpp
WrapDelphi.hpp
C:\Users\Public\Documents\Embarcadero\Studio\21.0\hpp\Win64
Python_D.hpp
PythonEngine.hpp
PythonGUIInputOutput.hpp
MethodCallBack.hpp
WrapDelphi.hpp
C:\Users\Public\Documents\Embarcadero\Studio\21.0\Dcp
Python_D.bpi
Python_D.dcp
Python_D.lib
C:\Users\Public\Documents\Embarcadero\Studio\21.0\Dcp\Win64
Python_D.a
Python_D.bpi
Python_D.dcp
C:\Users\Public\Documents\Embarcadero\Studio\21.0\Bpl
Python_D270.bpl
C:\Users\Public\Documents\Embarcadero\Studio\21.0\Bpl\Win64
Python_D270.bpl
Python_D270.rsm
In the IDE you’ll now see the components in the Component Palette window.
Building Your First C++Builder Python4Delphi VCL Application
Using RAD Studio, I opened the Python4Delphi Demo1 Delphi project and tested it to make sure that I had the components and Python working. C:\Users\david\Documents\Embarcadero\Studio\Projects\Python4Delphi\python4delphi-master\Demos\Demo01
Use File | New | C++Builder VCL application to create a starting C++Builder project (note: the source code for the project is in a zip file listed in the References section). I copied all of the components from the Delphi version of the Demo01 form file.
Demo01Unit.dfm file
object Form2: TForm2 Left = 0 Top = 0 Caption = 'Demo 01 Python (C++, VCL)' ClientHeight = 344 ClientWidth = 534 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False PixelsPerInch = 96 TextHeight = 13 object Splitter1: TSplitter Left = 0 Top = 153 Width = 534 Height = 3 Cursor = crVSplit Align = alTop Color = clBtnFace ParentColor = False ExplicitWidth = 536 end object Memo1: TMemo Left = 0 Top = 156 Width = 534 Height = 144 Align = alClient Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -13 Font.Name = 'Consolas' Font.Pitch = fpVariable Font.Style = [] Lines.Strings = ( 'print(2+2)') ParentFont = False ScrollBars = ssBoth TabOrder = 0 end object Panel1: TPanel Left = 0 Top = 300 Width = 534 Height = 44 Align = alBottom BevelOuter = bvNone TabOrder = 1 object Button1: TButton Left = 0 Top = 6 Width = 115 Height = 25 Caption = 'Execute script' TabOrder = 0 OnClick = Button1Click end object Button2: TButton Left = 167 Top = 6 Width = 91 Height = 25 Caption = 'Load script...' TabOrder = 1 OnClick = Button2Click end object Button3: TButton Left = 264 Top = 8 Width = 89 Height = 25 Caption = 'Save script...' TabOrder = 2 OnClick = Button3Click end end object Memo2: TMemo Left = 0 Top = 0 Width = 534 Height = 153 Align = alTop Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -13 Font.Name = 'Consolas' Font.Pitch = fpVariable Font.Style = [] ParentFont = False ScrollBars = ssBoth TabOrder = 2 end object PythonEngine1: TPythonEngine IO = PythonGUIInputOutput1 Left = 32 Top = 32 end object OpenDialog1: TOpenDialog DefaultExt = '*.py' Filter = 'Python files|*.py|Text files|*.txt|All files|*.*' Title = 'Open' Left = 240 Top = 32 end object SaveDialog1: TSaveDialog DefaultExt = '*.py' Filter = 'Python files|*.py|Text files|*.txt|All files|*.*' Title = 'Save As' Left = 328 Top = 32 end object PythonGUIInputOutput1: TPythonGUIInputOutput UnicodeIO = True RawOutput = False Output = Memo2 Left = 128 Top = 32 end end
Demo01Unit.h file
//--------------------------------------------------------------------------- #ifndef Demo01UnitH #define Demo01UnitH //--------------------------------------------------------------------------- #include <System.Classes.hpp> #include <Vcl.Controls.hpp> #include <Vcl.StdCtrls.hpp> #include <Vcl.Forms.hpp> #include "PythonEngine.hpp" #include <Vcl.Dialogs.hpp> #include <Vcl.ExtCtrls.hpp> #include "PythonGUIInputOutput.hpp" //--------------------------------------------------------------------------- class TForm2 : public TForm { __published: // IDE-managed Components TSplitter *Splitter1; TMemo *Memo1; TPanel *Panel1; TButton *Button1; TButton *Button2; TButton *Button3; TMemo *Memo2; TPythonEngine *PythonEngine1; TOpenDialog *OpenDialog1; TSaveDialog *SaveDialog1; TPythonGUIInputOutput *PythonGUIInputOutput1; void __fastcall Button1Click(TObject *Sender); void __fastcall Button2Click(TObject *Sender); void __fastcall Button3Click(TObject *Sender); private: // User declarations public: // User declarations __fastcall TForm2(TComponent* Owner); }; //--------------------------------------------------------------------------- extern PACKAGE TForm2 *Form2; //--------------------------------------------------------------------------- #endif
Next, add OnClick event handlers for the 3 buttons.
Demo01Unit.cpp file
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Demo01Unit.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma link "PythonEngine" #pragma link "PythonGUIInputOutput" #pragma resource "*.dfm" TForm2 *Form2; //--------------------------------------------------------------------------- __fastcall TForm2::TForm2(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm2::Button1Click(TObject *Sender) { PythonEngine1->ExecStrings( Memo1->Lines ); } //--------------------------------------------------------------------------- void __fastcall TForm2::Button2Click(TObject *Sender) { if (OpenDialog1->Execute()) { Memo1->Lines->LoadFromFile( OpenDialog1->FileName ); } } //--------------------------------------------------------------------------- void __fastcall TForm2::Button3Click(TObject *Sender) { if (SaveDialog1->Execute()) { Memo1->Lines->SaveToFile( SaveDialog1->FileName ); } } //---------------------------------------------------------------------------
Save the project to a folder.
Compile and Run the C++ VCL Demo program and try some Python code
In the TMemo at the bottom of the form, type in some Python code. In my example I print the sum of two numbers, print the value of Pi from the Python math library and print the Python version # from the Python platform library. You can also use the Load and Save script buttons to bring up dialog boxes to load and save Python script files. Click the Execute script button to see the results show up in the upper TMemo.
References
Python4Delphi and PyScripter
Python4Delphi on GitHub by Kiriakos Vlahos – https://github.com/pyscripter/python4delphi
Webinar Replay – Python for Delphi Developers – Part 1 – Introduction – https://blogs.embarcadero.com/webinar-replay-python-for-delphi-developers-part-1-introduction/
PyScripter on GitHub by Kiriakos Vlahos – https://github.com/pyscripter/pyscripter
Python for Windows
Python Releases for Windows (python.org) – https://www.python.org/downloads/windows/
Embarcadero DocWiki
Creating Packages and DLLs – http://docwiki.embarcadero.com/RADStudio/en/Creating_Packages_and_DLLs
Project | Options | Output – C/C++ – http://docwiki.embarcadero.com/RADStudio/en/Output_-_C/C%2B%2B
Project | Options | Description – http://docwiki.embarcadero.com/RADStudio/en/Descripti
Package Files Created by Compiling – http://docwiki.embarcadero.com/RADStudio/en/Package_Files_Created_by_Compiling
DCC32.EXE, the Delphi Command Line Compiler – http://docwiki.embarcadero.com/RADStudio/en/DCC32.EXE,_the_Delphi_Command_Line_Compiler
DCC64.EXE, the Delphi 64-bit Command Line Compiler – http://docwiki.embarcadero.com/RADStudio/en/DCC64.EXE,_the_Delphi_64-bit_Command_Line_Compiler
Delphi 32-bit compiler (DCC32.exe) cmd line help (from C++Builder Community Edition 10.3.3)
Embarcadero Delphi for Win32 compiler version 33.0 Copyright (c) 1983,2018 Embarcadero Technologies, Inc. Syntax: dcc32 [options] filename [options] -A<unit>=<alias> = Set unit alias -B = Build all units -CC = Console target -CG = GUI target -D<syms> = Define conditionals -E<path> = EXE/DLL output directory -F<offset> = Find error -GD = Detailed map file -GP = Map file with publics -GS = Map file with segments -H = Output hint messages -I<paths> = Include directories -J = Generate .obj file -JPHNE = Generate C++ .obj file, .hpp file, in namespace, export all -JL = Generate package .lib, .bpi, and all .hpp files for C++ -K<addr> = Set image base addr -LE<path> = package .bpl output directory -LN<path> = package .dcp output directory -LU<package> = Use package -M = Make modified units -NU<path> = unit .dcu output directory -NH<path> = unit .hpp output directory -NO<path> = unit .obj output directory -NB<path> = unit .bpi output directory -NX<path> = unit .xml output directory -NS<namespaces> = Namespace search path -O<paths> = Object directories -P = look for 8.3 file names also -Q = Quiet compile -R<paths> = Resource directories -TX<ext> = Output name extension -U<paths> = Unit directories -V = Debug information in EXE -VR = Generate remote debug (RSM) -VT = Debug information in TDS -VN = TDS symbols in namespace -W[+|-|^][warn_id] = Output warning messages -Z = Output 'never build' DCPs -$<dir> = Compiler directive --help = Show this help screen --version = Show name and version --codepage:<cp> = specify source file encoding --default-namespace:<namespace> = set namespace --depends = output unit dependency information --doc = output XML documentation --drc = output resource string .drc file --no-config = do not load default dcc32.cfg file --description:<string> = set executable description --inline:{on|off|auto} = function inlining control --legacy-ifend = allow legacy $IFEND directive --zero-based-strings[+|-] = strings are indexed starting at 0 --peflags:<flags> = set extra PE Header flags field --peoptflags:<flags> = set extra PE Header optional flags field --peosversion:<major>.<minor> = set OS Version fields in PE Header (default: 5.0) --pesubsysversion:<major>.<minor> = set Subsystem Version fields in PE Header (default: 5.0) --peuserversion:<major>.<minor> = set User Version fields in PE Header (default: 0.0) --lib-version:<version> = Output package name version --lib-suffix:<suffix> = Output package name suffix Compiler switches: -$<letter><state> (defaults are shown below) A8 Aligned record fields B- Full boolean Evaluation C+ Evaluate assertions at runtime D+ Debug information G+ Use imported data references H+ Use long strings by default I+ I/O checking J- Writeable structured consts L+ Local debug symbols M- Runtime type info O+ Optimization P+ Open string params Q- Integer overflow checking R- Range checking T- Typed @ operator U- Pentium(tm)-safe divide V+ Strict var-strings W- Generate stack frames X+ Extended syntax Y+ Symbol reference info Z1 Minimum size of enum types Stack size: -$M<minStackSize[,maxStackSize]> (default 16384,1048576)
Delphi 64-bit compiler (DCC64.exe) cmd line help (C++Builder Community Edition 10.3.3)
Embarcadero Delphi for Win64 compiler version 33.0 Copyright (c) 1983,2018 Embarcadero Technologies, Inc. Syntax: dcc64 [options] filename [options] -A<unit>=<alias> = Set unit alias -B = Build all units -CC = Console target -CG = GUI target -D<syms> = Define conditionals -E<path> = EXE/DLL output directory -F<offset> = Find error -GD = Detailed map file -GP = Map file with publics -GS = Map file with segments -H = Output hint messages -I<paths> = Include directories -J = Generate .obj file -JPHNE = Generate C++ .obj file, .hpp file, in namespace, export all -JL = Generate package .lib, .bpi, and all .hpp files for C++ -K<addr> = Set image base addr -LE<path> = package .bpl output directory -LN<path> = package .dcp output directory -LU<package> = Use package -M = Make modified units -NU<path> = unit .dcu output directory -NH<path> = unit .hpp output directory -NO<path> = unit .obj output directory -NB<path> = unit .bpi output directory -NX<path> = unit .xml output directory -NS<namespaces> = Namespace search path -O<paths> = Object directories -P = look for 8.3 file names also -Q = Quiet compile -R<paths> = Resource directories -TX<ext> = Output name extension -U<paths> = Unit directories -V = Debug information in EXE -VR = Generate remote debug (RSM) -VT = Debug information in TDS -VN = TDS symbols in namespace -W[+|-|^][warn_id] = Output warning messages -Z = Output 'never build' DCPs -$<dir> = Compiler directive --help = Show this help screen --version = Show name and version --codepage:<cp> = specify source file encoding --default-namespace:<namespace> = set namespace --depends = output unit dependency information --doc = output XML documentation --drc = output resource string .drc file --no-config = do not load default dcc64.cfg file --description:<string> = set executable description --inline:{on|off|auto} = function inlining control --legacy-ifend = allow legacy $IFEND directive --zero-based-strings[+|-] = strings are indexed starting at 0 --peflags:<flags> = set extra PE Header flags field --peoptflags:<flags> = set extra PE Header optional flags field --peosversion:<major>.<minor> = set OS Version fields in PE Header (default: 5.0) --pesubsysversion:<major>.<minor> = set Subsystem Version fields in PE Header (default: 5.0) --peuserversion:<major>.<minor> = set User Version fields in PE Header (default: 0.0) --lib-version:<version> = Output package name version --lib-suffix:<suffix> = Output package name suffix Compiler switches: -$<letter><state> (defaults are shown below) A8 Aligned record fields B- Full boolean Evaluation C+ Evaluate assertions at runtime D+ Debug information G+ Use imported data references H+ Use long strings by default I+ I/O checking J- Writeable structured consts L+ Local debug symbols M- Runtime type info O+ Optimization P+ Open string params Q- Integer overflow checking R- Range checking T- Typed @ operator V+ Strict var-strings W- Generate stack frames X+ Extended syntax Y+ Symbol reference info Z1 Minimum size of enum types Stack size: -$M<minStackSize[,maxStackSize]> (default 16384,1048576)
C++ Demo project and Delphi command line package build batch files (zip file)
A zip file is available for download at http://davidi.com/code/Python4DelphiDemo01.zip