關鍵詞: 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),正確設置環境變量
- 正確設置注冊表信息+正確設置環境變量信息
通過上述設置,該問題得以解決。