3

我正在尝试通过 python 脚本构建一个大型系统。我首先需要为 Visual Studio 设置环境。遇到问题,我决定看看是否可以设置并启动 Visual Studio。我先设置了几个环境变量,然后调用C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat x64.

一旦完成,我会打电话给devenv /useenv. 如果我从命令提示符处执行这些操作,一切正常,我可以在 VS 中做我需要做的事情。我这样做的python代码是:

import os
vcdir=os.environ['ProgramFiles(x86)']
arch = 'x64'
command  = 'CALL "' +vcdir+'\\Microsoft Visual Studio 11.0\\VC\\vcvarsall.bat" '+arch
os.system(command)
command = "CALL devenv /useenv"
os.system(command)

如果我运行它,bat 文件将运行,当它尝试devenv命令时,我得到它无法识别。看起来 bat 文件在与运行脚本的子进程不同的子进程中运行。我真的需要在我当前的进程中运行它。我的最终目标是在 python 脚本中完成整个构建,并且会有很多调用来devenv完成构建的主要部分。

谢谢你。

4

6 回答 6

5

我和你有完全相同的问题。我试图将 vcvarsall.bat 作为用 python 编写的构建脚本的一部分运行,我需要 vcvarsall 创建的环境。我找到了一种方法。首先创建一个名为 setup_environment.bat 的包装脚本:

call "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat" amd64
set > environment.txt

然后在您调用 vcvarsall.bat 的 python 脚本中,运行包装脚本,然后将文本文件中的环境变量读取到当前环境中:

    this_dir = os.path.dirname(os.path.realpath(__file__)) # path of the currently executing script
    os.system('call ' + this_dir + '\setup_environment.bat') # run the wrapper script, creates environment.txt
    f = open('environment.txt','r')
    lines = f.read().splitlines()
    f.close()
    os.remove('environment.txt')
    for line in lines:
        pair = line.split('=',1)
        os.environ[pair[0]] = pair[1]
于 2014-10-02T19:26:07.337 回答
2

这是一个简单的例子,应该开箱即用:

import os
import platform


def init_vsvars():
    vswhere_path = r"%ProgramFiles(x86)%/Microsoft Visual Studio/Installer/vswhere.exe"
    vswhere_path = os.path.expandvars(vswhere_path)
    if not os.path.exists(vswhere_path):
        raise EnvironmentError("vswhere.exe not found at: %s", vswhere_path)

    vs_path = os.popen('"{}" -latest -property installationPath'.format(vswhere_path)).read().rstrip()
    vsvars_path = os.path.join(vs_path, "VC\\Auxiliary\\Build\\vcvars64.bat")

    output = os.popen('"{}" && set'.format(vsvars_path)).read()

    for line in output.splitlines():
        pair = line.split("=", 1)
        if(len(pair) >= 2):
            os.environ[pair[0]] = pair[1]

if "windows" in platform.system().lower():
    init_vsvars()
    os.system("where cl.exe")

请注意,python 脚本退出后环境变量不起作用。

于 2019-09-11T06:57:57.377 回答
1

你试图做的事情是行不通的。 vcvarsall.bat设置环境变量,它只在特定的进程内工作。并且 Python 进程无法CMD.exe在同一进程空间内运行进程。

我有几个解决方案给你。

一种是运行vcvarsall.bat,然后找出它设置的所有环境变量并让 Python 为您设置它们。您可以使用该命令set > file.txt从 CMD shell 中保存所有环境变量,然后编写 Python 代码来解析此文件并设置环境变量。可能工作量太大了。

另一种是创建一个运行的批处理文件,vcvarsall.bat然后从该批处理文件中启动一个新的 Python 解释器。新的 Python 解释器将在一个新的进程中,但它会是该进程下的一个子进程CMD.exe,它会继承所有的环境变量。

或者,嗯。也许最好的事情就是编写一个运行vcvarsall.bat然后运行devenv命令的批处理文件。是的,这可能是最简单的,简单就是好的。

需要注意的重要一点是,在 Windows 批处理文件语言(以及之前的 DOS 批处理文件)中,当您执行另一个批处理文件时,另一个批处理文件设置的变量设置在同一环境中。在 *NIX 中,您需要使用特殊命令source在同一环境中运行 shell 脚本,但批量运行就是这样。但是你永远不会让变量在进程终止后持续存在。

于 2013-02-04T23:41:27.183 回答
1

在@derekswanson08 的答案的基础上,我想出了这个更成熟的方法。使用 VS 2017 自带的 wvwhere.exe。

def init_vsvars():
    cprint("")
    cprint_header("Initializing vs vars")

    if "cygwin" in platform.system().lower():
        vswhere_path = "${ProgramFiles(x86)}/Microsoft Visual Studio/Installer/vswhere.exe"
    else:
        vswhere_path = r"%ProgramFiles(x86)%/Microsoft Visual Studio/Installer/vswhere.exe"
    vswhere_path = path.expandvars(vswhere_path)
    if not path.exists(vswhere_path):
        raise EnvironmentError("vswhere.exe not found at: %s", vswhere_path)

    vs_path = common.run_process(".", vswhere_path,
                                 ["-latest", "-property", "installationPath"])
    vs_path = vs_path.rstrip()

    vsvars_path = os.path.join(vs_path, "VC/Auxiliary/Build/vcvars64.bat")

    env_bat_file_path = "setup_build_environment_temp.bat"
    env_txt_file_path = "build_environment_temp.txt"
    with open(env_bat_file_path, "w") as env_bat_file:
        env_bat_file.write('call "%s"\n' % vsvars_path)
        env_bat_file.write("set > %s\n" % env_txt_file_path)

    os.system(env_bat_file_path)
    with open(env_txt_file_path, "r") as env_txt_file:
        lines = env_txt_file.read().splitlines()

    os.remove(env_bat_file_path)
    os.remove(env_txt_file_path)
    for line in lines:
        pair = line.split("=", 1)
        os.environ[pair[0]] = pair[1]
于 2018-05-02T13:10:45.097 回答
0

您应该使用的是标准库中的一个模块,称为subprocess

我已将您链接到此处标准库中的示例。

这是您的情况的示例。

import shlex, subprocess
args = shlex.split(your_command)
p = subprocess.Popen(args)

如果您需要知道调用发生了什么,那应该执行它也返回stderr。您的命令甚至可能是包含两个 bat 文件的第三个 bat 文件,因此您可以获得所有环境变量。

于 2013-02-04T23:45:03.363 回答
0

另一种解决方案是在与构建命令相同的 os.system 中调用 vcvarsall.bat:

os.system("cd " + vcFolder + " & vcvarsall.bat amd64 & cd " + buildFolder + " & make")
于 2017-03-07T15:07:32.253 回答