本章重点介绍Setuptools,因为这是每个Python程序员都要用到的工具。实际上,Setuptools 并非只能用于创建基于脚本的Python安装程序,还可用于编译扩展。另外,通过将其与扩展py2exe 和py2app结合起来使用,还可创建独立的Windows和macOS可执行程序。
安装setuptools:
C:\Windows\system32>pip install setuptools Requirement already satisfied: setuptools in c:\python37\lib\site-packages (39.0.1)
简单的Setuptools安装脚本(setup.py)
#setup.py from setuptools import setup setup(name='Hello', version='1.0', py_modules=['hello'])
运行结果:
usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...] or: setup.py --help [cmd1 cmd2 ...] or: setup.py --help-commands or: setup.py cmd --help error: no commands supplied ------------------ (program exited with code: 1) 请按任意键继续. . .
同时在setup.py所在的目录中创建了一个pycache新的目录,其内包含一个setup.cpython-37.pyc文件。
试执行命令 build 运行结果:
E:\pythonProjects>python setup.py build running build running build_py creating build creating build\lib copying hello.py -> build\lib E:\pythonProjects>
创建了build目录且在其中包含了源文件hello.py。
执行install命令结果:
E:\pythonProjects>python setup.py install running install running bdist_egg running egg_info creating Hello.egg-info writing Hello.egg-info\PKG-INFO writing dependency_links to Hello.egg-info\dependency_links.txt writing top-level names to Hello.egg-info\top_level.txt writing manifest file 'Hello.egg-info\SOURCES.txt' reading manifest file 'Hello.egg-info\SOURCES.txt' writing manifest file 'Hello.egg-info\SOURCES.txt' installing library code to build\bdist.win-amd64\egg running install_lib running build_py creating build\bdist.win-amd64 creating build\bdist.win-amd64\egg copying build\lib\hello.py -> build\bdist.win-amd64\egg byte-compiling build\bdist.win-amd64\egg\hello.py to hello.cpython-37.pyc creating build\bdist.win-amd64\egg\EGG-INFO copying Hello.egg-info\PKG-INFO -> build\bdist.win-amd64\egg\EGG-INFO copying Hello.egg-info\SOURCES.txt -> build\bdist.win-amd64\egg\EGG-INFO copying Hello.egg-info\dependency_links.txt -> build\bdist.win-amd64\egg\EGG-IN O copying Hello.egg-info\top_level.txt -> build\bdist.win-amd64\egg\EGG-INFO zip_safe flag not set; analyzing archive contents... creating dist creating 'dist\Hello-1.0-py3.7.egg' and adding 'build\bdist.win-amd64\egg' to i removing 'build\bdist.win-amd64\egg' (and everything under it) Processing Hello-1.0-py3.7.egg Copying Hello-1.0-py3.7.egg to c:\python37\lib\site-packages Adding Hello 1.0 to easy-install.pth file Installed c:\python37\lib\site-packages\hello-1.0-py3.7.egg Processing dependencies for Hello==1.0 Finished processing dependencies for Hello==1.0 E:\pythonProjects>
同时在python的安装第三方包目录下产生了一个相应的egg文件;在项目目录中产生了一个Hello.egg-info目录和dist目录。Hello.egg-info中包含了一些信息文件;dist中则包含一个和在python的安装第三方包目录下产生的egg文件相同的文件。
编写让用户能够安装模块的脚本setup.py后,就可使用它来创建归档文件了。你还可使用它 来创建Windows安装程序、RPM包、egg文件、wheel文件等。
要创建源代码归档文件,可使用命令sdist :
E:\pythonProjects>python setup.py sdist running sdist running egg_info writing Hello.egg-info\PKG-INFO writing dependency_links to Hello.egg-info\dependency_links.txt writing top-level names to Hello.egg-info\top_level.txt reading manifest file 'Hello.egg-info\SOURCES.txt' writing manifest file 'Hello.egg-info\SOURCES.txt' warning: sdist: standard file not found: should have one of README, README. README.txt, README.md running check warning: check: missing required meta-data: url warning: check: missing meta-data: either (author and author_email) or (mai er and maintainer_email) must be supplied creating Hello-1.0 creating Hello-1.0\Hello.egg-info copying files to Hello-1.0... copying hello.py -> Hello-1.0 copying setup.py -> Hello-1.0 copying Hello.egg-info\PKG-INFO -> Hello-1.0\Hello.egg-info copying Hello.egg-info\SOURCES.txt -> Hello-1.0\Hello.egg-info copying Hello.egg-info\dependency_links.txt -> Hello-1.0\Hello.egg-info copying Hello.egg-info\top_level.txt -> Hello-1.0\Hello.egg-info Writing Hello-1.0\setup.cfg Creating tar archive removing 'Hello-1.0' (and everything under it)
同时在dist目录下创建了一个.tar.gz的安装文件!
第17章介绍了如何编写Python扩展。你可能也认为这些扩展编译起来有点麻烦,所幸 Setuptools也可用来完成这种任务。你可能想回过头去看看第17章中程序palindrome的源代码。假设这个源代码文件(palindrome2.c)位于当前目录中,则可使用下面的setup.py 脚本来编译(并安装)它:
/*palindrome2.c*/
#include
static PyObject *is_palindrome(PyObject *self, PyObject *args) {
int i, n;
const char *text;
int result;
/* "s"表示一个字符串:*/
if (!PyArg_ParseTuple(args, "s", &text)) {
return NULL;
}
/* 与旧版的代码大致相同:*/
n=strlen(text);
result = 1;
for (i = 0; i <= n/2; ++i) {
if (text[i] != text[n-i-1]) {
result = 0;
break;
}
}
/* "i"表示一个整数:*/
return Py_BuildValue("i", result);
}
/* 方法/函数列表:*/
static PyMethodDef PalindromeMethods[] = {
/*名称、函数、参数类型、文档字符串 */
{"is_palindrome", is_palindrome, METH_VARARGS, "Detect palindromes"},
/* 列表结束标志:*/
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef palindrome =
{
PyModuleDef_HEAD_INIT,
"palindrome", /* 模块名 */
"", /* 文档字符串 */
-1, /*存储在全局变量中的信号状态 */
PalindromeMethods
};
/* 初始化模块的函数:*/
PyMODINIT_FUNC PyInit_palindrome(void)
{
return PyModule_Create(&palindrome);
}
#setup.py
from setuptools import setup, Extension
setup(name='palindrome',
version='1.0',
ext_modules = [
Extension('palindrome', ['palindrome2.c'])
])
如果在编译器中直接运行setup.py或者在终端中仅输入python setup.py将会出现如下错误:
usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
or: setup.py --help [cmd1 cmd2 ...]
or: setup.py --help-commands
or: setup.py cmd --help
error: no commands supplied
------------------
(program exited with code: 1)
请按任意键继续. . .
提示你没有输入命令。必须在终端中输入python setup.py install安装命令。但是如果系统中没有安装Microsoft Visual C++ 14.0,同样会出现错误提示:
error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++
Build Tools": https://visualstudio.microsoft.com/downloads/
正确的结果形如:
E:\pythonProjects>python setup.py install
running install
running bdist_egg
running egg_info
writing palindrome.egg-info\PKG-INFO
writing dependency_links to palindrome.egg-info\dependency_links.txt
writing top-level names to palindrome.egg-info\top_level.txt
reading manifest file 'palindrome.egg-info\SOURCES.txt'
writing manifest file 'palindrome.egg-info\SOURCES.txt'
installing library code to build\bdist.win-amd64\egg
running install_lib
running build_ext
building 'palindrome' extension
creating build\temp.win-amd64-3.7
creating build\temp.win-amd64-3.7\Release
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN\x86_amd64\cl.exe /c
nologo /Ox /W3 /GL /DNDEBUG /MD -IC:\Python37\include -IC:\Python37\include "-I
:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\INCLUDE" "-IC:\Program Fi
es (x86)\Windows Kits\10\include\10.0.10240.0\ucrt" "-IC:\Program Files (x86)\W
ndows Kits\8.1\include\shared" "-IC:\Program Files (x86)\Windows Kits\8.1\inclu
e\um" "-IC:\Program Files (x86)\Windows Kits\8.1\include\winrt" /Tcpalindrome2.
/Fobuild\temp.win-amd64-3.7\Release\palindrome2.obj
palindrome2.c
palindrome2.c(12): warning C4267: '=': conversion from 'size_t' to 'int', possi
le loss of data
creating E:\pythonProjects\build\lib.win-amd64-3.7
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\BIN\x86_amd64\link.exe /
ologo /INCREMENTAL:NO /LTCG /DLL /MANIFEST:EMBED,ID=2 /MANIFESTUAC:NO /LIBPATH:
:\Python37\libs /LIBPATH:C:\Python37\PCbuild\amd64 "/LIBPATH:C:\Program Files (
86)\Microsoft Visual Studio 14.0\VC\LIB\amd64" "/LIBPATH:C:\Program Files (x86)
Windows Kits\10\lib\10.0.10240.0\ucrt\x64" "/LIBPATH:C:\Program Files (x86)\Win
ows Kits\8.1\lib\winv6.3\um\x64" /EXPORT:PyInit_palindrome build\temp.win-amd64
3.7\Release\palindrome2.obj /OUT:build\lib.win-amd64-3.7\palindrome.cp37-win_am
64.pyd /IMPLIB:build\temp.win-amd64-3.7\Release\palindrome.cp37-win_amd64.lib
palindrome2.obj : warning LNK4197: export 'PyInit_palindrome' specified multipl
times; using first specification
Creating library build\temp.win-amd64-3.7\Release\palindrome.cp37-win_amd64.
ib and object build\temp.win-amd64-3.7\Release\palindrome.cp37-win_amd64.exp
Generating code
Finished generating code
creating build\bdist.win-amd64\egg
copying build\lib.win-amd64-3.7\palindrome.cp37-win_amd64.pyd -> build\bdist.wi
-amd64\egg
creating stub loader for palindrome.cp37-win_amd64.pyd
byte-compiling build\bdist.win-amd64\egg\palindrome.py to palindrome.cpython-37
pyc
creating build\bdist.win-amd64\egg\EGG-INFO
copying palindrome.egg-info\PKG-INFO -> build\bdist.win-amd64\egg\EGG-INFO
copying palindrome.egg-info\SOURCES.txt -> build\bdist.win-amd64\egg\EGG-INFO
copying palindrome.egg-info\dependency_links.txt -> build\bdist.win-amd64\egg\E
G-INFO
copying palindrome.egg-info\top_level.txt -> build\bdist.win-amd64\egg\EGG-INFO
writing build\bdist.win-amd64\egg\EGG-INFO\native_libs.txt
zip_safe flag not set; analyzing archive contents...
__pycache__.palindrome.cpython-37: module references __file__
creating 'dist\palindrome-1.0-py3.7-win-amd64.egg' and adding 'build\bdist.win-
md64\egg' to it
removing 'build\bdist.win-amd64\egg' (and everything under it)
Processing palindrome-1.0-py3.7-win-amd64.egg
creating c:\python37\lib\site-packages\palindrome-1.0-py3.7-win-amd64.egg
Extracting palindrome-1.0-py3.7-win-amd64.egg to c:\python37\lib\site-packages
Adding palindrome 1.0 to easy-install.pth file
Installed c:\python37\lib\site-packages\palindrome-1.0-py3.7-win-amd64.egg
Processing dependencies for palindrome==1.0
Finished processing dependencies for palindrome==1.0
E:\pythonProjects>
以上结果很清楚说明了egg文件安装成功:
Installed c:\python37\lib\site-packages\palindrome-1.0-py3.7-win-amd64.egg
同样在项目目录下也会产生一个包含诸多信息的信息目录,同时在安装目录下也会产生相应的目录。至此python就可以毫无顾忌的引用C/++语言编写的函数(类)等要素了。如果系统安装了SWIG再编辑一个.i接口文件,它将产生一个.so文件 ,这就不需要象第十七章所讲的那样繁琐,就能轻而易举的把C/C++与Python联系在一起了。
py2exe是Setuptools的一个扩展(可通过pip来安装它),让你能够创建可执行的Windows程序 (.exe文件)。
打包exe文件:1)在setup.py中加入
... ...
import py2exe
... ...
在setup.py所在的目录运行终端,并输入如下命令
python setup.py py2exe
既能创建控制台程序。
使用py2app创建macOS控制台程序的方法大致与此相同。
(至此python语言所有技能叙述完了,留下了不少遗憾和错误。其实它的每一章都可以是一本厚厚的书,不可能事无巨细,这本书的目的是领路,不会陪你到天亮的。但编程关键是阅读和练习,阅读资料、源代码及别人的编码;自己勤动手写,最终把这门语言融汇到血液里)