【问题标题】:Building a python module and linking it against a MacOSX framework构建 python 模块并将其与 MacOSX 框架链接
【发布时间】:2011-02-04 18:57:22
【问题描述】:

我正在尝试在 MacOSX 10.6 上构建 Python 扩展并将其链接到多个框架(仅限 i386)。我使用 distutils 和 Extension 对象制作了一个 setup.py 文件。

我要链接到我的框架,我的 LDFLAGS 环境变量应该如下所示:

LDFLAGS = -lc -arch i386 -framework fwk1 -framework fwk2

由于我在扩展模块文档中没有找到任何“框架”关键字,因此我使用了 extra_link_args 关键字。

Extension('test',
define_macros = [('MAJOR_VERSION', '1'), ,('MINOR_VERSION', '0')],
include_dirs = ['/usr/local/include', 'include/', 'include/vitale'],
extra_link_args = ['-arch i386',
                   '-framework fwk1',
                   '-framework fwk2'],
sources = "testmodule.cpp",
language = 'c++' )

一切都在编译和链接。如果我从 extra_link_args 中删除 -framework 行,我的链接器会按预期失败。这是 python setup.py build 生成的最后两行:

/usr/bin/g++-4.2 -arch x86_64 -arch i386 -isysroot /
-L/opt/local/lib -arch x86_64 -arch i386 -bundle
-undefined dynamic_lookup build/temp.macosx-10.6-intel-2.6/testmodule.o
-o build/lib.macosx-10.6-intel-2.6/test.so
-arch i386 -framework fwk1 -framework fwk2

很遗憾,我刚刚生成的 .so 无法找到该框架提供的几个符号。我试图用 otool 检查链接的框架。它们都没有出现。

$ otool -L test.so
test.so:
    /usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.9.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.0.1)

在测试二进制文件上运行 otool 的输出,由 g++ 和 ldd 使用我的帖子顶部描述的 LDFLAGS 制作。在这个例子中,-framework 确实有效。

$ otool -L vitaosx 
vitaosx:
    /Library/Frameworks/fwk1.framework/Versions/A/fwk1 (compatibility version 1.0.0, current version 1.0.0)
    /Library/Frameworks/fwk2.framework/Versions/A/fwk2 (compatibility version 1.0.0, current version 1.0.0)
    /usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.9.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.0.1)

这个问题可以链接到链接步骤中的“-undefined dynamic_lookup”标志吗?我对在 Google 上找到的几行文档感到有些困惑。

干杯,

