关键词: python插件, visual studio, Windows编译
1. 背景知识
1.1 关于Python编译
目前,我们使用的Python大部分属于CPython,也就是用C语言实现的Python版本。本质上来讲,无论是在Linux还是Windows平台下,我们使用的都是C编译器编译后的(python)可执行程序。不同点在于,Linux平台源码安装(默认的C编译器一般为gcc)python,C/C++编译环境在本地;Windows平台则通过下载编译好的Python安装使用,本地不一定具备C/C++编译环境。
编译Python使用的编译器版本信息可在python版本信息中查看:
#########################
## 该Linux平台上安装的python是经过GCC 5.4.0版编译器
## 编译生成的python 2.7.12 版
python
Python 2.7.12 (default, Nov 19 2016, 06:48:10)
[GCC 5.4.0 20160609] on linux2
>>> import sys
>>> sys.version
2.7.12 (default, Nov 19 2016, 06:48:10)
[GCC 5.4.0 20160609]
#########################
## 该Windows平台上安装的python是经过Visual C++ 9.0版编译器
## 编译生成的python 2.7.14 版
python
Python 2.7.14 | packaged by conda-forge | (default, Dec 25 2017, 01:17:32) [ MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> print sys.version
2.7.14 | packaged by conda-forge | (default, Dec 25 2017, 01:17:32) [MSC v.1500 64 bit (AMD64)]
为保证兼容性,使用pip给python添加扩展/模块时,如果扩展/模块中包含有C/C++源码,安装脚本将试图寻找与编译生成Python的同版本编译器来编译生成该模块。也就是说在上述两个平台下,Linux平台将寻找并使用GCC 5.4.0 来编译生成Python扩展/模块,Windows平台将寻找并使用Visual C++ 9.0 来编译生成Python扩展/模块。
1.2 关于编译器版本
上面说过,编译生成Python的编译器及版本信息可以在Python的版本信息中查看。通常情况下,Linux平台能够保证Python编译生成环境和Python扩展/模块编译生成环境的一致性,使用中不会存在什么问题。所以本节将主要讨论Windows下的C/C++编译器。
Windows平台下的C/C++编译器默认是 Microsoft Visual C++ (下面简称VC)。VC常作为Microsoft Visual Studio(以下简称VS) 开发套件的组成部分在 VS安装时被安装在设备上,我们通常不单独安装VC。特别需要注意的是不同版本 的VS搭载不同版本的VC,其对应关系如下:
VS版本 | 内部版本 | VC版本 |
---|---|---|
Visual Studio | 4.0 | Visual C++ 4.0 |
Visual Studio 97 | 5.0 | Visual C++ 5.0 |
Visual Studio 6.0 | 6.0 | Visual C++ 6.0 |
Visual Studio .NET 2002 | 7.0 | Visual C++ 2002 |
Visual Studio .NET 2003 | 7.1 | Visual C++ 2003 |
Visual Studio 2005 | 8.0 | Visual C++ 2005 |
Visual Studio 2008 | 9.0 | Visual C++ 2008 |
Visual Studio 2010 | 10.0 | Visual C++ 2010 |
Visual Studio 2012 | 11.0 | Visual C++ 2012 |
Visual Studio 2013 | 12.0 | Visual C++ 2013 |
Visual Studio 2015 | 14.0 | Visual C++ 2015 |
Visual Studio 2015 RTM | 14.0 | Visual C++ 2015 |
所以如果你需要使用 VC 9.0 即 VC 2008,则你需要 安装VS 2008 或 VS 2008 Express 版本才行。
1.3 编译 Python 的VC版本
从 Python的版本信息可以看出:虽然我们能够知道编译生成Python的环境信息(MSC v.1500 64 bit (AMD64)
),但不难发现这和上节所讲的编译器版本上没有直观的联系,那么将如何通过条信息推断相应的VC版本呢?
在Python安装目录的子目录Lib/distutils中,msvccompiler.py 和 msvc9compiler.py 包含了编译器相关的操作。我们先看看两个文件的注释:
"""distutils.msvccompiler
Contains MSVCCompiler, an implementation of the abstract CCompiler class
for the Microsoft Visual Studio.
"""
"""distutils.msvc9compiler
Contains MSVCCompiler, an implementation of the abstract CCompiler class
for the Microsoft Visual Studio 2008.
The module is compatible with VS 2005 and VS 2008. You can find legacy support
for older versions of VS in distutils.msvccompiler.
"""
在这两个文件中定义了一个函数 get_build_version 从python版本信息中抽取编译版本信息,计算并返回编译生成Python的VC版本信息,函数实现如下:
def get_build_version():
"""Return the version of MSVC that was used to build Python.
For Python 2.3 and up, the version number is included in
sys.version. For earlier versions, assume the compiler is MSVC 6.
"""
prefix = "MSC v."
i = string.find(sys.version, prefix)
if i == -1:
return 6
i = i + len(prefix)
s, rest = sys.version[i:].split(" ", 1)
majorVersion = int(s[:-2]) - 6
minorVersion = int(s[2:3]) / 10.0
# I don't think paths are affected by minor version in version 6
if majorVersion == 6:
minorVersion = 0
if majorVersion >= 6:
return majorVersion + minorVersion
# else we don't know what version of the compiler this is
return None
结合节1.1 中所示的python版本信息来推演一遍,过程如下:
- 先提取 MSC v. 字符串后的版本号 1500
- 计算 majorVersion = 15-6 和 minorVersion = 0 / 10.0
- 返回 majorVersion+minorVersion = 9.0
所以在1.1节的环境下,要编译生成python扩展/模块脚本将寻找并使用9.0 版本的VC 编译器。根据 get_build_version 提供的逻辑,只要知道python的详细版本信息就能够推理出所需要的VC版本。
实际上,MSC v. 后面跟的数字并不是随意的、为满足 get_build_version 计算而生成的数字,他们是微软为编译器定义的数字版本号码,只是编译器版本和数字版本号码之间有如 get_build_version 所描述的对应关系。下面列出一些对应关系:
VC版本 | 数字版本号 |
---|---|
Visual C++ 4.x | MSC_VER=1000 |
Visual C++ 5 | MSC_VER=1100 |
Visual C++ 6 | MSC_VER=1200 |
Visual C++ .NET | MSC_VER=1300 |
Visual C++ .NET 2003 | MSC_VER=1310 |
Visual C++ 2005 | MSC_VER=1400 |
Visual C++ 2008 | MSC_VER=1500 |
Visual C++ 2010 | MSC_VER=1600 |
Visual C++ 2012 | MSC_VER=1700 |
Visual C++ 2013 | MSC_VER=1800 |
知道对应的VC版本后,接下了就是找到该版本VC 编译器的物理路径。脚本在寻找VC路径的时候遵循 “先注册表---后环境变量” 的顺序。对于 VC版本>=9.0的情形,脚本通过 HKLM\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\ VC版本 \ Setup\VC\ProductDir (64位Python) 或 HKLM\SOFTWARE\Microsoft\VisualStudio\ VC版本 \ Setup\VC\ProductDir (其他情况)键值获取VC编译器的路径。若该键不存在则通过 环境变量 “VS@0COMNTOOLS” 来确定VC 编译器路径,其中@ 为VC主版本号。具体的寻径策略见 msvc9compiler.py (vc_major>8) 或 msvccompiler.py (低版本)。
2. 解决方案
在用pip为Python安装扩展/模块时,出现错误 “error: Microsoft Visual C++ 9.0 is required” 说明安装脚本没有在安装平台上找到所需要的 9.0 版本的VC 编译器。这种错误通过安装VS 2008 或者 VS 2008 Express 一定能够解决,因为安装软件时会自动设置注册表信息和环境变量信息。
考虑到python的广泛使用性,Microsoft 发布了用于编译python的vc 编译器。通过安装相应版本的程序,用户可为python提供匹配的VC编译环境,从而避免安装VS。这里给出 Python 2.7 对应的 VC 9.0 编译器 Microsoft Visual C++ Compiler for Python 2.7下载地址 :
https://www.microsoft.com/en-us/download/details.aspx?id=44266
http://aka.ms/vcpython27
需要说明的是仅仅通过安装 VC for Python 还不够,因为这个软件在安装过程中既不会设置注册表也不会设置环境变量,所以即使完成了安装也依然会出现找不到编译器的问题。这时可通过手动设置注册表或环境变量的方法排除问题。考虑到脚本路径搜索时,注册表信息对环境变量信息的覆盖作用,以下几个设置方式行之有效:
- 正确设置相应注册表信息 (参见节1.3),此时环境变量设置与否、正确与否不影响使用
- 删除VC版本对应的注册表信息(参见节1.3),正确设置环境变量
- 正确设置注册表信息+正确设置环境变量信息
通过上述设置,该问题得以解决。