Building a python module and linking it against a MacOSX framework

前端 未结 5 1699
没有蜡笔的小新
没有蜡笔的小新 2021-02-19 05:46

I\'m trying to build a Python extension on MacOSX 10.6 and to link it against several frameworks (i386 only). I made a setup.py file, using distutils and the Extension object.

相关标签:
5条回答
  • 2021-02-19 06:19

    I am not sure I understand what you are trying to do and your desired outcome but perhaps this will help. Because C extension modules are normally run within the execution context of the Python interpreter, extension modules have to be built to be compatible with the interpreter. On OS X, Python and distutils go to some trouble to ensure that C extension modules are built with the same SDK (-sysroot), MACOSX_DEPLOYMENT_TARGET value, and -arch values as the Python interpreter itself was originally built. So, if you are using the Apple-supplied Python on 10.6, distutils will supply -arch i386 -arch ppc -arch x86_64, the three archs that it was built with. If you use a current python.org OS X installer (on 10.6, 10.5, or 10.4), it will use:

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

    From the snippets you supply, I'm guessing you are using a MacPorts-installed universal Python and, by default, it is built with and uses -arch x86_64 -arch i386 -isysroot / for building extension modules.

    Generally, to make everything work you need to ensure:

    1. there is at least one arch in common among the interpreter, all C extension modules, and all external frameworks and/or shared libraries that they link to

    2. the interpreter is executing in that (or one of those) common architecture(s).

    On OS X 10.6, that last step is not as easy as it should be depending on which Python you are using. For instance, the Apple-supplied Python 2.6 has a modification to force 32-bit execution (see Apple's man python for details):

    export VERSIONER_PYTHON_PREFER_32_BIT=yes
    

    If you build your own 32-/64-bit universal Python, there are fixes in 2.6.5 to allow selection at run-time. Unfortunately, the way MacPorts builds Python bypasses those fixes so there does not appear to be any simple way to force a MacPorts python2.6 32-/64-bit universal build on 10.6 to run in 32-bit mode. For complicated reasons, it will always prefer 64-bit, if available, even if you use /usr/bin/arch -i386.

    So, depending on what you are trying to do, you may be able to work around the issue (if I understand it correctly) by either:

    1. rebuild your frameworks to include -arch x86_64
    2. use the Apple-supplied Python (/usr/bin/python) in 32-bit mode or the python.org 2.6.5
    3. reinstall the MacPorts python in 32-bit-only mode (untested!):

      sudo port selfupdate
      sudo port clean python26
      sudo port install python26 +universal universal_archs=i386
      
    0 讨论(0)
  • 2021-02-19 06:23

    It seems that my framework is compiled for ppc and i386 but not 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
    

    I removed the -arch x86_64 flag from my linking line. My library is linked against my frameworks :

    $ 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)
    

    If someone know how to force the -arch to be used at compile and link time with Python's distutils... please share your advice.

    0 讨论(0)
  • 2021-02-19 06:25

    Although long after the dust has settled, having the same question myself I dug around a little bit and found this:

    /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
    

    I'm coming at the problem from a different angle - on 10.6 distutils is trying to build C extensions and as complains because there's no PPC portion in the 10.6 SDK.

    However,

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

    Worked like a charm.

    0 讨论(0)
  • 2021-02-19 06:31

    This has nothing to do with the undefined dynamic_lookup but all with distutils. It appends the extra_link_flags to the link flags it chooses for python building. Instead it should prepend it because the -framework listings must come before the objects that use them on the cmdline (AFAIK this is due how gcc gathers symbols for linking). A quick fix that I personally use is building with

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

    or whatever frameworks you need. LDFLAGS is prepended to distutils own flags. Note that your package will not be pip installable. A proper fix can only come from distutils - imho they should support frameworks like they support libraries.

    Alternatively, you can also add

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

    in your setup.py. Your package should then be pip installable.

    0 讨论(0)
  • 2021-02-19 06:32

    I just ran into this myself. I had to bypass distutils, because they appear to hard-code the -undefined dynamic_lookup. Here is the Makefile I'm using to emulate 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) *~
    

    I'm sure there is a way to get distutils to stop emitting that -undefined argument, but the above worked for me on 10.7

    0 讨论(0)
提交回复
热议问题