nor*_*ius 11 python distutils setuptools pypi
我的包几乎完全是用 python 编写的。但是,某些功能基于在 python 中使用subprocess. 如果我在本地设置包,我需要首先编译相应的 C++ 项目(由 CMake 管理)并确保在 bin 文件夹中创建生成的二进制可执行文件。然后我的 python 脚本就可以调用这些实用程序。
我的项目的文件夹结构类似于以下内容:
root_dir
- bin
- binary_tool1
- binary_tool2
- cpp
- CMakeLists.txt
- tool1.cpp
- tool2.cpp
- pkg_name
- __init__.py
- module1.py
- module2.py
- ...
LICENSE
README
setup.py
Run Code Online (Sandbox Code Playgroud)
我现在考虑创建一个可分发的 python 包并通过PyPi/pip发布它。因此,我需要将 C++ 项目的构建步骤包含到打包过程中。
到目前为止,我创建了 python 包(没有二进制“有效负载”),如本教程中所述。我现在想知道如何扩展打包过程,以便 C++ 二进制文件与包一起分发。
问题:
setuptools专为这样的用例而设计的吗?我相信用 C 代码扩展纯 python 包的规范方法是创建“二进制扩展”(例如使用distutils,或如此处所述)。在这种情况下,功能由可执行文件提供,而不是由可包装的 C/C++ 函数提供。我想避免重新设计 C++ 项目来创建二进制扩展。
我找到了一些半答案,但没有完整的答案,所以这里是。
我相信您需要从包名称中删除破折号。这个答案的其余部分假设它已被替换为下划线。
site-packages/pkg_name,而site-packages/bin不是将其全部放在site-packages/pkg_name.打包所需的最小文件集现在应如下所示:
- pkg_name/
- __init__.py
- module1.py
- module2.py
- bin/
- binary_tool1
- binary_tool2
- setup.py
Run Code Online (Sandbox Code Playgroud)
__file__:def run_binary_tool1(args):
cmd = [os.path.join(os.path.dirname(__file__), 'bin', 'binary_tool1')] + args
p = subprocess.Popen(cmd, ...)
...
Run Code Online (Sandbox Code Playgroud)
from setuptools import setup
setup(
name='pkg_name',
version='0.1.0',
package_data={
'pkg_name':['bin/binary_tool1','bin/binary_tool2']
},
packages=['pkg_name']
)
Run Code Online (Sandbox Code Playgroud)
# Makefile for pkg_name python wheel
# PKG_NAME and VERSION should match what is in setup.py
PKG_NAME=pkg_name
VERSION=0.1.0
# Shouldn't need to change anything below here
# determine the target wheel file
WHEEL_TARGET=dist/${PKG_NAME}-${VERSION}-py2.py3-none-any.whl
# help
help:
@echo "Usage: make <setup|build|install|uninstall|clean>"
# install packaging utilities (only run this once)
setup: pip install wheel setuptools
# build the wheel
build: ${WHEEL_TARGET}
# install to local python environment
install: ${WHEEL_TARGET}
pip install ${WHEEL_TARGET}
# uninstall from local python environment
uninstall:
pip uninstall ${PKG_NAME}
# remove all build artifacts
clean:
@rm -rf build dist ${PKG_NAME}.egg-info
@find . -name __pycache__ -exec rm -rf {} \; 2>/dev/null
# build the wheel
${WHEEL_TARGET}: setup.py ${PKG_NAME}/__init__.py ${PKG_NAME}/module1.py ${PKG_NAME}/module2.py ${PKG_NAME}/bin/binary_tool1 ${PKG_NAME}/bin/binary_tool2
python setup.py bdist_wheel --universal
Run Code Online (Sandbox Code Playgroud)
make setup # only run once if needed
make install # runs `make build` first
## optional:
# make uninstall
# make clean
Run Code Online (Sandbox Code Playgroud)
在Python中:
import pkg_name
pkg_name.run_binary_tool1(...)
...
Run Code Online (Sandbox Code Playgroud)
您几乎肯定希望在setup()通话中提供更多信息,因此我不会在这里详细介绍。更重要的是,上面创建的轮子声称是通用的,但实际上并非如此。如果您确定仅在单个平台上分发并且不介意这种不匹配,那么这可能足以满足您的需求,但不适合更广泛的分发。
对于多平台分发,您可以走明显的路线并创建特定于平台的轮子(更改--universal上述 Makefile 命令中的标志等)。
或者,如果您可以为每个平台编译一个二进制文件,则可以将所有平台的所有二进制文件打包在一个万能轮中,并让您的 python 代码确定要调用哪个二进制文件(例如,通过检查和/或其他sys.platform可用的方法)变量来确定平台详细信息)。
这种替代方法的优点是打包过程仍然很简单,平台动态代码是一些简单的Python,并且您可以轻松地在多个平台上重用相同的二进制文件,前提是它实际上可以在这些平台上运行。现在,如果“全二进制”方法被至少一些人(如果不是很多的话)所反对,我不会感到惊讶,但是,嘿,Python 用户经常说开发人员的时间是王道,所以这种方法有利于这个论点 -打包二进制可执行文件的整体想法也是如此,而不是经历创建 python/C 包装器接口的所有脑损伤。
| 归档时间: |
|
| 查看次数: |
1321 次 |
| 最近记录: |