Prerequisite: .
- Ensure that
gccis installed on the computer and that the terminal can retrieve it - Ensure that the
cythonpackage is installed in Python. If not, usepip install cythonfor installation first
Packaging method: .
-
Step 1: Write the compilation script
setup.py, with the following code:# encoding = utf-8 from distutils.core import setup from Cython.Build import cythonize setup( name = 'libname', ext_modules = cythonize(["file1.py", "file2.py", "dir/file3.py"], language_level = "3") ) -
Step 2: Execute in the terminal:
python3 setup.py build_ext
Points to note: .
-
ext_modulesinsetup()is notexe_modules, so don't make a mistake. If you make a mistake, you will find that it has only been compiled into a.cfile and not used to generate.so - The generated
.socan only be used in the same system, platform, and Python version environment as the packaging computer. To use it on other platforms or environments, it needs to be repackaged on the specified platform or environment - When there are multiple versions of Python, such as the coexistence of bloggers Python 2 and Python 3 on Linux, it is necessary to specify the Python version used for compilation, otherwise the terminal will alarm FutureWarning: Python directive 'language'_Level 'not set, using 2 for now (Py2). There are two ways to specify a version:
- Method 1 Write
# cython:language_level=3at the header of each py file to be packaged - Method 2 : Like in
setup.pyabove, add thelanguage_level = "3"option to thecythonizefunction
- Method 1 Write
- The structure of the packaged
.sofile will be disrupted, such as thefile3.sogenerated byfile3.pyindirbeing in the same directory as the other two, instead of being in thedirfolder. If not adjusted, there may beimporterrors when executing the script, so it is necessary to manually adjust the file structure
Attached code for batch packaging:
import os
import sys
import shutil
import numpy
import tempfile
from setuptools import setup
from setuptools.extension import Extension
from Cython.Build import cythonize
from Cython.Distutils import build_ext
import platform
# code from: https://blog.csdn.net/qq_33375598/article/details/118677130
#directory of files stored after construction
build_root_dir = 'build/lib.' + platform.system().lower() + '-' + platform.machine() + '-' + str(
sys.version_info.major) + '.' + str(sys.version_info.minor)
print(build_root_dir)
extensions = []
ignore_folders = ['build', 'test', 'tests']
conf_folders = ['conf']
def get_root_path(root):
if os.path.dirname(root) in ['', '.']: #obtain the file path for the file
return os.path.basename(root) #return path the final file name
else:
return get_root_path(os.path.dirname(root))
def copy_file(src, dest):
if os.path.exists(dest): #destination file exists and returns
return
if not os.path.exists(os.path.dirname(dest)): #the destination folder does not exist, recursively create a folder
os.makedirs(os.path.dirname(dest))
if os.path.isdir(src): #determine whether a certain path is a directory
shutil.copytree(src, dest) #copy the entire folder (the destination folder needs to not exist, otherwise it will fail)
else:
shutil.copyfile(src, dest) #copy the entire file
def touch_init_file(): #create in temporary folder init
init_file_name = os.path.join(tempfile.mkdtemp(), '__init__.py')
with open(init_file_name, 'w'):
pass
return init_file_name
init_file = touch_init_file()
print(init_file)
def compose_extensions(root='.'):
for file_in os.listdir(root): #all files in the current directory
abs_file = os.path.join(root, file_) #path splicing
if os.path.isfile(abs_file):
if abs_file.endswith('.py'):
extensions.append(Extension(get_root_path(abs_file) + '.*', [abs_file]))
elif abs_file.endswith('.c') or abs_file.endswith('.pyc'):
continue
else:
copy_file(abs_file, os.path.join(build_root_dir, abs_file))
if abs_file.endswith('__init__.py'): #use blank __init__.py replace the original
copy_file(init_file, os.path.join(build_root_dir, abs_file))
else:
if os.path.basename(abs_file) in ignore_folders: #ignored files are not copied
continue
if os.path.basename(abs_file) in conf_folders: #copy configuration files together
copy_file(abs_file, os.path.join(build_root_dir, abs_file))
compose_extensions(abs_file)
compose_extensions()
os.remove(init_file)
setup(
name='your_project_name',
version='1.0',
ext_modules=cythonize(
extensions,
nthreads=16,
compiler_directives=dict(always_allow_keywords=True),
include_path=[numpy.get_include()], language_level="3"),
cmdclass=dict(build_ext=build_ext))
Reference link: .