我尝试安装Python包dulwich:

pip install dulwich

但我收到了一条神秘的错误消息:

error: Unable to find vcvarsall.bat

如果我尝试手动安装软件包,也会发生同样的情况:

> python setup.py install
running build_ext
building 'dulwich._objects' extension
error: Unable to find vcvarsall.bat

当前回答

我尝试了以上所有的答案,但没有为我工作。我使用的是Windows 10,并安装了Visual Studio 2010在我的情况下,需要将vcvars64.bat添加到C:\Program Files(x86)\Microsoft Visual Studio 10.0\VC\bin\amd64

下面是vcvars64.bat:

CALL "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64

如果未安装,请安装Microsoft SDK 7.1,然后重新运行pip Install dulwich

其他回答

您需要安装一个与用于构建Python的编译器兼容的Microsoft编译器。这意味着您需要Visual C++2008(或更高版本,有一些调整)。

微软现在提供了一个捆绑的编译器和头文件,以便能够在令人难忘的URL上编译Python扩展:

Microsoft Visual C++编译器Python 2.7版http://aka.ms/vcpython27

这是一个相对较小的包装;85MB可下载,无需管理员权限即可安装,无需重新启动。这个名字有点误导人,编译器适用于最初使用Visual C++2008编译的任何Python版本,而不仅仅是Python 2.7。

如果启动Python交互式提示或打印sys.version,请查找MSC版本字符串;如果是MSC v.1500,您可以使用此工具。

从最初的公告到distutils列表:

微软发布了Python 2.7的编译器包,使人们更容易在Windows上构建和分发C扩展模块。Microsoft Visual C++编译器Python 2.7版(又名VC9)可从以下网站获得:http://aka.ms/vcpython27 此包包含为Python 2.7 32位和64位构建C扩展模块所需的所有工具和头文件(请注意,某些扩展模块需要第三方依赖项,如未包含的OpenSSL或libxml2)。也支持使用Visual C++2008构建的Python的其他版本,因此“Python 2.7”只是一个广告——它可以在2.6和3.2中正常工作。

请注意,您需要安装setuptools6.0或更高版本(在下载页面的系统要求中列出)。您正在安装的项目必须使用setuptools.setup(),而不是distutils,否则自动检测将无法工作。

微软表示,他们希望保持URL稳定,以便自动化脚本可以轻松引用它。

我找到了解决方案。我也遇到了同样的问题和错误,安装“amara”。我安装了mingw32,但需要配置distutils。

我已经安装了Python 2.6。我将mingw32安装到C:\programs\mingw\将mingw32的bin目录添加到环境变量:append c:\programs\MinGW\bin;到PATH将位于C:\Python26\Lib\distutils\distutils.cfg的distutils.cfg文件编辑为:[生成]编译器=mingw32现在运行easy_install.exe amara。

确保通过打开新的cmd.exe来设置环境。

我也遇到了同样的错误(我觉得这很愚蠢,而且对错误消息没有任何帮助),尽管有一个C编译器可用,我还是继续遇到问题。

令人惊讶的是,最终对我有用的只是将pip和setuptools升级到最新版本。希望这对其他人有所帮助。

如果要使用Visual Studio C++而不是mingw进行编译。。。

