草庐IT

python - 在 Windows 中构建 Python C 扩展时导出符号时出错

coder 2024-06-08 原文

我正在努力将 Python 模块移植到 Windows。我有一个玩具示例如下。

文件夹结构是:

foo/
  libfoo/
    foo.c
  setup.py

setup.py

from setuptools import setup, Extension

sources = ['libfoo/foo.c']

foo = Extension('libfoo',
                 sources = sources,
                 define_macros = None,
                 include_dirs = ['./libfoo'],
                 libraries = None,
                 library_dirs = None,
                 )

setup(name          = 'foo',
      ext_modules      = [foo],
      install_requires = ['setuptools'],
)

libfoo/foo.c(为了完整性)

#include <stdio.h>

void foo() {
  printf("Hello World!");
}

当我尝试安装软件包时遇到错误。

C:\Users\user\foo>python setup.py install
running install
running bdist_egg
running egg_info
creating foo.egg-info
writing requirements to foo.egg-info\requires.txt
writing foo.egg-info\PKG-INFO
writing top-level names to foo.egg-info\top_level.txt
writing dependency_links to foo.egg-info\dependency_links.txt
writing manifest file 'foo.egg-info\SOURCES.txt'
reading manifest file 'foo.egg-info\SOURCES.txt'
writing manifest file 'foo.egg-info\SOURCES.txt'
installing library code to build\bdist.win32\egg
running install_lib
running build_ext
building 'libfoo' extension
creating build
creating build\temp.win32-2.7
creating build\temp.win32-2.7\Release
creating build\temp.win32-2.7\Release\libfoo
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\BIN\cl.exe /c /nologo /Ox
/MD /W3 /GS- /DNDEBUG -I./libfoo -IC:\Python27\include -IC:\Python27\PC /Tclibfo
o/foo.c /Fobuild\temp.win32-2.7\Release\libfoo/foo.obj
foo.c
creating build\lib.win32-2.7
c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\BIN\link.exe /DLL /nologo
/INCREMENTAL:NO /LIBPATH:C:\Python27\libs /LIBPATH:C:\Python27\PCbuild /EXPORT:i
nitlibfoo build\temp.win32-2.7\Release\libfoo/foo.obj /OUT:build\lib.win32-2.7\l
ibfoo.pyd /IMPLIB:build\temp.win32-2.7\Release\libfoo\libfoo.lib /MANIFESTFILE:b
uild\temp.win32-2.7\Release\libfoo\libfoo.pyd.manifest
LINK : error LNK2001: unresolved external symbol initlibfoo
build\temp.win32-2.7\Release\libfoo\libfoo.lib : fatal error LNK1120: 1 unresolv
ed externals
error: command 'c:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\VC\\BIN\\l
ink.exe' failed with exit status 1120

似乎 distutils 包(在本例中为 setuputils)将始终从共享扩展中导出一个符号,即“init + extension_name”[Link] .

它在 Windows 链接器的“EXPORT”选项中指定 [Link]但找不到符号。

帮忙吗?

编辑:C 代码不使用 Python C API,即“#include”。这是因为该项目的目标是采用现有的 C 库并通过 Python 扩展封装在 Python 包装器中。该软件包适用于 Unix/Linux。

最佳答案

经过大量尝试,我终于明白了这个问题。

解决方案:在 Windows 中,您必须为您的扩展定义一个初始化函数,因为 setuptools 将构建一个 .pyd 文件,而不是一个 DLL

要在 Python 2 中解决这个问题,您可以在源代码中定义 initlibfoo() 方法。

#include <Python.h>

PyMODINIT_FUNC initlibfoo(void) {
    // do stuff...
}

要在 Python 3 中解决此问题,您可以在源代码中定义 PyInit_libfoo() 方法。

#include <Python.h>

PyMODINIT_FUNC PyInit_libfoo(void) {
    // do stuff...
}

所以现在,foo.c 看起来像:

#include <stdio.h>
#include <Python.h>

void foo() {
  printf("Hello World!");
}

PyMODINIT_FUNC initlibfoo(void) // Python 2.7
//PyMODINIT_FUNC PyInit_libfoo(void) // Python 3.5
{
    // do stuff...
}

解释

为 Windows 编译 Python 扩展时,Extension类会告诉 linker to export a function供其他程序调用。可以在终端输出中看到:

c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\BIN\link.exe /DLL /nologo
/INCREMENTAL:NO /LIBPATH:C:\Python27\libs /LIBPATH:C:\Python27\PCbuild /EXPORT:i
nitlibfoo build\temp.win32-2.7\Release\libfoo/foo.obj /OUT:build\lib.win32-2.7\l
ibfoo.pyd /IMPLIB:build\temp.win32-2.7\Release\libfoo\libfoo.lib /MANIFESTFILE:b
uild\temp.win32-2.7\Release\libfoo\libfoo.pyd.manifest

(强调/EXPORT:initlibfoo)

现在这是 C/C++ 扩展的必需函数,以便它们可以作为模块导入。换句话说,当您 import libfoo 时,Python 将在 .pyd 上调用函数 initlibfoo 作为模块初始化的一部分。此处遇到的错误是由于链接器被告知导出函数 initlibfoo 但是它无法在 C 目标文件中找到该符号,因为它从未在源代码中定义!

当然,应该可以拒绝导出符号的选项吧?显然不是。回顾扩展类文档,有一个参数 export_symbols。我尝试将 None 传递给它,但仍在使用链接器选项。似乎没有办法绕过这个链接器选项。

不推荐:如果出于某种原因,需要 Python.h 困扰您,那么有一种解决方法。您仍然需要定义上面的“init”方法,但您可以这样做:

void initlibfoo() {} //Python 2.7
void PyInit_libfoo() {} //Python 3.5

但是现在,您不能通过import libfoo 使用该库。您可以使用 ctypes 模块并使用 ctypes.PyDLL('/path/to/pyd') 加载它。本质上,您使用 Python 为您构建了一个 DLL,在这种情况下,它确实构建了一个称为 .pyd 文件的特殊 DLL。然后要使用它,您必须通过 ctypes 模块加载它。

关于python - 在 Windows 中构建 Python C 扩展时导出符号时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34689210/

有关python - 在 Windows 中构建 Python C 扩展时导出符号时出错的更多相关文章

  1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

    我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

  2. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  3. ruby - ECONNRESET (Whois::ConnectionError) - 尝试在 Ruby 中查询 Whois 时出错 - 2

    我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.

  4. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

  5. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  6. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  7. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

    这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

  8. c - mkmf 在编译 C 扩展时忽略子文件夹中的文件 - 2

    我想这样组织C源代码:+/||___+ext||||___+native_extension||||___+lib||||||___(Sourcefilesarekeptinhere-maycontainsub-folders)||||___native_extension.c||___native_extension.h||___extconf.rb||___+lib||||___(Rubysourcecode)||___Rakefile我无法使此设置与mkmf一起正常工作。native_extension/lib中的文件(包含在native_extension.c中)将被完全忽略。

  9. Python 相当于 Perl/Ruby ||= - 2

    这个问题在这里已经有了答案:关闭10年前。PossibleDuplicate:Pythonconditionalassignmentoperator对于这样一个简单的问题表示歉意,但是谷歌搜索||=并不是很有帮助;)Python中是否有与Ruby和Perl中的||=语句等效的语句?例如:foo="hey"foo||="what"#assignfooifit'sundefined#fooisstill"hey"bar||="yeah"#baris"yeah"另外,类似这样的东西的通用术语是什么?条件分配是我的第一个猜测,但Wikipediapage跟我想的不太一样。

  10. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

随机推荐