Reputation: 2092
I am trying to package my project code into a an executable binary using Cython
and PyInstaller
libraries.
My code directory looks like this:
The main.py
is the main code which imports the logic from program_a.py
and program_b.py
.
I am successfully able to convert my program_a
and program_b
files into .so files which can be imported by any python code. I did this by executing the following script.
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),
)
By executing >python setup.py build_ext --inplace
I get .so
files as shown below
When I run python main.py
it runs perfectly with .so
files. Which shows that I can import them as a module.
Now, I want to package binaries (.so) files and main.py
into single binary file. For that I used the following command provided by pyInstaller
pyinstaller "main.py" --onefile
It actually gives a binary in dist/
folder but I cannot able to import some modules and getting the following error:
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
How can I link libraries with the pyinstaller or embed library information into my binaries?
What I found yet:
But all of these above links are not using any external package inside there python code examples. I am able to compile the code without external modules
Upvotes: 0
Views: 4622
Reputation: 416
Just in case someone's looking for a quick fix.
I ran into the same situation and found a quick/dirty way to do the job. The issue is that pyinstaller is not adding the necessary libraries in the .exe file that are needed to run your program.
All you need to do is import all the libraries (and the .so files) needed into your main.py file (the file which calls program_a.py and program_b.py). For example, assume that program_a.py uses opencv library (cv2) and program_b.py uses matplotlib library. Now in your main.py file you need to import cv2 and matplotlib as well. Basically, whatever you import in program_a.py and program_b.py, you have to import that in main.py as well. This tells pyinstaller that the program needed these libraries and it includes those libraries in the exe file.
Upvotes: 0
Reputation: 2092
After getting familiar with PyInstaller package I am able to figure out the issue. I followed the following steps to make it work for me at the end.
Now, posting my answer to help others :)
## 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 :)
Here is spec file to make it work for me:
# -*- 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 )
Upvotes: 2