Windows平台python 编译C "error: Microsoft Visual C++ 9.0 is required"

关键词: 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版本信息来推演一遍,过程如下:

  1. 先提取 MSC v. 字符串后的版本号 1500
  2. 计算 majorVersion = 15-6 和 minorVersion = 0 / 10.0
  3. 返回 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. 正确设置相应注册表信息 (参见节1.3),此时环境变量设置与否、正确与否不影响使用
  2. 删除VC版本对应的注册表信息(参见节1.3),正确设置环境变量
  3. 正确设置注册表信息+正确设置环境变量信息

通过上述设置,该问题得以解决。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容