Using Elmer To Generate C Code And Then Create Dll
Solution 1:
So I contact the individuals behind ELmer and they were nice enough to create an example as to how to create a DLL from the code generate from Elmer. The example can be found in the following link: http://elmer.sourceforge.net/examples.html#WINDOWSDLL
Solution 2:
Not sure how things worked out for you, but I was able to create a DLL using Elmer with Python 2.7.8 and Elmer 1.1.7a on Windows 7 x64 and figured I'd share my experience.
My compilation/build environment was VisualStudio2005 using NMAKE
I did run into several issues along the way, especially related to the -frozen flag and my older version of visual studio, but I am getting what appears to be a working DLL now.
My top level notes:
- I had to statically link elmer with MSVCRT80 due to a conflict during dll loading with the MSVCRT90 included by python27.dll.
- The library, elmer.lib, was needed for the linking step, but existed only in the c:\elmer\src\build\temp.win32-2.7\Release\elmer directory, it seems like it should get copied someplace without the word temp in the name, but I set my makefile to use it from the temp directory.
- When using -frozen, there can be dozens of generated .c files
- PyImport_FrozenModules and Py_FrozenFlag are already declared by other include files (pydebug).
- PyImport_FrozenModules is getting redefined (due to elPythonToC), rather than just assigned.
- DL_IMPORT (used within elPythonToC.py) is deprecated per http://bugs.python.org/issue566100. should use PyApi_DATA instead I think, but makes no real difference.EDIT Not that important as I deleted that entire block as it was redefining PyImport_FrozenModules
- In the end, I had to include python27.dll, elmer.dll. I believe MSVCRT90.dll also needs to be installed via the MS redistributable installer on the target machine as python27.dll needs that. It would be nice if using frozen would get us a single distributable, but I'll take what I can get.
- I was able to run the procedure on python 2.6.5 with slight modifications (e.g. python path is c:\python26 instead of c:\python27).
- Test your script in python first, elmer will happily package a script containing malformed python.
- To create a debugable dll, add
/Z7 /Od
to the CFLAGS and/incremental:no /debug
to the LINKFLAGS - Would be nice if some sort of formatted comment or function in the python code itself could replace the .elm file.
Now here are the detailed steps of I did (no warranties that any of these are correct and they were certainly not optimal, but they did seem to work for me):
- Install Elmer
- Download and unzip elmer to some directory (I picked C:\elmer, so I'll use that throughout my example)
- When I started, I was using 2.7.2 and I ran into this issue: Compiling with cython and mingw produces gcc: error: unrecognized command line option '-mno-cygwin'. I patched Lib/distutils/cygwinccompiler.py to remove -mno-cygwin and got it to install, but I later installed 2.7.8, which I think fixes the underlying issue.
- I wanted the Elmer.dll to statically link to the MSVCRT junk as I have an older version of MSVCRT, so I modified setup.py as follows. (I know I shouldn't statically link and you probably don't want that, but in case you do:
- Add
extraCompileArgs = []
andextraLinkArgs = []
below thelibDirs = []
declaration - In the Windows-specific build options if block add:
extraCompileArgs = ['/MT']
andextraLinkArgs = ['/MANIFEST']
- Add
, extra_compile_args=extraCompileArgs, extra_link_args=extraLinkArgs
afterlibraries=libs
insideSetup(..., ext_modules=[Extension(
- from command prompt, run C:\elmer\src>python setup.py build
- from command prompt, run C:\elmer\src>python setup.py install
- Modify .py and .elm files to suit my needs - that was the easy part
- Obtain makefrozen.py makefrozen is used by elmer when using the -frozen option, but it does not appear to be included in the standard win32 MSI distribution.
- makefrozen is included in the source code for python, but is not included in the windows MSI installer, so download the source tarball from www.python.org
- extract \Tools\freeze\ to c:\python27\Tools\freeze
- Modify buildAndRun
- Change ELMERDIR to C:\
- Path should point to
SET PATH=%PATH%;%ELMERDIR%;%THISDIR%
- Set ELMERDIR to C:\elmer\
Update Make files to work for my configuration (the example files didn't work at all with nmake or frozen). Here is my MAKEFILE that can build the frozen or non-frozen version using nmake:
PYTHONDIR=C:\Python27 ELMERDIR=C:\elmer ELMERLIBDIR=$(ELMERDIR)\src\build\temp.win32-2.7\Release\elmer ELMER_OUTPUT_DIR=Generated CC=cl RM=del /F /Q ELMER=$(ELMERDIR)\elmer shell=call CFLAGS=/TC /LD INCLUDEFLAGS=/I$(ELMER_OUTPUT_DIR) /I$(PYTHONDIR)\include /I$(PYTHONDIR)\Lib\site-packages\elmer LINKFLAGS=/LIBPATH:$(PYTHONDIR)\libs python27.lib /LIBPATH:$(ELMERLIBDIR) elmer.lib .PHONY: generatedFiles generatedFrozen all allFrozen SRCS = Generated\*.c OBS = $(SRCS:.c=.obj) {Generated}.c{Generated}.obj:: @echo Compiling... @$(CC) /nologo $(CFLAGS) $(INCLUDEFLAGS) /c /FoGenerated\ $<generatedFrozen: echo Elmering @$(shell) $(ELMER) -c -frozen -o $(ELMER_OUTPUT_DIR) -int MyDll.elm MyDll.py generatedFiles: echo Elmering @$(shell) $(ELMER) -c -o $(ELMER_OUTPUT_DIR) -int MyDll.elm MyDll.py showIncludeAndLinkFlags:@echoincludeDirs: @$(shell) $(ELMER) --printIncludeFlags @echolinkDirs: @$(shell) $(ELMER) --printLinkFlags MyDll.dll:$(OBS) @echo Linking... @Link$(LINKFLAGS) /DLL $(OBS) all:@echo"Making All"@nmake generatedFiles @nmake showIncludeAndLinkFlags @nmake MyDll.dll allFrozen:@echo"Making All"@nmake generatedFrozen @nmake showIncludeAndLinkFlags @nmake MyDll.dll clean:@echo cleaning $(RM) .\Generated\*.* 2>nul || echo eatFailure >nul
Create a Build.bat to setup the Visual Studio environment before calling nmake. Here are the contents of my build batch file:
@ECHO OFF SETLOCAL SET THISDIR=%~dp0 REM Setup Visual Studio build environment REM Microsoft Visual Studio 8 == Visual Studio 2005CALL"C:\Program Files (x86)\Microsoft Visual Studio 8\VC\vcvarsall.bat" nmake clean nmake allFrozen pause ENDLOCAL
- Fix compilation/link errors, it got a bit ugly here as I had to modify elmer code to get it to work
- Remove duplicate declarations and redefinition for Py_FrozenFlag and PyImport_FrozenModules
- Open C:\python27\Lib\site-packages\elmer\elPythonToC.py in a text or python editor
- Delete or comment out the
if( frozenFlag ) :
block containingretCode += "extern int Py_FrozenFlag;\n"
andretCode += "DL_IMPORT(struct _frozen *) PyImport_FrozenModules;\n"
(around line 145) - Add the line:
retCode += " PyImport_FrozenModules = _PyImport_FrozenModules;\n"
above the line containingretCode += " retRunVal = PyImport_ImportFrozenModule( (char*)\"%s\" );\n"
(around line 189)
- Remove duplicate declarations and redefinition for Py_FrozenFlag and PyImport_FrozenModules
- Copy DLLs to a distribution folder
- Copy MyDLL.dll from the working directory containing your .elm file. Copy elmer.dll from C:\elmer\src\build\lib.win32-2.6\elmer. Copy python27.dll from C:\Windows\SysWOW64.
- Install Visual C++ Redistributable Package if necessary on target machine (or maybe just find MSVCRT90.dll in your windows side-by-side configurations and stuff that next to your DLL. see http://msdn.microsoft.com/en-us/library/vstudio/ms235299.aspx.
EDIT When I added some meat to my dll, I noticed the frozen import stuff wasn't working properly and was causing my DLL to exit. My original modifications were causing Py_FrozenFlag and PyImport_FrozenModules to be defined locally, which caused PyImport_ImportFrozenModule to fail within the generated c code. I've made modifications to the makefile to eliminate the Py_NO_ENABLE_SHARED define, removed the definitions and declarations of those vars, changed the definition of PyImport_FrozenModules to an assignment and everything seems to be working properly now. I've successfully connected to and debugged my dll from a simple c++ app.
Post a Comment for "Using Elmer To Generate C Code And Then Create Dll"