我尝试安装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

当前回答

您可以从安装编译版本http://www.lfd.uci.edu/~gohlke/pythonlibs/

其他回答

您可以从下载免费的Visual C++2008速成版http://go.microsoft.com/?linkid=7729279,它将在安装期间设置VS90COMNTOOLS环境变量,因此使用兼容的编译器进行构建。

正如@PiotrDobrogost在一篇评论中提到的,他对另一个问题的回答详细说明了为什么Visual C++2008是正确的构建工具,但随着Windows版本的Python迁移到Visual Studio的更新版本,这一点可能会发生变化:在Windows上为Python 2.7构建lxml

对于Python 3.4,依赖于Visual Studio 2010。安装Visual C++2010 Express为我解决了这个问题。

欺骗它使用VS 2008或2013安装,而我碰巧没有使用。

调用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()

如果您希望在未安装Visual Studio的Windows机箱上安装pyodbc,另一种选择是使用二进制发行版手动安装pyodcc。

如果您在正在使用的计算机上没有管理员权限,并且正在尝试设置virtualenv,则这特别有用。

步骤:

从这里下载最新的Windows安装程序(pyodbc-X.X.X.X.win-Y-py2.7.exe)使用7-Zip(或WinRAR等)打开安装程序可执行文件提取pyodbc.pyd和pyodbc-X.X-X-py2.7.egg-info,并将它们放在[python安装目录或virtualenv]\Lib\site包中没有步骤4:)

您可以从安装编译版本http://www.lfd.uci.edu/~gohlke/pythonlibs/