我有一个包mypack
,里面有一个模块mymod.py
,和__init__.py
。出于某些原因,这是没有争议的,我需要打包编译的模块(不允许使用.py或.pyc文件)。也就是说,__init__.py
是分布式压缩文件中允许的唯一源文件。
文件夹结构为:
.
│
├── mypack
│ ├── __init__.py
│ └── mymod.py
├── setup.py
我发现Cython可以做到这一点,方法是将.so库中的每个.py文件转换为可以直接用python导入的.so库。
问题是:setup.py
文件必须怎样才能便于打包和安装?
目标系统具有virtualenv,必须使用允许轻松安装和卸载的任何方法安装软件包(欢迎使用easy_install,pip等)。
我尽了一切可能。我阅读setuptools
并distutils
记录了所有与stackoverflow相关的问题,并尝试了各种命令(sdist,bdist,bdist_egg等),并在文件条目中使用了setup.cfg和MANIFEST.com的许多组合。
我得到的最接近的是下面的安装文件,该文件将bdist_egg命令子类化,以便同时删除.pyc文件,但这破坏了安装。
如果覆盖了正确安装中包含的所有辅助文件(我需要pip freeze
在venv中运行,请参见参考资料
mymod==0.0.1
),那么“手动”安装venv文件的解决方案也不错。
使用以下命令运行它:
python setup.py bdist_egg --exclude-source-files
并(尝试)使用
easy_install mymod-0.0.1-py2.7-linux-x86_64.egg
您可能会注意到,目标是使用python 2.7的linux 64位。
from Cython.Distutils import build_ext
from setuptools import setup, find_packages
from setuptools.extension import Extension
from setuptools.command import bdist_egg
from setuptools.command.bdist_egg import walk_egg, log
import os
class my_bdist_egg(bdist_egg.bdist_egg):
def zap_pyfiles(self):
log.info("Removing .py files from temporary directory")
for base, dirs, files in walk_egg(self.bdist_dir):
for name in files:
if not name.endswith('__init__.py'):
if name.endswith('.py') or name.endswith('.pyc'):
# original 'if' only has name.endswith('.py')
path = os.path.join(base, name)
log.info("Deleting %s",path)
os.unlink(path)
ext_modules=[
Extension("mypack.mymod", ["mypack/mymod.py"]),
]
setup(
name = 'mypack',
cmdclass = {'build_ext': build_ext,
'bdist_egg': my_bdist_egg },
ext_modules = ext_modules,
version='0.0.1',
description='This is mypack compiled lib',
author='Myself',
packages=['mypack'],
)
更新。在@Teyras答案之后,可以按照答案中的要求构建轮子。该setup.py
文件内容如下:
import os
import shutil
from setuptools.extension import Extension
from setuptools import setup
from Cython.Build import cythonize
from Cython.Distutils import build_ext
class MyBuildExt(build_ext):
def run(self):
build_ext.run(self)
build_dir = os.path.realpath(self.build_lib)
root_dir = os.path.dirname(os.path.realpath(__file__))
target_dir = build_dir if not self.inplace else root_dir
self.copy_file('mypack/__init__.py', root_dir, target_dir)
def copy_file(self, path, source_dir, destination_dir):
if os.path.exists(os.path.join(source_dir, path)):
shutil.copyfile(os.path.join(source_dir, path),
os.path.join(destination_dir, path))
setup(
name = 'mypack',
cmdclass = {'build_ext': MyBuildExt},
ext_modules = cythonize([Extension("mypack.*", ["mypack/*.py"])]),
version='0.0.1',
description='This is mypack compiled lib',
author='Myself',
packages=[],
include_package_data=True )
关键是要设定packages=[],
。需要重写build_ext
classrun
方法,以使__init__.py
文件进入车轮。
不幸的是,公认的设置答案packages=[]
是错误的,并且可能破坏很多东西,例如可以在此问题中看到。不要使用它。而不是从dist中排除所有软件包,您应该仅排除将被cythonized并编译为共享对象的python文件。
下面是一个工作示例;它使用我的食谱中的问题从python
bdist_egg或bdist_wheel中排除单个源文件。示例项目包含spam
具有两个模块的软件包spam.eggs
和spam.bacon
,以及spam.fizz
具有一个模块的子软件包spam.fizz.buzz
:
root
├── setup.py
└── spam
├── __init__.py
├── bacon.py
├── eggs.py
└── fizz
├── __init__.py
└── buzz.py
模块查找是在build_py
命令中完成的,因此您需要使用自定义行为对其进行子类化。
如果您要编译每个.py
文件(包括__init__.py
s),则覆盖build_py.build_packages
方法已经足够,使其成为noop。由于build_packages
不执行任何操作,因此根本不会.py
收集任何文件,并且dist将仅包含cythonized扩展名:
import fnmatch
from setuptools import find_packages, setup, Extension
from setuptools.command.build_py import build_py as build_py_orig
from Cython.Build import cythonize
extensions = [
# example of extensions with regex
Extension('spam.*', ['spam/*.py']),
# example of extension with single source file
Extension('spam.fizz.buzz', ['spam/fizz/buzz.py']),
]
class build_py(build_py_orig):
def build_packages(self):
pass
setup(
name='...',
version='...',
packages=find_packages(),
ext_modules=cythonize(extensions),
cmdclass={'build_py': build_py},
)
如果只想编译选定的模块,而其余的都保持不变,那么您将需要更复杂的逻辑。在这种情况下,您需要覆盖模块查找。在下面的例子中,我仍然编译spam.bacon
,spam.eggs
和spam.fizz.buzz
对共享对象的,但假__init__.py
文件不变,所以它们将被包括作为源模块:
import fnmatch
from setuptools import find_packages, setup, Extension
from setuptools.command.build_py import build_py as build_py_orig
from Cython.Build import cythonize
extensions = [
Extension('spam.*', ['spam/*.py']),
Extension('spam.fizz.buzz', ['spam/fizz/buzz.py']),
]
cython_excludes = ['**/__init__.py']
def not_cythonized(tup):
(package, module, filepath) = tup
return any(
fnmatch.fnmatchcase(filepath, pat=pattern) for pattern in cython_excludes
) or not any(
fnmatch.fnmatchcase(filepath, pat=pattern)
for ext in extensions
for pattern in ext.sources
)
class build_py(build_py_orig):
def find_modules(self):
modules = super().find_modules()
return list(filter(not_cythonized, modules))
def find_package_modules(self, package, package_dir):
modules = super().find_package_modules(package, package_dir)
return list(filter(not_cythonized, modules))
setup(
name='...',
version='...',
packages=find_packages(),
ext_modules=cythonize(extensions, exclude=cython_excludes),
cmdclass={'build_py': build_py},
)
本文向大家介绍Python编译为二进制so可执行文件实例,包括了Python编译为二进制so可执行文件实例的使用技巧和注意事项,需要的朋友参考一下 通过cpython把python的文件转换为二进制文件,达到代码保护的目的 1、下载Cython-0.28.2.tar.gz python setup.py install安装 2、创建你需要打包成二进制的python文件 3、创建一个setup.py
本文向大家介绍Cython编译python为so 代码加密示例,包括了Cython编译python为so 代码加密示例的使用技巧和注意事项,需要的朋友参考一下 1. 编译出来的so比网上流传的其他方法小很多。 2. language_level 是python的主版本号,如果python版本是2.x,目前的版本Cython需要人工指定language_level. 3. python setup
本文向大家介绍Python编译成.so文件进行加密后调用的实现,包括了Python编译成.so文件进行加密后调用的实现的使用技巧和注意事项,需要的朋友参考一下 pyc的破解相对容易,使用cython将python文件编译成.so文件,能在一定程度上增强python源码的私密性。 编译成.so文件 环境准备:cython 测试脚本准备:test.py 脚本编译准备: 3.1 编写compile.py
如何创建一个预Compiled二进制框架,类似于在这个git repo上使用cloud firestore所做的事情:https://github.com/invertase/firestore-ios-sdk-frameworks 谢谢!
问题内容: 当我在Windows上使用命令编译任意一个__init__.py文件时,它具有无法解析的外部符号错误(即“ LINK:错误LNK2001:无法解析的外部符号PyInit___init__”)。 当地环境: ctest / init.py setup.py 终端打印的信息: 问题答案: 也许此行为可能被视为-package中的一个小错误(如@DavidW所指出的,存在一个未解决的问题:h
问题内容: 我有一个纯Python脚本,我想分发给具有未知Python配置的系统。因此,我想将Python代码编译为独立的可执行文件。 我奔波没有问题。那我跑 哪里给 并给 通过这种方式,我可以获得一个动态链接的可执行文件,该文件可以正常运行。产量 现在,我尝试将选项添加到gcc,但这会导致错误: 我检查了ldd给定的所有共享库是否也都安装为静态库。 那么,这与python3-config提供的选
问题内容: 我已经使用构建了一个简单的可执行程序。 我已经将代码编译成静态二进制程序。 我想反编译输出二进制文件并获取Go源代码。 这有可能吗? 问题答案: 没有工具可以执行此操作,并且由于Go程序已编译为机器代码,因此它们所包含的信息不足,无法将其转换回Go代码。但是,仍然可以使用标准拆卸技术。
Ubuntu是基于Debian Linux, 使用dpkg包挂利器来管理软件像deb. apt程序是用来管理dpkg仓库, 跟zypper和yum使用RPM是一样的. 下面的步骤将会展示如何安装deb. 安装dpkg-dev包. 这个包提供开发工具(包括dpkg-source), 用来unpack, 编译, 和上传Debian源码包. sudo apt-get install dpkg-dev 如