运行python.exe以显示编译时使用的VC++版本(示例如下)。使用Python编译时使用的Visual C++编译器的相应版本是很重要的,因为distilutils的get_build_version防止混合版本(根据Piotr的警告)。黄色(顶部)是Python 2.7,使用MSC v.1500(Visual Studio C++2008)编译红色(底部)是Python 3.4.1,使用MSC v.1600(Visual Studio C++2010)编译使用下表[1]将内部VC++版本与相应的Visual Studio版本匹配:MSC v.1000->Visual C++4.xMSC v.1100->Visual C++5MSC v.1200->Visual C++6MSC v.1300->Visual C++.NETMSC v.1310->Visual C++.NET 2003MSC v.1400->Visual C++2005(8.0)MSC v.1500->Visual C++2008(9.0)MSC v.1600->Visual C++2010(10.0)MSC v.1700->Visual C++2012(11.0)MSC v.1800->Visual C++2013(12.0)MSC v.1900->Visual C++2015(14.0)MSC v.1910->Visual C++2017(15.0)MSC v.1911->Visual C++2017(15.3)MSC v.1912->Visual C++2017(15.5)MSC v.1913->Visual C++2017(15.6)MSC v.1914->Visual C++2017(15.7)MSC v.1915->Visual C++2017(15.8)MSC v.1916->Visual C++2017(15.9)从上一步下载并安装相应版本的Visual Studio C++。下面列出了VC++特定版本的其他注意事项。Visual Studio C++2008说明对于32位编译器,请下载Visual Studio C++2008速成版。对于64位编译器[2][3],请下载适用于Windows 7和.NET Framework 3.5 SP1的Windows SDK。取消选中“开发人员工具”>>“Visual C++编译器”以外的所有选项,以节省安装SDK工具所需的时间和磁盘空间。Visual Studio C++2010注释根据Microsoft的说法,如果您安装了Visual Studio 2010 SP1,它可能已经删除了VC++的编译器和库。如果是这种情况,请下载Visual C++2010 SP1编译器更新。Visual Studio C++2015注释如果您不需要Visual Studio IDE,请下载Visual Studio C++2015生成工具。Visual Studio C++2017注释如果您不需要Visual Studio IDE,请下载Visual Studio 2017的生成工具。建议:如果您同时安装了32位和64位Python,您可能还想使用virtualenv创建单独的Python环境,这样您就可以一次使用一个或另一个,而不必打乱选择使用哪个Python版本的路径。

根据@srodriguex的说法,您可以跳过手动加载批处理文件(步骤4-6),而是按照以下答案将一些批处理文件复制到Python正在搜索的位置。如果这不起作用,以下是最初对我有效的步骤。

打开cmd.exe在尝试安装需要C扩展名的东西之前,运行以下批处理文件将VC++编译器的环境加载到会话中(即环境变量、编译器路径等)。执行:32位编译器:注意:32位Windows安装将仅具有预期的C:\Program Files\“C:\Program Files(x86)\Microsoft Visual Studio 9.0\Common7\Tools\vsvars32.bat”64位编译器:“C:\Program Files(x86)\Microsoft Visual Studio 9.0\Common7\Tools\vsvars64.bat”注意:是的,本机64位编译器位于程序文件(x86)中。不要问我为什么。此外,如果您想知道vcvars64.bat和vcvarsx86_amd64.bat之间的区别,或者更重要的是amd64和x86_amd 64之间的区别是什么,前者用于本机64位编译器工具,后者是可以在32位Windows安装上运行的64位交叉编译器。更新:如果由于某种原因,您收到错误:。。。这在当时是出乎意料的。其中。。。是一系列字符,那么您需要检查路径变量是否没有多余的字符,如额外的引号或多余的字符。如果批处理文件一开始就无法理解,那么它将无法更新您的会话路径。如果进展顺利,根据您运行的VC++版本和命令,您应该收到以下消息之一:对于32位编译器工具:设置使用Microsoft Visual Studio 20xx x86工具的环境。对于64位编译器工具:正在设置使用Microsoft Visual Studio 20xx x64工具的环境。现在,通过python setup.py install或pip install pkg名称运行安装程序希望并祈祷行星正确对齐,以便VC++合作。

调用importsetuptools将对补丁distutils进行模仿,以强制与Visual Studio兼容。手动调用vcvars32.bat将设置虚拟环境并防止编译器抛出其他常见错误。对于VS 2017,文件位于

“C:\Program Files(x86)\Microsoft VisualStudio\2017\社区\VC\Auxiliary\Build\vcvars32.bat“

