1

我想看看是否有人尝试过这样的事情,并就是否追求这个想法获得一些建议。我有一个 Python 脚本,我想从中创建一个 dll。在做了一些研究之后,执行此任务的最佳方法是将 python 脚本嵌入到 C 中,然后从 C 代码生成一个 dll。

然后我找到了 Elmer Software Glue: http ://elmer.sourceforge.net/index.html ,它将 Python 模块嵌入到 C 中。我想我可以使用 Elmer 将我的 python 代码嵌入到 C 中,然后从那里创建一个 dll。

我任何人都会给我一些保证,这可能会奏效,如果不是的话,也许还有其他选择。我对任何和所有建议持开放态度。

4

2 回答 2

3

因此,我联系了 ELmer 背后的个人,他们非常友好地创建了一个示例,说明如何从 Elmer 生成的代码创建 DLL。该示例可以在以下链接中找到: http: //elmer.sourceforge.net/examples.html#WINDOWSDLL

于 2013-01-10T13:52:56.127 回答
2

不知道你的结果如何,但我能够在 Windows 7 x64 上使用 Elmer 和 Python 2.7.8 和 Elmer 1.1.7a 创建一个 DLL,并想我会分享我的经验。

我的编译/构建环境是使用 NMAKE 的 VisualStudio2005

在此过程中我确实遇到了几个问题,尤其是与 -frozen 标志和我的旧版 Visual Studio 相关,但我现在得到的似乎是一个工作 DLL。

我的顶级笔记:

  • 由于在加载 dll 期间与 python27.dll 包含的 MSVCRT90 发生冲突,我不得不将 elmer 与 MSVCRT80 静态链接。
  • 链接步骤需要库 elmer.lib,但仅存在于 c:\elmer\src\build\temp.win32-2.7\Release\elmer 目录中,似乎应该在没有单词的情况下将其复制到某个地方名称中的 temp ,但我将我的 makefile 设置为从 temp 目录使用它。
  • 使用-frozen时,可以生成几十个.c文件
  • PyImport_FrozenModules 和 Py_FrozenFlag 已由其他包含文件 (pydebug) 声明。
  • PyImport_FrozenModules 正在重新定义(由于 elPythonToC),而不仅仅是分配。
  • 根据http://bugs.python.org/issue566100不推荐使用 DL_IMPORT(在 elPythonToC.py 中使用)。我认为应该使用 PyApi_DATA 代替,但没有真正的区别。编辑没那么重要,因为我删除了整个块,因为它正在重新定义 PyImport_FrozenModules
  • 最后,我不得不包含 python27.dll、elmer.dll。我相信 MSVCRT90.dll 也需要通过目标机器上的 MS 可再发行安装程序安装,因为 python27.dll 需要它。如果使用 freeze 可以让我们获得一个可分发的内容,那就太好了,但我会尽我所能。
  • 我能够在 python 2.6.5 上运行该过程并稍作修改(例如,python 路径是 c:\python26 而不是 c:\python27)。
  • 首先在 python 中测试你的脚本,elmer 会很高兴地打包一个包含畸形 python 的脚本。
  • 要创建可调试的 dll,请添加/Z7 /Od到 CFLAGS 和/incremental:no /debugLINKFLAGS
  • 如果 python 代码本身中的某种格式化注释或函数可以替换 .elm 文件,那就太好了。

