使用PyInstaller将Cython编译的模块和python代码构建为可执行二进制文件

时间:2019-04-16 12:11:35

标签: python shared-libraries cython pyinstaller binaryfiles

我正在尝试使用CythonPyInstaller库将项目代码打包为可执行二进制文件。 我的代码目录如下:

Code Directory main.py是从program_a.pyprogram_b.py导入逻辑的主要代码。

我成功地将program_aprogram_b文件转换为.so文件,可以通过任何python代码导入。我是通过执行以下脚本来做到这一点的。

from distutils.core import setup
from Cython.Build import cythonize

sourcefiles = ['program_a.py', 'program_b.py']

setup(
    name = "Hello World",
    ext_modules = cythonize(sourcefiles), 
)

通过执行> python setup.py build_ext --inplace,我将得到.so文件,如下所示

binaries with libraries 当我运行python main.py时,它可以与.so文件完美地运行。这表明我可以将它们作为模块导入。

现在,我想将二进制(.so)文件和main.py打包到单个二进制文件中。为此,我使用了pyInstaller

提供的以下命令
  

pyinstaller "main.py" --onefile

它实际上在dist/文件夹中提供了一个二进制文件,但是我无法导入某些模块并出现以下错误:

Traceback (most recent call last):
  File "main.py", line 1, in <module>
    import program_a as lisence_checker
  File "program_a.py", line 1, in init program_a
ModuleNotFoundError: No module named 'licensing'
[18032] Failed to execute script main

如何将库与pyinstaller链接或将库信息嵌入到我的二进制文件中?

我发现了什么

  1. Building Cython-compiled python code with PyInstaller

  2. https://riptutorial.com/cython/example/21982/bundling-a-cython-program-using-pyinstaller

但是以上所有这些链接都没有使用python代码示例中的任何外部包。我可以在没有外部模块的情况下编译代码

2 个答案:

答案 0 :(得分:0)

熟悉PyInstaller程序包后,我就可以找出问题所在。最后,我按照以下步骤进行操作。

现在,发布我的答案以帮助他人:)

## Build *.so files from python modules 
    1. Execute "setup.py" file
       > python setup.py build
    2. It will generate "*.so" modules inside "build/lib.linux-x86_64-3.6" dir.

## Created binary from cython modules
    1. Copy the binaries (i.e. *.so) files into binary folder
    2. Get inside the binary folder 'cd binary'
    3. Run Pyinstaller command inside binary directory: `python -O -m PyInstaller --clean --onefile idps.spec`
    4. Your binary will be inside dist folder 'binary/dist/'
    5. Execute the binary in linux using './dist/sample_app'
    6. Your app is ready :)

这是使它对我有用的规格文件:

# -*- mode: python -*-

block_cipher = None


a = Analysis(['main.py'],
             pathex=['cython_pyinstaller_sample/binary'],
             binaries=[('program_a.cpython-36m-x86_64-linux-gnu.so', '.'),('program_b.cpython-36m-x86_64-linux-gnu.so', '.')],
             datas=[('config_file.txt', '.')],
             hiddenimports=['licensing', 'licensing.methods', 'pandas'],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             noarchive=False) pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher) exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          [],
          name='sample_app',
          debug=True,
          bootloader_ignore_signals=False,
          strip=False,
          upx=True,
          runtime_tmpdir=None,
          console=True )

答案 1 :(得分:0)

以防万一有人在寻找快速解决方案。

我遇到了同样的情况,发现一种快速/肮脏的方式来完成这项工作。问题是pyinstaller没有在运行程序所需的.exe文件中添加必需的库。

所有您需要做的就是将所有需要的库(和.so文件)导入到main.py文件(调用program_a.py和program_b.py的文件)中。例如,假设program_a.py使用opencv库(cv2),而program_b.py使用matplotlib库。现在,在main.py文件中,您还需要导入cv2和matplotlib。基本上,无论您在program_a.py和program_b.py中导入什么内容,都必须在main.py中也导入它。这告诉pyinstaller该程序需要这些库,并且在exe文件中包含这些库。