2010-04-06 72 views
13

我試圖在MacOSX 10.6上構建一個Python擴展並將其與幾個框架(僅i386)鏈接起來。我使用distutils和Extension對象創建了一個setup.py文件。構建一個python模塊並將其鏈接到MacOSX框架

我爲了反對我的框架,我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構建產生的最後兩行:

/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運行的輸出上的測試二進制,克++製成並使用在我的柱的頂部描述的LDFLAGS ldd的。在這個例子中,框架工作確實有效。

$ 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上發現的幾行文檔讓我有點困惑。

乾杯,

回答

6

這與undefined dynamic_lookup無關,但都與distutils有關。它將extra_link_flags附加到它爲python構建選擇的鏈接標誌。相反,它應該預先考慮它,因爲-framework列表必須位於在cmdline上使用它們的對象之前(AFAIK這是由於gcc如何收集鏈接符號)。我個人使用的快速修復方法是使用

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

或任何您需要的框架。將LDFLAGS預先設置爲使自己的標誌失效。請注意,您的包裝不會是pip install。一個適當的修復只能來自distutils - 恕我直言,他們應該支持frameworks像他們支持libraries

或者,你也可以在你的setup.py添加

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

。你的包裹應該是pip install

1

看來,我的框架編譯爲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使用......請分享您的建議。

3

我不確定我是否理解你正在嘗試做什麼以及期望的結果,但也許這會有所幫助。由於C擴展模塊通常在Python解釋器的執行上下文中運行,擴展模塊必須構建爲與解釋器兼容。在OS X上,Python和distutils遇到了一些麻煩,以確保C擴展模塊使用相同的SDK(-sysroot),MACOSX_DEPLOYMENT_TARGET值和-arch值作爲Python解釋器本身最初構建時的值。因此,如果您在10.6上使用Apple提供的Python,distutils將提供-arch i386 -arch ppc -arch x86_64,這是與它一起構建的三個arch。如果使用當前python.org OS X安裝程序(在10.6,10.5,10.4),它會使用:

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

從您提供的片段,我猜你正在使用的MacPorts安裝通用Python,默認情況下,它使用-arch x86_64 -arch i386 -isysroot /構建,並用於構建擴展模塊。

一般而言,使一切工作,你需要確保:

  1. 至少有一個arch共同 解釋中,所有的C 擴展模塊,和所有外部 框架和/或共享它們鏈接到的庫

  2. 解釋器正在那個(或其中一個)通用體系結構中執行。

在OS X 10.6上,最後一步並不像取決於您使用的Python那樣容易。例如,蘋果提供的Python 2.6中有一個修改,迫使32位執行(見蘋果的man python瞭解詳細信息):

export VERSIONER_PYTHON_PREFER_32_BIT=yes 

如果你建立你自己的32位/ 64位通用Python中,有修復在2.6.5中允許在運行時進行選擇。不幸的是,MacPorts構建Python的方式繞過了這些修復,所以似乎沒有任何簡單的方法來強制10.6的MacPorts python2.6 32位/ 64位通用構建以32位模式運行。出於複雜的原因,即使您使用/usr/bin/arch -i386,它也會始終偏好64位(如果可用)。

所以,這取決於你正在嘗試做的,你可能能夠解決該問題(如果我理解正確的話)有兩種方法:

  1. 重建框架,包括-arch x86_64
  2. 使用的Apple提供的Python(/usr/bin/python)在32位模式或python.org 2.6.5
  3. 重新安裝在32位只有模式的MacPorts蟒(未經測試!):

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

非常感謝您的回答。 如果在框架中找不到至少一個拱,連接器似乎不會引用生成的.so文件中的框架。 就我而言,我的框架包含ppc和i386變體。 如果我手動強制鏈接步驟中的-arch標誌爲「i386」,那麼一切工作都正常,包含在MacOSX中的基本python分發版本。如果我在生成的.so文件上運行otool,我可能會發現我的框架。 但是如果我使用系統的默認值-arch i386 -arch ppc -arch x86_64,.so文件沒有鏈接到我的任何框架。 – madflo 2010-04-07 09:50:48

+0

不幸的是,選項1不可用,因爲框架沒有任何源代碼。從我的提供商獲得更新版本似乎是不可能的。 選項2正在工作。謝謝,我幾乎忘了我有一個與macosx捆綁在一起的python二進制文件... 選項3非常奇怪,無法正常工作。正如預期的那樣,在建築物的連接步驟中出現的唯一拱門是i386,但.so並沒有與任何框架相關聯。我會嘗試清除這個問題。 – madflo 2010-04-07 09:54:03

3

雖然不久後塵埃落定,具有同樣的問題我自己,我周圍挖一點點,發現這一點:

/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 

工作就像一個魅力。

+0

我相信PPC的問題是隻有當你得到最新的XCode。也就是說,你可以付錢。配備10.6個OS磁盤的應該沒問題。 – 2011-05-26 12:39:43

+0

我還沒有嘗試過@synthesizerpatel答案,但是我之前的XCode存在ppc問題。免費提供MacOS X DVD。 – madflo 2011-05-27 06:33:39

0

我剛碰到這個。我不得不繞過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 [email protected] 

%.o: %.c Makefile 
    $(CC) $(CFLAGS) $< -c -o [email protected] 

install: $(library) 
    cp $(library) /Library/Python/2.7/site-packages 

clean: 
     rm -f $(library) $(objects) *~ 

我敢肯定有辦法讓distutils的停止發射該-undefined的說法,但上述工作對我來說10。7

相關問題