Skip to content Skip to sidebar Skip to footer

Using Elmer To Generate C Code And Then Create Dll

I wanted to see if anyone has tried something like this and to get some advice whether or not to pursue this idea. I have a Python script which I would like to create a dll from.

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 = [] and extraLinkArgs = [] below the libDirs = [] declaration
    • In the Windows-specific build options if block add: extraCompileArgs = ['/MT'] and extraLinkArgs = ['/MANIFEST']
    • Add , extra_compile_args=extraCompileArgs, extra_link_args=extraLinkArgs after libraries=libs inside Setup(..., 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 containing retCode += "extern int Py_FrozenFlag;\n" and retCode += "DL_IMPORT(struct _frozen *) PyImport_FrozenModules;\n" (around line 145)
      • Add the line: retCode += " PyImport_FrozenModules = _PyImport_FrozenModules;\n" above the line containing retCode += " retRunVal = PyImport_ImportFrozenModule( (char*)\"%s\" );\n" (around line 189)
  • 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"