【问题讨论】:

    标签: c++ python macos dynamic-linking


    【解决方案1】:

    这与未定义的 dynamic_lookup 无关,而与 distutils 无关。它将 extra_link_flags 附加到它为 python 构建选择的链接标志上。相反,它应该预先添加它,因为 -framework 列表必须出现在 cmdline 上使用它们的对象之前(AFAIK 这是由于 gcc 如何收集符号以进行链接)。我个人使用的快速修复方法是使用

        LDFLAGS="-framework Carbon" python setup.py build_ext --inplace
    

    或您需要的任何框架。 LDFLAGS 被添加到 distutils 自己的标志之前。请注意,您的包裹不会是pip installable。正确的修复只能来自 distutils - 恕我直言,他们应该支持 frameworks,就像他们支持 libraries 一样。

    或者,您也可以添加

    import os
    os.environ['LDFLAGS'] = '-framework Carbon'
    

    在你的 setup.py 中。然后你的包应该是pip installable。

    【讨论】:

      【解决方案2】:

      虽然尘埃落定很久之后,我自己也有同样的问题,我挖了一点,发现了这个:

      /System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/distutils/sysconfig.py

         if 'ARCHFLAGS' in os.environ:
                      archflags = os.environ['ARCHFLAGS']
                  else:
                      archflags = '-arch i386 -arch ppc -arch x86_64'
                  _config_vars['ARCHFLAGS'] = archflags
                  if archflags.strip() != '':
                      _config_vars['CFLAGS'] = _config_vars['CFLAGS'] + ' ' + archflags
                      _config_vars['LDFLAGS'] = _config_vars['LDFLAGS'] + ' ' + archflags
      

      我从不同的角度来解决这个问题 - 在 10.6 上,distutils 正在尝试构建 C 扩展,并抱怨因为 10.6 SDK 中没有 PPC 部分。

      然而,

       export ARCHFLAGS="-arch i386 -arch x86_64"
       python setup.py build
      

      工作就像一个魅力。

      【讨论】:

      • 我相信 PPC 问题只有在您获得最新的 XCode 时才会出现。即,您可以支付的费用。 10.6 OS盘自带的应该没问题。
      • 我还没有尝试过@synthesizerpatel 的答案,但是我遇到了以前的 XCode 的 ppc 问题。来自 MacOS X DVD 的免费版本。
      【解决方案3】:

      我不确定我是否了解您想要做什么以及您想要的结果,但也许这会有所帮助。由于 C 扩展模块通常在 Python 解释器的执行上下文中运行,因此必须构建扩展模块以与解释器兼容。在 OS X 上,Python 和 distutils 会遇到一些麻烦,以确保使用与 Python 解释器本身最初构建时相同的 SDK (-sysroot)、MACOSX_DEPLOYMENT_TARGET-arch 值构建 C 扩展模块。因此,如果您在 10.6 上使用 Apple 提供的 Python,distutils 将提供 -arch i386 -arch ppc -arch x86_64,这是构建它的三个拱门。如果您使用当前的 python.org OS X 安装程序(在 10.6、10.5 或 10.4 上),它将使用:

      gcc-4.0 -arch ppc -arch i386 -isysroot /Developer/SDKs/MacOSX10.4u.sdk
      

      根据您提供的 sn-ps,我猜您正在使用安装了 MacPorts 的通用 Python,默认情况下,它使用 -arch x86_64 -arch i386 -isysroot / 构建扩展模块。

      一般来说,要使一切正常工作,您需要确保:

      1. 至少有一个arch 在 在解释器中通用,所有 C 扩展模块,以及所有外部 框架和/或共享库 他们链接到

      2. 解释器在该(或其中一种)通用架构中执行。

      在 OS X 10.6 上,最后一步并不像应有的那么简单,具体取决于您使用的 Python。例如,Apple 提供的 Python 2.6 进行了修改以强制 32 位执行(有关详细信息,请参阅 Apple 的 man python):

      export VERSIONER_PYTHON_PREFER_32_BIT=yes
      

      如果您构建自己的 32 位/64 位通用 Python,2.6.5 中有一些修复程序允许在运行时进行选择。不幸的是,MacPorts 构建 Python 的方式绕过了这些修复,因此似乎没有任何简单的方法可以强制 MacPorts python2.6 32/64 位通用构建在 10.6 上以 32 位模式运行。出于复杂的原因,即使您使用 /usr/bin/arch -i386,它也总是更喜欢 64 位(如果可用)。

      因此,根据您要执行的操作,您可以通过以下任一方式解决该问题(如果我理解正确的话):

      1. 重建您的框架以包含-arch x86_64
      2. 在 32 位模式下使用 Apple 提供的 Python (/usr/bin/python) 或 python.org 2.6.5
      3. 在 32 位模式下重新安装 MacPorts python(未经测试!):

        sudo port selfupdate
        sudo port clean python26
        sudo port install python26 +universal universal_archs=i386
        

      【讨论】:

      • 非常感谢您的回答。如果在框架中找不到至少一个拱门,链接器似乎不会引用生成的 .so 文件中的框架。就我而言,我的框架包括 ppc 和 i386 变体。如果我在链接步骤中手动强制 -arch 标志到“i386”,那么 MacOSX 中包含的基本 python 发行版一切正常。如果我在生成的 .so 文件上运行 otool,我可能会找到我的框架。但是如果我使用系统默认的 -arch i386 -arch ppc -arch x86_64,.so 文件不会链接到我的任何框架。
      • 不幸的是,选项 1 不可用,因为框架是按原样提供的,没有任何来源。从我的提供商那里获得更新版本似乎是不可能的。选项 2 正在工作。谢谢,我差点忘了我有一个与 macosx 捆绑在一起的 python 二进制文件……选项 3 很奇怪,不起作用。正如预期的那样,在 buildutils 的链接步骤中出现的唯一拱门是 i386,但 .so 未链接到任何框架。我会努力解决这个问题。
      【解决方案4】:

      看来我的框架是为 ppc 和 i386 而不是 x86_64 编译的:

      $ file /Library/Frameworks/fwk1.framework/Versions/A/fwk1 
      /Library/Frameworks/fwk1.framework/Versions/A/fwk1: Mach-O universal binary with 2 architectures
      /Library/Frameworks/fwk1.framework/Versions/A/fwk1 (for architecture ppc):  Mach-O dynamically linked shared library ppc
      /Library/Frameworks/fwk1.framework/Versions/A/fwk1 (for architecture i386): Mach-O dynamically linked shared library i386
      

      我从链接行中删除了 -arch x86_64 标志。我的库与我的框架相关联:

      $ otool -L  test.so
      test.so:
          /Library/Frameworks/fwk1.framework/Versions/A/fwk1 (compatibility version 1.0.0, current version 1.0.0)
          /Library/Frameworks/fwk2.framework/Versions/A/fwk2 (compatibility version 1.0.0, current version 1.0.0)
          /usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.9.0)
          /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.0.1)
      

      如果有人知道如何强制在编译时使用 -arch 并与 Python 的 distutils 链接...请分享您的建议。

      【讨论】:

        【解决方案5】:

        我自己也遇到了这个问题。我不得不绕过 distutils,因为它们似乎对 -undefined dynamic_lookup 进行了硬编码。这是我用来模拟 distutils 的 Makefile:

        CC = gcc
        CFLAGS = -pipe -std=c99 -fno-strict-aliasing -fno-common -dynamic -fwrapv -mno-fused-madd -DENABLE_DTRACE -DMACOSX -DNDEBUG -Werror -pedantic -Wall -Wstrict-prototypes -Wshorten-64-to-32 -g -Os -arch i386 -arch x86_64 -I/System/Library/Frameworks/Python.framework/Versions/2.7/include/python2.7
        LD = gcc
        LDFLAGS = -Wl,-F. -bundle -Wl,-F. -arch i386 -arch x86_64 -framework CoreFoundation -framework CoreMIDI -framework Python
        
        project = <extension_name>
        library = $(project).so
        modules = <module_names>
        sources = $(foreach module,$(modules),$(module).c)
        objects = $(sources:.c=.o)
        
        all: $(library)
        
        $(library): $(objects)
            $(LD) $(LDFLAGS) $(objects) -o $@
        
        %.o: %.c Makefile
            $(CC) $(CFLAGS) $< -c -o $@
        
        install: $(library)
            cp $(library) /Library/Python/2.7/site-packages
        
        clean:
                rm -f $(library) $(objects) *~
        

        我确信有一种方法可以让 distutils 停止发出 -undefined 参数,但上述方法在 10.7 上对我有用

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-03-12
          • 2012-01-13
          • 2016-03-10
          • 2021-03-20
          • 2013-10-06
          • 2011-05-07
          相关资源
          最近更新 更多