不知道你的结果如何,但我能够在 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 /debug
LINKFLAGS
- 如果 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=libs
Setup(..., 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。