Сборка модуля Python и связывание его с платформой MacOSX - PullRequest
14 голосов
/ 06 апреля 2010

Я пытаюсь построить расширение 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:

/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.

Приветствия

Ответы [ 5 ]

8 голосов
/ 04 января 2012

Это не имеет ничего общего с 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.

4 голосов
/ 26 мая 2011

Хотя спустя много времени после того, как пыль осела, у меня возник тот же вопрос, и я немного покопался и обнаружил:

/ System / Library / Frameworks / Python.framework / Версии / 2,6 / Библиотека / 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

работал как шарм.

3 голосов
/ 07 апреля 2010

Я не уверен, что понимаю, что вы пытаетесь сделать, и ваш желаемый результат, но, возможно, это поможет. Поскольку модули расширения 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, три арки, с которыми он был собран. Если вы используете текущий установщик 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 вы используете. Например, поставляемый Apple Python 2.6 имеет модификацию для принудительного 32-разрядного исполнения (подробности см. В Apple man python):

export VERSIONER_PYTHON_PREFER_32_BIT=yes

Если вы создаете свой собственный 32- / 64-битный универсальный Python, в 2.6.5 есть исправления, позволяющие выбирать во время выполнения. К сожалению, способ сборки Python в MacPorts обходит эти исправления, поэтому не существует простого способа заставить 32- / 64-битную универсальную сборку MacPorts python2.6 на 10.6 работать в 32-битном режиме. По сложным причинам он всегда будет предпочитать 64-битную версию, если она доступна, даже если вы используете /usr/bin/arch -i386.

Таким образом, в зависимости от того, что вы пытаетесь сделать, вы можете обойти проблему (если я правильно понимаю) одним из следующих способов:

  1. перестройте ваши фреймворки, включив в них -arch x86_64
  2. использовать предоставленный Apple Python (/usr/bin/python) в 32-битном режиме или python.org 2.6.5
  3. переустановите питон MacPorts в 32-битном режиме (не проверено!):

    sudo port selfupdate
    sudo port clean python26
    sudo port install python26 +universal universal_archs=i386
    
1 голос
/ 06 апреля 2010

Кажется, что мой фреймворк скомпилирован для 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 использовать во время компиляции и связать с distutils Python ... пожалуйста, поделитесь своим советом.

0 голосов
/ 08 ноября 2011

Я просто столкнулся с этим сам. Мне пришлось обойти 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 $@

%.o: %.c Makefile
    $(CC) $(CFLAGS) $< -c -o $@

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

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

Я уверен, что есть способ заставить distutils прекратить испускать этот -неопределенный аргумент, но вышесказанное сработало для меня на 10.7

...