以下是我用来将.pyx文件快速编译为.pyd的安装脚本:(注意:它使用第三方模块发送2个

# cython_setup.py
import sys, os, time, platform, subprocess
from setuptools import setup, find_packages
from Cython.Build import cythonize
from traceback import format_exc

# USAGE:
#
#   from cython_setup import run
#   run(pyx_path)

# vcvars = r"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat"

# NOTE: to use visual studio 2017 you must have setuptools version 34+
vcvars = r"C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars32.bat"


def _build_ext():
    try:
        pyx_path = sys.argv.pop(-1)
        pyx_path = os.path.abspath(pyx_path)
        if not os.path.exists(pyx_path):
            raise FileNotFoundError(f"{pyx_path} does not exist")
        project_name = sys.argv.pop(-1)
        os.chdir(os.path.abspath(os.path.dirname(pyx_path)))

        print("cwd: %s" % os.getcwd())
        print(os.path.abspath("build"))
        setup(
            name=project_name,
            # cmdclass = {'build_ext': build_ext},
            packages=find_packages(),
            # ext_modules=cythonize(extensions)
            ext_modules=cythonize(pyx_path,
                                  compiler_directives={'language_level': 3, 'infer_types': True, 'binding': False},
                                  annotate=True),
            # include_dirs = [numpy.get_include()]
            build_dir=os.path.abspath("build")
        )
    except:
        input(format_exc())


def retry(func):
    def wrapper(*args, **kw):
        tries = 0
        while True:
            try:
                return func(*args, **kw)
            except Exception:
                tries += 1
                if tries > 4:
                    raise
                time.sleep(0.4)

    return wrapper


@retry
def cleanup(pyx_path):
    from send2trash import send2trash
    c_file = os.path.splitext(pyx_path)[0] + ".c"
    if os.path.exists(c_file):
        os.remove(c_file)

    if os.path.exists("build"):
        send2trash("build")


def move_pyd_files(pyx_path):
    pyx_dir = os.path.dirname(pyx_path)
    build_dir = os.path.join(pyx_dir, "build")
    if not os.path.exists(build_dir):
        raise RuntimeError(f"build_dir {build_dir} did not exist....")
    found_pyd = False
    for top, dirs, nondirs in os.walk(build_dir):
        for name in nondirs:
            if name.lower().endswith(".pyd") or name.lower().endswith(".so"):
                found_pyd = True
                old_path = os.path.join(top, name)
                new_path = os.path.join(pyx_dir, name)
                if os.path.exists(new_path):
                    print(f"removing {new_path}")
                    os.remove(new_path)
                print(f"file created at {new_path}")
                os.rename(old_path, new_path)
    if not found_pyd:
        raise RuntimeError("Never found .pyd file to move")

def run(pyx_path):
    """
    :param pyx_path:
    :type pyx_path:
    :return: this function creates the batch file, which in turn calls this module, which calls cythonize, once done
    the batch script deletes itself... I'm sure theres a less convoluted way of doing this, but it works
    :rtype:
    """
    try:
        project_name = os.path.splitext(os.path.basename(pyx_path))[0]
        run_script(project_name, os.path.abspath(pyx_path))
    except:
        input(format_exc())


def run_script(project_name, pyx_path):
    dirname = os.path.dirname(pyx_path)
    # ------------------------------
    os.chdir(dirname)
    if os.path.exists(vcvars):
        #  raise RuntimeError(
        # f"Could not find vcvars32.bat at {vcvars}\nis Visual Studio Installed?\nIs setuptools version > 34?")
        subprocess.check_call(f'call "{vcvars}"', shell=True)

    cmd = "python" if platform.system() == "Windows" else "python3"
    subprocess.check_call(f'{cmd} "{__file__}" build_ext "{project_name}" "{pyx_path}"', shell=True)
    move_pyd_files(pyx_path)
    cleanup(pyx_path)


if len(sys.argv) > 2:
    _build_ext()