Search code examples
pythonlxmlpy2app

Problem using py2app with the lxml package


I am trying to use 'py2app' to generate a standalone application from some Python scripts. The Python uses the 'lxml' package, and I've found that I have to specify this explicitly in the setup.py file that 'py2app' uses. However, the resulting application program still won't run on machines that haven't had 'lxml' installed.

My Setup.py looks like this:

from setuptools import setup

OPTIONS = {'argv_emulation': True, 'packages' : ['lxml']}

setup(app=[MyApp.py],
      data_files=[],
      options={'py2app' : OPTIONS},
      setup_requires=['py2app'])

Running the application produces the following output:

MyApp Error
An unexpected error has occurred during execution of the main script
ImportError: dlopen(/Users/ake/XXXX/XXXX/MyApp.app/Contents/Resources/lib/python2.5/lxml/etree.so, 2): Symbol not found: _xmlSchematronParse
Referenced from: /Users/ake/XXXX/XXXX/MyApp.app/Contents/Resources/lib/python2.5/lxml/etree.so
Expected in: dynamic lookup

The symbol '_xmlSchematronParse' is from a library called 'libxml2' that 'lxml' depends on. The version that comes preinstalled with Mac OS X isn't up to date enough for 'lxml', so I had to install version 2.7.2 (in /usr/local). py2app, for some reason, is linking in the version in /Developer/SDKs/MacOSX10.3.9.sdk/usr/lib. When I run my application as a Python script though, the correct version is found. (I checked this just now by hiding the 2.7.2 version.)

So my question now is, how can I tell py2app where to look for libraries?


Solution

  • Found it. py2app has a 'frameworks' option to let you specify frameworks, and also dylibs. My setup.py file now looks like this:

    from setuptools import setup
    
    DATA_FILES = []
    OPTIONS = {'argv_emulation': True,
               'packages' : ['lxml'],
               'frameworks' : ['/usr/local/libxml2-2.7.2/lib/libxml2.2.7.2.dylib']
              }
    
    setup(app=MyApp.py,
          data_files=DATA_FILES,
          options={'py2app' : OPTIONS},
          setup_requires=['py2app'])
    

    and that's fixed it.

    Thanks for the suggestions that led me here.