Azure
Azure

Reputation: 154

cx_Freeze Mac-build stopped at _ctypes for Homebrew-and-Python

We use cx_Freeze to produce standalone binary build of our python application under Mac OS. The build runs well under the build machine (which has Homebrew-and-Python installed), but failed in client machine with following error messages.

Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/cx_Freeze/initscripts/__startup__.py", line 14, in run
      module.run()
  File "/usr/local/lib/python2.7/site-packages/cx_Freeze/initscripts/Console.py", line 26, in run
      exec(code, m.__dict__)
  File "./utest2.py", line 15, in <module>
      from ttLib import *
  File "ttLib.py", line 848, in init ttLib
      import ctypes
  File "/usr/local/Cellar/python@2/2.7.15_1/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ctypes/__init__.py", line 7, in <module>
      from _ctypes import Union, Structure, Array


ImportError: dlopen(/Users/gff/src/TextSeek_test/build/test_build/lib/_ctypes.so, 2): Symbol not found: __PySlice_AdjustIndices
  Referenced from: /Users/gff/src/TextSeek_test/build/test_build/lib/_ctypes.so
  Expected in: flat namespace
 in /Users/gff/src/TextSeek_test/build/test_build/lib/_ctypes.so

By browsing stackoverflow answers about "__PySlice_AdjustIndices" and "flat namespace", we suspect this error was caused by the python conflict between system-default version and homebrew version.

Then we use "brew install python@2" in client machine, and the ctypes error disappeared. We run "brew uninstall python@2", this error returned back.

The question is : how can we embed necessary part of homebrew-python to bypass this ctype error?

We used "otool -L lib/_ctypes.so" to know the depenency of dynamic-linked file, it only showed out one file "/usr/lib/libSystem.B.dylib". This file seems to have no relation with python.

Any advice to move forward?


Dev Machine Info: Mac High Sierra, python 2.7.15 64bit. Use homebrew-python to build.

setup.py for cx_Freeze :

build_exe_options = {
    "packages":  ["wcwidth", "watchdog", "xlrd", "jinja2", "subprocess"],
    "excludes": [ "AppKit", "Carbon", "CoreFoundation", "Finder", "Foundation", "FSEvents", "objc"],
    "include_msvcr": True,
    "zip_include_packages":["winshell", "wcwidth", "watchdog", "pyhk", "xlrd", "jinja2",\
        "argh", "ctypes",  "email", "encodings" ]
    }
exeList = [Executable( "utest2.py", base = None, targetName= "utest")  ]

setup(  name = "XXX",
        description = u"XXX desc",
        options = {
            "build_exe": build_exe_options,
            'bdist_mac': {
                'bundle_name': "XXX",
            }

        },
        executables = exeList)

Upvotes: 1

Views: 551

Answers (2)

Azure
Azure

Reputation: 154

I found the solution by myself.

This issue is caused by wrongly linked dylib files. We use "otool -L" to find the dependency and re-link them with "install_name_tool -change" one by one. Finally the program works.

Upvotes: 1

jpeg
jpeg

Reputation: 2461

  1. On the client machine, after installation of the frozen application, try to manually copy all dynamic libraries (.so, .dylib, ...?) which are in the lib subdirectory of the build directory into the build directory itself. Copy also all dynamic libraries which are in the build directory into its lib subdirectory. Does this solve the problem? On the build machine, you should of course use the same python version to produce the frozen application than you use to run the unfrozen application.

  2. If 1. solves the problem, find out which dynamic libraries need to be copied in order that the application works (i.e. find out which of the manual copy actions you've done are really necessary). Use the include_files list of the build_exe options in your setup script to let cx_Freeze include the dynamic library automatically at the build step. You can use a tuple (source, destination) as item in the include_files list to let cx_Freeze copy a file from source to a specific destination into the build directory.

Explanation: I don't know Mac/OS. But I believe the issue you describe could be related to a similar issue with Microsoft Visual C++ Redistributable DLLs under Windows: cx_Freeze 5.1.1 includes packages in a lib subdirectory of the build directory, in the previous versions of cx_Freeze they used to be in the build directory itself. Some dynamic libraries need to be found in the build directory but are erroneously included in the lib subdirectory by cx_Freeze or vice versa. On the build machine it is usually not a problem, because a copy of the library is usually found in the system path, but on the client machine often no copy of the library can be found on the system path, or an incompatible one.

By the way the build_exe option "include_msvcr": True does not seem to work in cx_Freeze5.1.1, see this issue.

Upvotes: 0

Related Questions