使用MinGW链接Python

9 投票
3 回答
15520 浏览
提问于 2025-04-16 21:45

我想创建一个可以在不同平台上运行的程序,这个程序需要嵌入Python解释器,并且我打算用MinGW来编译它。但是,Python的二进制发行版没有提供可以和MinGW链接的库(只有python32.lib是给Visual C++用的),而Python的源代码包也不支持用MinGW编译。

我尝试在MinGW中链接python32.lib,用的是-lpython32这个选项,但还是出现了一些错误,比如:

main.cpp: undefined reference to `_imp__Py_Initialize'
main.cpp: undefined reference to `_imp__Py_Finalize'

我该如何在MinGW中链接Python呢?我真的不想换成使用Visual C++。

3 个回答

0

EmbeddingPython.c

#include <Python.h>

int main(int argc, char *argv[])
{
    Py_SetProgramName((wchar_t *)argv[0]);  /* optional but recommended */
    Py_Initialize();
    PyRun_SimpleString("from time import time,ctime\n"
        "print('Today is', ctime(time()))\n");
    Py_Finalize();
    return 0;
}

然后用gcc来编译,方法如下:

gcc EmbeddingPython.c -I C:\Python34\include -LC:/Python34/libs -lpython34 -o a.exe

这样就能按照我们的预期正常运行了。

D:\>a.exe
Today is Fri Aug 29 15:14:04 2014
7

试试这个...

  1. 下载适合你版本的 mingw 的 gendef(32位或 64位),然后在 msys shell 中...
  2. 运行 gendef /c/windows/system32/python32.dll
  3. 运行 dlltool -D python32.dll -d python32.def -l libpython32.a
  4. libpython32.a 复制到你的 ./python32/libs 目录下。

如果你的 libpython32.a 文件是 0 字节,那就出问题了。请仔细检查你下载的 gendef 版本是否和你的 mingw/msys 版本匹配。如果你在使用 64 位版本,可能需要下载 gendef 的二进制文件并自己编译,不过这其实也很简单。

希望这能帮到你。

8

使用binutils里的nm和dlltool,你应该能够为gcc重新构建这个库:

echo EXPORTS > python32.def
nm python32.lib | grep " T _" | sed "s/.* T _//" >> python32.def
dlltool --input-def python32.def --dllname python32 --output-lib libpython32.a

这是一个名为python_test.c的文件:

#include "Python.h"

int main(int argc, char *argv[]) {
    Py_Initialize();
    PyRun_SimpleString("from time import time,ctime\n"
                       "print('Today is',ctime(time())\n)");
    Py_Finalize();
    return 0;
}

编译命令:

gcc -Wall -IC:\Python32\include -LC:\Python32\libs -o python_test.exe python_test.c -lpython32

测试命令:

C:\python_test.exe
Today is Mon Jul 18 08:50:53 2011

补充说明: 如果你不想自己在x64上构建这个库,可以从Christoph Gohlke的Python扩展包的非官方Windows二进制文件下载多个版本。

补充说明: 这里有一个基于现有功能的Python版本,这个功能分布在Tools/msi/msi.py里:

import subprocess
import warnings
import re

NM = 'x86_64-w64-mingw32-nm'
DLLTOOL = 'x86_64-w64-mingw32-dlltool'
EXPORT_PATTERN = r'^[_]{1,2}imp_(?P<export>.*) in python\d+\.dll'

def build_libpython(ver, nm=NM, dlltool=DLLTOOL,
                    export_pattern=EXPORT_PATTERN):
    pylib = 'python%s.lib' % ver
    pydef = 'python%s.def' % ver
    pydll = 'python%s.dll' % ver
    libpy = 'libpython%s.a' % ver
    warning = '%s failed - ' + '%s not built' % libpy
    match_export = re.compile(export_pattern).match
    cmd_nm = [nm, '-Cs', pylib]
    cmd_dlltool = [dlltool, 
                   '--dllname', pydll, 
                   '--def', pydef,
                   '--output-lib', libpy]
    with open(pydef, 'w') as f:
        f.write('LIBRARY %s\nEXPORTS\n' % pydll)
        p_nm = subprocess.Popen(cmd_nm, 
                                stdout=subprocess.PIPE,
                                universal_newlines=True)
        for line in sorted(p_nm.stdout):
            m = match_export(line)
            if m:
                f.write(m.group('export') + '\n')
        if p_nm.wait() != 0:
            warnings.warn(warning % nm)
            return False
    if subprocess.call(cmd_dlltool) != 0:
        warnings.warn(warning % dlltool)
        return False
    return True

举个例子:

import os
for n in (27, 33, 35):
    pylib = 'python%s.lib' % n
    if os.path.exists(pylib):
        build_libpython(n)
        pydef = 'python%s.def' % n            
        lc_def = sum(1 for line in open(pydef))
        libpy = 'libpython%s.a' % n
        lc_lib = sum(1 for line in os.popen('ar -t %s' % libpy))
        assert lc_def == lc_lib

撰写回答