This chapter briefly explains how to create a Windows extension module forPython using Microsoft Visual C++, and follows with more detailed backgroundinformation on how it works. The explanatory material is useful for both theWindows programmer learning to build Python extensions and the Unix programmerinterested in producing software which can be successfully built on both Unixand Windows.
Module authors are encouraged to use the distutils approach for buildingextension modules, instead of the one described in this section. You will stillneed the C compiler that was used to build Python; typically Microsoft VisualC++.
Note
This chapter mentions a number of filenames that include an encoded Pythonversion number. These filenames are represented with the version number shownasXY; in practice,'X' will be the major version number and'Y'will be the minor version number of the Python release you’re working with. Forexample, if you are using Python 2.2.1,XY will actually be22.
There are two approaches to building extension modules on Windows, just as thereare on Unix: use thedistutils package to control the build process, ordo things manually. The distutils approach works well for most extensions;documentation on usingdistutils to build and package extension modulesis available inDistributing Python Modules. This section describes the manualapproach to building Python extensions written in C or C++.
To build extensions using these instructions, you need to have a copy of thePython sources of the same version as your installed Python. You will needMicrosoft Visual C++ “Developer Studio”; project files are supplied for VC++version 7.1, but you can use older versions of VC++. Notice that you should usethe same version of VC++that was used to build Python itself. The example filesdescribed here are distributed with the Python sources in thePC\example_nt\ directory.
Copy the example files — Theexample_nt directory is asubdirectory of thePC directory, in order to keep all the PC-specificfiles under the same directory in the source distribution. However, theexample_nt directory can’t actually be used from this location. Youfirst need to copy or move it up one level, so thatexample_nt is asibling of thePC andInclude directories. Do all your workfrom within this new location.
Open the project — From VC++, use theFile ‣ OpenSolution dialog (notFile ‣ Open!). Navigate to and selectthe fileexample.sln, in thecopy of theexample_nt directoryyou made above. Click Open.
Build the example DLL — In order to check that everything is set upright, try building:
Select a configuration. This step is optional. ChooseBuild ‣ Configuration Manager ‣ Active Solution Configurationand select eitherRelease orDebug. If you skip thisstep, VC++ will use the Debug configuration by default.
Build the DLL. ChooseBuild ‣ Build Solution. Thiscreates all intermediate and result files in a subdirectory called eitherDebug orRelease, depending on which configuration you selectedin the preceding step.
Testing the debug-mode DLL — Once the Debug build has succeeded, bringup a DOS box, and change to theexample_nt\Debug directory. You shouldnow be able to repeat the following session (C> is the DOS prompt,>>>is the Python prompt; note that build information and various debug output fromPython may not match this screen dump exactly):
C>..\..\PCbuild\python_dAdding parser accelerators ...Done.Python 2.2 (#28, Dec 19 2001, 23:26:37) [MSC 32 bit (Intel)] on win32Type "copyright", "credits" or "license" for more information.>>> import example[4897 refs]>>> example.foo()Hello, world[4903 refs]>>>
Congratulations! You’ve successfully built your first Python extension module.
Creating your own project — Choose a name and create a directory forit. Copy your C sources into it. Note that the module source file name doesnot necessarily have to match the module name, but the name of theinitialization function should match the module name — you can only import amodulespam if its initialization function is calledinitspam(),and it should callPy_InitModule() with the string"spam" as itsfirst argument (use the minimalexample.c in this directory as a guide).By convention, it lives in a file calledspam.c orspammodule.c.The output file should be calledspam.pyd (in Release mode) orspam_d.pyd (in Debug mode). The extension.pyd was chosento avoid confusion with a system libraryspam.dll to which your modulecould be a Python interface.
Now your options are:
Copyexample.sln andexample.vcproj, rename them tospam.*, and edit them by hand, or
Create a brand new project; instructions are below.
In either case, copyexample_nt\example.def tospam\spam.def,and edit the newspam.def so its second line contains the string‘initspam‘. If you created a new project yourself, add the filespam.def to the project now. (This is an annoying little file with onlytwo lines. An alternative approach is to forget about the.def file,and add the option/export:initspam somewhere to the Link settings, bymanually editing the setting in Project Properties dialog).
Creating a brand new project — Use theFile ‣ New‣ Project dialog to create a new Project Workspace. SelectVisualC++ Projects/Win32/ Win32 Project, enter the name (spam), and make sure theLocation is set to parent of thespam directory you have created (whichshould be a direct subdirectory of the Python build tree, a sibling ofInclude andPC). Select Win32 as the platform (in my version,this is the only choice). Make sure the Create new workspace radio button isselected. Click OK.
You should now create the filespam.def as instructed in the previoussection. Add the source files to the project, usingProject ‣Add Existing Item. Set the pattern to*.* and select bothspam.candspam.def and click OK. (Inserting them one by one is fine too.)
Now open theProject ‣ spam properties dialog. You only needto change a few settings. Make sureAll Configurations is selectedfrom theSettings for: dropdown list. Select the C/C++ tab. Choosethe General category in the popup menu at the top. Type the following text inthe entry box labeledAdditional Include Directories:
..\Include,..\PC
Then, choose the General category in the Linker tab, and enter
..\PCbuild
in the text box labelledAdditional library Directories.
Now you need to add some mode-specific settings:
SelectRelease in theConfiguration dropdown list.Choose theLink tab, choose theInput category, andappendpythonXY.lib to the list in theAdditional Dependenciesbox.
SelectDebug in theConfiguration dropdown list, andappendpythonXY_d.lib to the list in theAdditional Dependenciesbox. Then click the C/C++ tab, selectCode Generation, and selectMulti-threaded Debug DLL from theRuntime librarydropdown list.
SelectRelease again from theConfiguration dropdownlist. SelectMulti-threaded DLL from theRuntimelibrary dropdown list.
If your module creates a new type, you may have trouble with this line:
PyVarObject_HEAD_INIT(&PyType_Type,0)
Static type object initializers in extension modules may causecompiles to fail with an error message like “initializer not aconstant”. This shows up when building DLL under MSVC. Change it to:
PyVarObject_HEAD_INIT(NULL,0)
and add the following to the module initialization function:
if(PyType_Ready(&MyObject_Type)<0)returnNULL;
Unix and Windows use completely different paradigms for run-time loading ofcode. Before you try to build a module that can be dynamically loaded, be awareof how your system works.
In Unix, a shared object (.so) file contains code to be used by theprogram, and also the names of functions and data that it expects to find in theprogram. When the file is joined to the program, all references to thosefunctions and data in the file’s code are changed to point to the actuallocations in the program where the functions and data are placed in memory.This is basically a link operation.
In Windows, a dynamic-link library (.dll) file has no danglingreferences. Instead, an access to functions or data goes through a lookuptable. So the DLL code does not have to be fixed up at runtime to refer to theprogram’s memory; instead, the code already uses the DLL’s lookup table, and thelookup table is modified at runtime to point to the functions and data.
In Unix, there is only one type of library file (.a) which contains codefrom several object files (.o). During the link step to create a sharedobject file (.so), the linker may find that it doesn’t know where anidentifier is defined. The linker will look for it in the object files in thelibraries; if it finds it, it will include all the code from that object file.
In Windows, there are two types of library, a static library and an importlibrary (both called.lib). A static library is like a Unix.afile; it contains code to be included as necessary. An import library isbasically used only to reassure the linker that a certain identifier is legal,and will be present in the program when the DLL is loaded. So the linker usesthe information from the import library to build the lookup table for usingidentifiers that are not included in the DLL. When an application or a DLL islinked, an import library may be generated, which will need to be used for allfuture DLLs that depend on the symbols in the application or DLL.
Suppose you are building two dynamic-load modules, B and C, which should shareanother block of code A. On Unix, you wouldnot passA.a to thelinker forB.so andC.so; that would cause it to be includedtwice, so that B and C would each have their own copy. In Windows, buildingA.dll will also buildA.lib. Youdo passA.lib to thelinker for B and C.A.lib does not contain code; it just containsinformation which will be used at runtime to access A’s code.
In Windows, using an import library is sort of like usingimportspam; itgives you access to spam’s names, but does not create a separate copy. On Unix,linking with a library is more likefromspamimport*; it does create aseparate copy.
Windows Python is built in Microsoft Visual C++; using other compilers may ormay not work (though Borland seems to). The rest of this section is MSVC++specific.
When creating DLLs in Windows, you must passpythonXY.lib to the linker.To build two DLLs, spam and ni (which uses C functions found in spam), you coulduse these commands:
cl/LD/I/python/includespam.c../libs/pythonXY.libcl/LD/I/python/includeni.cspam.lib../libs/pythonXY.lib
The first command created three files:spam.obj,spam.dll andspam.lib.Spam.dll does not contain any Python functions (suchasPyArg_ParseTuple()), but it does know how to find the Python codethanks topythonXY.lib.
The second command createdni.dll (and.obj and.lib),which knows how to find the necessary functions from spam, and also from thePython executable.
Not every identifier is exported to the lookup table. If you want any othermodules (including Python) to be able to see your identifiers, you have to say_declspec(dllexport), as invoid_declspec(dllexport)initspam(void) orPyObject_declspec(dllexport)*NiGetSpamData(void).
Developer Studio will throw in a lot of import libraries that you do not reallyneed, adding about 100K to your executable. To get rid of them, use the ProjectSettings dialog, Link tab, to specifyignore default libraries. Add thecorrectmsvcrtxx.lib to the list of libraries.
3. Building C and C++ Extensions with distutils
5. Embedding Python in Another Application
Enter search terms or a module, class or function name.