一:简介
尽管Python标准库已经支持很多的功能,但是有时还是会需要以第三方模块的形式添加新的功能到Python中。
在最简单的场景中,是你要安装的模块,已经有了针对你的平台的安装版本,因此只需要像安装其他软件一样安装他们即可。比如针对Windows用户的安装程序,针对基于RPM的Linux用户的RPM包等等。这种情况,只需要将该安装包下载下来,直接安装即可,比如直接运行”rpm –install”。
当然,事情不会一直这么简单。更多的时候,是需要从一个源码发布包开始安装,但只要该模块是按照标准方式进行打包发布的,从源码发布进行安装也非常简单。
下载了一个模块的源码发布之后,可以使用Distutils简单的分辨出该模块是否是按照标准方式打包和发布的。第一,下载的包的名字通常包含了发布的名字和版本号,比如foo-1.0.tar.gz或者widget-0.9.7.zip;第二,解压之后,包含setup脚本setup.py,包含帮助文件README.txt或README等,该帮助文件说明构建和安装该模块发布的方法,Linux下就是运行命令:python setup.py install;Windows下则是:setup.py install
如果以上的条件都满足的话,那你已经知道了如何构建和安装下载的包了,直接运行上面的命令即可。除非你需要对构建过程进行定制,以非标准的方式安装,否则就不需要接着读本文档了。
二:标准构建和安装
标准的构建和安装过程,只需要运行命令python setup.py install即可。必须在发布的根目录运行该命令,也就是setup.py所在的目录。
比如,如果下载了源码发布文件foo-1.0.tar.gz,在Unix系统上,标准的做法是:
#gunzip -c foo-1.0.tar.gz | tar xf - # unpacks into directory foo-1.0 #cd foo-1.0 #python setup.py install
运行install命令,会依次执行构建和安装过程。当然也可以将其分步执行,比如可能需要将构建和安装交给不同的用户执行。下面的两条命令,首先是构建,然后就是安装:
python setup.py build python setup.py install
这样做时,会发现执行install命令时,它首先还是会执行build命令,因为已经执行过该命令,build目录中已经是最新的了,所以它直接跳过。
一般情况下,如果只是安装从网上下载下来的包,则不需要分成两个步骤。不过这对于执行一些高级任务来说是有用的。
1:构建过程
build命令,主要是将需要安装的文件放到发布根目录下的build子目录中,如果需要改变build目录的位置,可以使用build-base选项,比如:
python setup.py build --build-base=/path/to/pybuild/foo-1.0
默认情况下,build子目录的结构如下:
build/ lib/
或者是:
build/ lib.<plat>/ temp.<plat>/
上面的<plat>会扩展为当前的OS平台以及Python版本。如果该发布只包含纯Python模块,则只会生成lib目录,也就是上面的第一种情况。如果发布中包含由C/C++编写的扩展模块,则会是第二种情况,此时,temp.plat目录中存放了由编译器、连接器产生的临时文件,这些临时文件不会被安装。在两种情况中,lib目录或者lib.plat目录中的文件都会被安装。
2:安装过程
在执行完build命令后(要么明确的运行,要么是在install中执行),install命令剩下的工作就比较简单了,它只是把build/lib或者build/lib.plat中的任何文件都复制到指定的安装目录中。
如果没有指定安装目录,(比如仅执行setup.py install),则install命令就会把文件安装到第三方Python模块的标准路径中。标准路径根据平台的不同而不同。在Unix(以及Mac OS X)上,这还取决于要安装的模块是否包含扩展模块:
Platform |
Standard installation location |
Default value |
Unix (pure) |
prefix/lib/pythonX.Y/site-packages |
/usr/local/lib/pythonX.Y/site-packages |
Unix (non-pure) |
exec-prefix/lib/pythonX.Y/site-packages |
/usr/local/lib/pythonX.Y/site-packages |
Windows |
prefixLibsite-packages |
C:PythonXYLibsite-packages |
prefix和exec-prefix表示Python的安装目录,以及运行时库的搜索路径。可以在Python交互模式下得到这两个值,比如:
>>> import sys >>> sys.prefix '/usr' >>> sys.exec_prefix '/usr'
大多数Linux系统会将Python作为系统的标准组成部分,所以在Linux上,prefix和exec-prefix一般都是”/usr”。如果在Linux上自己安装的Python,则默认的prefix和exec-prefix是”/usr/local”.
另外,X.Y表示Python的版本,比如2.7;distname(下面的备用方案中)表示安装的模块名称。
三:备用安装方案
有时候会希望不以标准方式安装第三方模块,比如可能没有相应目录的权限,或者是在正式安装之前先测试等。
Distutils的install命令支持将发布模块安装到其他目录。基本思想是你需要提供一个base目录,然后install命令将会在该base目录下选择一系列子目录(称为安装方案)来安装不同类型的文件。
注意不同的安装方案是相互排斥的,支持的安装方案是--user、 --home, 、--prefix和--exec-prefix、--install-base 和 --install-platbase,这些方案不能混用。
1:user方案
这种方案对于那些对全局site-packages目录无权限,或者不想安装到该目录下的用户而设计的,命令如下:python setup.py install --user
在这种方案中,base目录就是site.USER_BASE,该值在UNIX上默认值是~/.local。执行上面的命令之后,就会将文件安装到其中的子目录中。这种方案会将纯Python模块和扩展模块安装到相同的子目录中。下面是Unix上相应的子目录:
Type of file |
Installation directory |
modules |
userbase/lib/pythonX.Y/site-packages |
scripts |
userbase/bin |
data |
userbase |
C headers |
userbase/include/pythonX.Y/distname |
跟下面的其他方案相比,该方案的优点就是sys.path会自动包含用户的site-packages目录,也就是说,执行这种方案的安装,之后无需其他步骤(修改sys.path),即可直接使用安装的模块。比如在Linux下,以用户hh安装单独的模块foo,则最终会生成文件:
/home/hh/.local/lib/python2.7/site-packages/foo-1.0-py2.7.egg-info
/home/hh/.local/lib/python2.7/site-packages/foo.py
/home/hh/.local/lib/python2.7/site-packages/foo.pyc
执行完该安装后,进入python交互环境,sys.path打印如下:
>>> sys.path ['', '/usr/lib64/python27.zip', '/usr/lib64/python2.7', '/usr/lib64/python2.7/plat-linux2', '/usr/lib64/python2.7/lib-tk', '/usr/lib64/python2.7/lib-old', '/usr/lib64/python2.7/lib-dynload', '/home/hh/.local/lib/python2.7/site-packages', '/usr/lib64/python2.7/site-packages', '/usr/lib64/python2.7/site-packages/gtk-2.0', '/usr/lib/python2.7/site-packages']
可见它已经自动包含了目录/home/hh/.local/lib/python2.7/site-packages,在安装之前是没有的。
2:home方案
执行这种方案的命令是:python setup.py install --home=<dir>
可以在”--home”选项中指定任意目录。比如上面的例子,如果运行命令:
python setup.py install --home=/root/hehe,则最终生成的文件是:
/root/hehe/lib/python/foo-1.0-py2.7.egg-info
/root/hehe/lib/python/foo.py
/root/hehe/lib/python/foo.pyc
为了能够使用这种方案安装的模块,需要修改python的搜索路径sys.path的值。”—home”指定了安装的base目录,相应的子目录如下:
Type of file |
Installation directory |
modules |
home/lib/python |
scripts |
home/bin |
data |
home |
C headers |
home/include/python/distname |
3:Unix下的prefix 方案
“--prefix”选项指定了安装base目录,”--exec-prefix”指定了平台特定文件的安装base目录(一般而言,就是指扩展模块、C库文件、二进制可执行文件等)。如果没有提供”--exec-prefix”选项,则它等同于”—prefix”。相应的子目录如下:
Type of file |
Installation directory |
Python modules |
prefix/lib/pythonX.Y/site-packages |
extension modules |
exec-prefix/lib/pythonX.Y/site-packages |
scripts |
prefix/bin |
data |
prefix |
C headers |
prefix/include/pythonX.Y/distname |
比如还是上面的例子,如果运行命令:
python setup.py install --prefix=/root/hehe,则生成的文件就是:
/root/hehe/lib/python2.7/site-packages/foo-1.0-py2.7.egg-info
/root/hehe/lib/python2.7/site-packages/foo.py
/root/hehe/lib/python2.7/site-packages/foo.pyc
可以看见这种方案的安装目录与标准安装的目录结构是一样的,其实UNIX中的标准安装就是使用的prefix方案,由sys.prefix(默认为”/usr”) 和 sys.exec_prefix(默认为”/usr”)提供“--prefix”和”--exec-prefix”的值。因此,每次运行python setup.py install命令,其实都是使用了这种安装方案。
Note that installing extensions to an alternate Python installation has no effect on how those extensions are built: in particular, the Python header files(Python.h and friends) installed with the Python interpreter used to run the setup script will be used in compiling extensions. It is your responsibility to ensure that the interpreter used to run extensions installed in this way is compatible with the interpreter used to build them. The best wayto do this is to ensure that the two interpreters are the same version of Python(possibly different builds, or possibly copies of the same build). (Of course,if your --prefix and --exec-prefix don’t even point to an alternate Python installation, this is immaterial.)
windows下的prefix方案,参阅
https://docs.python.org/2/install/index.html#alternate-installation-windows-the-prefix-scheme
四:定制安装
如果备用安装方案还不能满足你的需求,那可以使用定制安装方案。使用该方案,需要以一个备用方案开始,然后用下面的选项调整某些类型的文件的安装目录:
Type of file |
Override option |
Python modules |
--install-purelib |
extension modules |
--install-platlib |
all modules |
--install-lib |
scripts |
--install-scripts |
data |
--install-data |
C headers |
--install-headers |
这些选项的值可以是绝对目录,也可以是相对目录。比如,如果在Unix中,使用home备用方案,但是希望脚本安装在~/scripts,而不是~/bin目录。这时可以使用--install-scripts选项,在这种情况下,该选项的值需要是一个相对目录,是相对于base目录的,也就是home目录:
python setup.py install --home=~ --install-scripts=scripts
再比如,如果采用标准安装方式的话,那脚本可能会安装在/usr/local/python/bin目录下,但是如果你希望将其安装在/usr/local/bin目录下,则选项—install-scripts的值应该是个绝对目录(这种方式使用的其实是prefix方案):
python setup.py install --install-scripts=/usr/local/bin
再比如,如果希望将第三方模块安装在prefix方案的子目录下,而不是直接安装在prefix中,这也很容易办到,因为只有两种类型的模块:纯Python模块和扩展模块,他们可以使用”--install-lib”一起指定:
python setup.py install --install-lib=site
这样就将所有模块都安装在了prefix下的site子目录下。
如果需要定义整个的安装方案,则需要提供所有选项的值,建议使用相对路径。比如,如果希望所有的模块相关的文件都安装在home目录下的python子目录中,则可以这样定义:
python setup.py install --home=~ --install-purelib=python/lib --install-platlib=python/lib.$PLAT --install-scripts=python/scripts --install-data=python/data
或者是
python setup.py install --home=~/python --install-purelib=lib --install-platlib='lib.$PLAT' --install-scripts=scripts --install-data=data
其中的$PLAT不是环境变量,它是Distutils自己定义的配置变量。在下面介绍配置文件时会介绍。
每次安装都敲这些命令的话肯定是非常麻烦的,所以可以将这些选项放在Distutils配置文件中:
[install] install-base=$HOME install-purelib=python/lib install-platlib=python/lib.$PLAT install-scripts=python/scripts install-data=python/data
或
[install] install-base=$HOME/python install-purelib=lib install-platlib=lib.$PLAT install-scripts=scripts install-data=data
五:Distutils配置文件
可以将Distutils的选项放在配置文件中,在执行命令之前,会解析改配置文件,因此,配置文件中的选项会覆盖默认值,而命令行中的选项会覆盖配置文件中的值。如果有多个配置文件,前面的文件会被后面的文件覆盖。
平台不同,配置文件的名称和位置也不同。在Unix上,有三个配置文件如下(按照处理顺序):
Type of file |
Location and filename |
Notes |
system |
prefix/lib/pythonver/distutils/distutils.cfg |
(1) |
personal |
$HOME/.pydistutils.cfg |
|
local |
setup.cfg |
(2) |
1:更严格的说,系统范围的配置文件存在于安装Distutils的目录,比如可能是prefix/lib/pythonver/distutils/中,也可能是/usr/lib64/python2.7/distutils/中。
2:指的是当前目录,也就是setup脚本所在目录
在Winidows上,他们如下:
Type of file |
Location and filename |
system |
prefixLibdistutilsdistutils.cfg |
personal |
%HOME%pydistutils.cfg |
local |
setup.cfg |
在Distutils配置文件中,内容被组织成sections。每个Distutils命令对应一个section,还有一个globalsection,它会影响到所有命令。在每个section中,一行就是一个选项,形式是option=value.
比如,下面就是一个配置文件的完整内容,它仅仅是使所有命令以静默方式执行。
[global] verbose=0
如果这是一个系统范围的配置文件,则它会影响到当前系统下的所有用户,处理所有Python模块的命令。如果它只是某个用户的私有配置文件,则它会影响到该用户处理的模块发布,如果他只是某个特定模块的配置文件,则它只影响该模块。
可以使用下面的配置文件,改变默认的构建base目录,并且使得所有build*命令都强制重新构建所有文件:
[build] build-base=blib force=1
该配置文件对应的命令行是:
python setup.py build --build-base=blib --force
可以通过下面的命令,得到任意命令的所有选项:
python setup.py build --help
可以通过下面的命令,得到所有的全局选项:
python setup.py --help
六:构建扩展的技巧
有时在编译由C或C++编写的Python扩展模块的时候,需要给编译器和链接器提供特定的选项,比如需要连接特定的库或者产生特定的对象码。
大多数情况下,扩展模块的作者会预见到编译扩展模块的复杂性,并且提供一个你可以编辑的setup文件。如果存在该文件,则其中的每一行对应着一个模块,每行的格式如下:
module ... [sourcefile ...] [cpparg ...][library ...]
module对应着要构建的扩展模块,一般情况下不要修改该值。
sourcefile就是源代码文件,扩展名.c表示是C编写的; .C, .cc,.c++表示是由C++编写的,.m或.mm表示是Objective C。
cpparg是C预处理器的参数,比如-I,-D, -U或者-C
library以.a结尾或者以-I或者-L开始。
比如,如果以源码文件foomodule.c编译foo模块,必须链接math库文件libm.a,则Setup文件的内容如下:
foo foomodule.c -lm
可以通过-Xcompiler arg和-Xlinker arg选项,向编译器和链接器提供任意数量的选项,比如:
foo foomodule.c -Xcompiler -o32 -Xlinker -shared -lm
上面的例子会将”-o32”传递给编译器,将”-shared”传递给链接器。如果某个编译器选项需要参数,则需要提供多个-Xcomplier选项,比如为了传递”-x c++”,则Setup文件应该包含-Xcompiler -x -Xcompiler c++。
另外,也可以通过设置CFLAGS环境变量来提供选项给编译器。
https://docs.python.org/2/install/index.html#install-index