现在这里是我所做的详细步骤(不保证其中任何一个都是正确的,它们当然不是最佳的,但它们似乎对我有用):

  • 安装埃尔默
    • 下载 elmer 并将其解压缩到某个目录(我选择了 C:\elmer,所以我将在整个示例中使用它)
    • 当我开始使用 2.7.2 时,我遇到了这个问题:Compiling with cython and mingw generated gcc: error: unrecognized command line option '-mno-cygwin'。我修补了 Lib/distutils/cygwinccompiler.py 以删除 -mno-cygwin 并安装它,但后来我安装了 2.7.8,我认为它解决了根本问题。
    • 我希望 Elmer.dll 静态链接到 MSVCRT 垃圾,因为我有旧版本的 MSVCRT,所以我修改了 setup.py 如下。(我知道我不应该静态链接,你可能不希望这样,但万一你这样做:
    • 在声明下方添加extraCompileArgs = []extraLinkArgs = []libDirs = []
    • 在 Windows 特定的构建选项中 if block add:extraCompileArgs = ['/MT']extraLinkArgs = ['/MANIFEST']
    • 在里面, extra_compile_args=extraCompileArgs, extra_link_args=extraLinkArgs之后添加libraries=libsSetup(..., ext_modules=[Extension(
    • 从命令提示符运行 C:\elmer\src>python setup.py build
    • 从命令提示符运行 C:\elmer\src>python setup.py install
  • 修改 .py 和 .elm 文件以满足我的需要 - 这是最简单的部分
  • 获取 makefrozen.py elmer 在使用 -frozen 选项时使用 makefrozen,但它似乎不包含在标准 win32 MSI 分发中。
    • makefrozen 包含在 python 的源代码中,但不包含在 windows MSI 安装程序中,因此请从 www.python.org 下载源 tarball
    • 解压 \Tools\freeze\ 到 c:\python27\Tools\freeze
  • 修改 buildAndRun
    • 将 ELMERDIR 更改为 C:\
    • 路径应该指向SET PATH=%PATH%;%ELMERDIR%;%THISDIR%
    • 将 ELMERDIR 设置为 C:\elmer\
  • 更新 Make 文件以适用于我的配置(示例文件根本不适用于 nmake 或 freeze)。这是我的 MAKEFILE,可以使用 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:
            @echo includeDirs: 
            @$(shell) $(ELMER) --printIncludeFlags
            @echo linkDirs: 
            @$(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
    
  • 在调用 nmake 之前创建一个 Build.bat 以设置 Visual Studio 环境。这是我的构建批处理文件的内容:

        @ECHO OFF
        SETLOCAL
        SET THISDIR=%~dp0
        REM Setup Visual Studio build environment
        REM  Microsoft Visual Studio 8 == Visual Studio 2005
        CALL "C:\Program Files (x86)\Microsoft Visual Studio 8\VC\vcvarsall.bat"
        nmake clean
        nmake allFrozen
        pause
        ENDLOCAL
    
  • 修复编译/链接错误,这里有点难看,因为我必须修改 elmer 代码才能让它工作
    • 删除 Py_FrozenFlag 和 PyImport_FrozenModules 的重复声明和重新定义
      • 在文本或 python 编辑器中打开 C:\python27\Lib\site-packages\elmer\elPythonToC.py
      • 删除或注释掉if( frozenFlag ) :包含retCode += "extern int Py_FrozenFlag;\n"and的块retCode += "DL_IMPORT(struct _frozen *) PyImport_FrozenModules;\n"(大约第 145 行)
      • 添加行:retCode += " PyImport_FrozenModules = _PyImport_FrozenModules;\n"在包含的行上方retCode += " retRunVal = PyImport_ImportFrozenModule( (char*)\"%s\" );\n"(大约第 189 行)
  • 将 DLL 复制到分发文件夹
    • 从包含 .elm 文件的工作目录中复制 MyDLL.dll。从 C:\elmer\src\build\lib.win32-2.6\elmer 复制 elmer.dll。从 C:\Windows\SysWOW64 复制 python27.dll。
    • 如有必要,在目标计算机上安装 Visual C++ Redistributable Package(或者可能只是在 Windows 并排配置中找到 MSVCRT90.dll 以及 DLL 旁边的内容。请参阅http://msdn.microsoft.com/en-us/库/vstudio/ms235299.aspx

编辑 当我在我的 dll 中添加一些肉时,我注意到冻结的导入内容无法正常工作并导致我的 DLL 退出。我最初的修改导致 Py_FrozenFlag 和 PyImport_FrozenModules 在本地定义,这导致 PyImport_ImportFrozenModule 在生成的 c 代码中失败。我对 makefile 进行了修改以消除 Py_NO_ENABLE_SHARED 定义,删除了这些变量的定义和声明,将 PyImport_FrozenModules 的定义更改为赋值,现在一切似乎都正常工作。我已经从一个简单的 c++ 应用程序成功连接并调试了我的 dll。

于 2014-07-17T19:22:55.263 回答