Создание модуля python и привязка его к среде MacOSX
Я пытаюсь создать расширение Python на MacOSX 10.6 и связать его с несколькими фреймворками (только i386). Я создал файл setup.py, используя distutils и объект Extension.
Я хочу связать себя с моими фреймворками, мой LDFLAGS env var должен выглядеть так:
LDFLAGS = -lc -arch i386 -framework fwk1 -framework fwk2
Поскольку я не нашел ключевое слово 'framework' в документации модуля расширения, вместо этого я использовал ключевое слово 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++' )
Все компилируется и хорошо связывается. Если я удаляю строку -framework из extra_link_args, мой компоновщик терпит неудачу, как и ожидалось. Вот две последние строки, создаваемые командой 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.
Приветствия,
Ответы
Ответ 1
Это не имеет ничего общего с undefined dynamic_lookup, но все с distutils. Он добавляет extra_link_flags к флагам ссылок, которые он выбирает для построения python. Вместо этого он должен добавить его, потому что списки -framework должны появиться перед объектами, которые используют их в cmdline (AFAIK это связано с тем, как gcc собирает символы для привязки). Быстрое исправление, которое я лично использую, строит с помощью
LDFLAGS="-framework Carbon" python setup.py build_ext --inplace
или любые необходимые вам рамки. LDFLAGS добавляется к distutils собственным флагам. Обратите внимание, что ваш пакет не будет pip install
в состоянии. Правильное исправление может исходить только от distutils - imho, они должны поддерживать frameworks
, как они поддерживают libraries
.
В качестве альтернативы вы также можете добавить
import os
os.environ['LDFLAGS'] = '-framework Carbon'
в файле setup.py. Тогда ваш пакет должен быть pip install
.
Ответ 2
Я не уверен, что понимаю, что вы пытаетесь сделать, и ваш желаемый результат, но, возможно, это поможет. Поскольку модули расширения C обычно запускаются в контексте выполнения интерпретатора Python, модули расширения должны быть построены для совместимости с интерпретатором. В OS X Python и distutils сталкиваются с некоторыми проблемами, чтобы гарантировать, что модули расширения C построены с теми же значениями SDK (-sysroot
), MACOSX_DEPLOYMENT_TARGET
и -arch
, что сам интерпретатор Python был изначально построен. Итак, если вы используете Python, поставляемый Apple, на 10.6, distutils будет поставлять -arch i386 -arch ppc -arch x86_64
, три арки, с которыми он был построен. Если вы используете текущий установщик OS X Python.org(10.6, 10.5 или 10.4), он будет использовать:
gcc-4.0 -arch ppc -arch i386 -isysroot /Developer/SDKs/MacOSX10.4u.sdk
Из предоставленных фрагментов, я предполагаю, что вы используете универсальный Python, установленный на MacPorts, и по умолчанию он построен и использует -arch x86_64 -arch i386 -isysroot /
для создания модулей расширения.
Как правило, чтобы все работало, вам необходимо обеспечить:
-
имеется по крайней мере один arch
в
общий среди переводчика, все C
модулей расширения и всех внешних
фреймворки и/или разделяемые библиотеки
что они ссылаются на
-
интерпретатор выполняет в этой (или одной из них) общую архитектуру (ы).
В 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 32-разрядную универсальную сборку python2.6 для 32.6/64-разрядной версии на 10.6 для работы в 32-разрядном режиме. По сложным причинам он всегда будет предпочитать 64-битный, если он доступен, даже если вы используете /usr/bin/arch -i386
.
Итак, в зависимости от того, что вы пытаетесь сделать, вы можете решить проблему (если я ее правильно понимаю):
Ответ 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 и как жалуется, потому что нет PPC-части в SDK 10.6.
Однако
export ARCHFLAGS="-arch i386 -arch x86_64"
python setup.py build
Работал как шарм.
Ответ 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)
Если кто-то знает, как force использовать -arch для компиляции и времени ссылки с помощью Python distutils..., пожалуйста, поделитесь своими советами.
Ответ 5
Я просто наткнулся на это сам. Мне пришлось обходить distutils, потому что они выглядят жестко закодированными - undefined dynamic_lookup. Вот Makefile, который я использую для эмуляции distutils:
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