序言:
Python setuptools用于包分发。我有一个Python包(我们称之为my_package
),它有几个extra_require
包。一切工作都是find(安装和构建包,以及额外的,如果被请求的话),因为所有extra_require
都是python包本身,pip正确地解决了所有问题。一个简单的pip install my_package
就像一个符咒。在
设置:
现在,对于其中一个extra(让我们称之为extra1
),我需要调用一个非python库的二进制文件X
。在
模块X
本身(源代码)被添加到my_package
代码库中,并包含在发行版my_package
中。可悲的是,对于我来说,^ {CD6}}需要首先编译成目标机器上的二进制(C++实现;我假定这样的编译应该发生在^ {CD1}}安装的构建阶段)。在为不同平台编译而优化的X
库中有一个Makefile
,因此所需的就是在生成过程运行时,在my_package
中的X
库的相应目录中运行make
。在
问题1:在包的构建过程中,如何使用setuptools/distutils运行终端命令(例如,make
)?在
问题2:如何确保只有在安装过程中指定了相应的extra1
,才执行这样的终端命令?在
示例:
pip install my_package
,则不会再编译库{pip install my_package [extra1]
,则需要编译模块X
,这样就可以创建相应的二进制文件,并在目标计算机上使用。在
两年前,我对这个问题发表评论很久之后,这个问题就一直困扰着我!我自己最近也遇到了同样的问题,我发现文档非常稀少,我想你们中的大多数人一定都经历过。所以我试着研究一下setuptools和{a2}的源代码,看看能不能找到一种或多或少标准化的方法来回答你提出的这两个问题。在
你问的第一个问题
有很多方法,它们都涉及在调用} 基类的类之间的映射(作为补充说明,
setup
时设置cmdclass
。setup
的参数cmdclass
必须是将根据发行版的构建或安装需要执行的命令名与继承自^{setuptools.command.Command
类是从distutils
'Command
类派生的,因此可以直接从setuptools
实现派生)。在cmdclass
允许您定义任何命令名,如ayoon所做的,然后在从命令行调用python setup.py install-option="customcommand"
时具体执行它。问题在于,当试图通过pip
或调用python setup.py install
安装包时,它不是标准命令。实现这一点的标准方法是检查setup
将尝试在正常安装中执行哪些命令,然后重载特定的cmdclass
。在从^{} 和^{} 开始,} 。反过来,这个命令可以做很多事情,但关键是决定是否调用} 、^{} 和/或{a11}。这意味着无论您使用} 、^{} 和/或^{} 将被运行,因此我们希望用}重载这些命令,问题就变成这三个命令中的哪一个。在
setup
将运行命令it found in the command line,这让我们假设只是一个普通的install
。在setuptools.setup
的情况下,这将触发一系列测试,这些测试将查看是否要求助于对distutils.install
命令类的简单调用,如果没有发生这种情况,它将尝试运行^{build_clib
、build_py
和/或build_ext
命令。如果需要,distutils.install
只运行build
,它还运行^{setuptools
还是distutils
,如果需要从源代码构建,命令^{setup
的{build_py
用于“构建”纯python包,因此我们可以安全地忽略它。在build_ext
用于生成声明的扩展模块,这些模块通过对setup
函数的调用的ext_modules
参数传递。如果我们希望重载这个类,构建每个扩展的主方法是^{build_clib
用于生成声明的库,这些库通过调用libraries
参数传递给setup
函数。在本例中,我们应该用派生类重载的主要方法是^{distutils
)。在我将分享一个示例包,它通过Makefile使用
setuptools
build_ext
命令,通过Makefile构建一个toyc静态库。这种方法可以适应使用build_clib
命令,但是您必须签出build_clib.build_libraries
的源代码。在设置.py
测试包
^{pr2}$测试软件包
测试软件包opt/src/Makefile
test_pack_opt/src/test.c
test_pack_opt/src/testlib.c
test_pack_opt/src/testlib.h
在本例中,我想使用定制Makefile构建的c库只有一个函数,它将}方法。在
"Hello from testlib_fun!\n"
打印到stdout。test.c
脚本是python和这个库的单个函数之间的一个简单接口。我的想法是告诉setup
我想构建一个名为test_pack_opt.test_ext
的c扩展,它只有一个源文件:test.c
接口脚本,我还告诉扩展必须链接到静态库libtestlib.a
。最重要的是我结束了使用specialized_build_ext(build_ext, object)
加载build_ext
cmdclass。只有当您希望能够调用super
来分派给父类方法时,object
的继承才是必需的。build_extension
方法以一个Extension
实例作为第二个参数,为了更好地处理其他需要build_extension
行为的Extension
实例,我检查这个扩展是否有特殊的名称,如果它没有,我调用super
的{对于特殊库,我只使用
subprocess.Popen('make static ...')
调用Makefile。传递给shell的命令的其余部分只是将静态库移动到某个默认位置,在该位置库应该能够将其链接到已编译扩展的其余部分(该扩展也是使用super
的build_extension
方法编译的)。在正如您可以想象的那样,您可以用很多不同的方式来组织这些代码,将它们全部列出是没有意义的。我希望这个例子能够说明如何调用Makefile,以及在标准安装中应该重载哪个}派生类来调用
cmdclass
和{make
。在现在,进入问题2。在
这可能是因为不推荐使用的列出强制要求,} documentation
features
参数setuptools.setup
。标准的方法是根据满足的要求尝试安装包。^{extras_requires
列出可选要求。例如从^{您可以通过调用
pip install Project-A[PDF]
来强制安装可选的必需包,但是如果由于某种原因,名为extra的'PDF'
的要求事先得到满足,pip install Project-A
将以相同的"Project-A"
功能结束。这意味着“Project-A”的安装方式并不是针对命令行中指定的每一个额外的命令而定制的,“Project-A”将始终尝试以相同的方式安装,并且可能由于不可用的可选要求而导致功能减少。在据我所知,这意味着,为了只在指定了[extra1]的情况下编译和安装模块X,您应该将模块X作为一个单独的包发送,并通过
extras_require
依赖它。假设模块X将在my_package_opt
中交付,您的my_package
的设置应该如下所示很抱歉,我的回答太长了,但我希望能有所帮助。请不要犹豫指出任何概念性错误或命名错误,因为我主要是从
setuptools
源代码中推断出来的。在不幸的是,这些文档在设置.py还有皮普,但你应该能做这样的事:
这为您提供了一个使用命令运行任意代码的钩子,还支持各种自定义选项解析(此处未演示)。在
将此文件放入
setup.py
文件中,然后尝试以下操作:pip install install-option="customcommand" .
请注意,此命令是在主安装序列之后执行的,因此根据您正在尝试执行的操作,它可能不起作用。请参阅详细的pip安装输出:
^{pr2}$相关问题 更多 >
编程相关推荐