通过Python在当前进程中运行bat文件

5 投票
6 回答
5917 浏览
提问于 2025-04-17 14:45

我正在尝试通过一个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 来完成大部分的构建工作。

谢谢。

6 个回答

5

这里有一个简单的例子,应该可以直接使用:

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脚本退出后就不再有效了。

5

我遇到过和你一样的问题。我在用Python写一个构建脚本时,想要运行vcvarsall.bat,因为我需要vcvarsall创建的环境。我找到了解决办法。首先,创建一个叫做setup_environment.bat的包装脚本:

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

然后在你的Python脚本中,原本你会调用vcvarsall.bat的地方,改为运行这个包装脚本,然后从文本文件中读取环境变量到你当前的环境中:

    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]
1

你想做的事情是行不通的。vcvarsall.bat 是用来设置环境变量的,这些环境变量只在特定的进程中有效。而且,Python 进程无法在同一个进程空间内运行 CMD.exe 进程。

我有几种解决方案可以给你。

一种方法是先运行 vcvarsall.bat,然后找出它设置的所有环境变量,再让 Python 来设置这些变量。你可以使用命令 set > file.txt 将 CMD 窗口中的所有环境变量保存到一个文件中,然后写 Python 代码来解析这个文件并设置环境变量。不过,这可能工作量有点大。

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

或者,嗯,也许最简单的方法就是写一个批处理文件,先运行 vcvarsall.bat,然后再运行 devenv 命令。对,这可能是最简单的,而简单的东西总是好的。

需要注意的是,在 Windows 的批处理文件语言中(还有之前的 DOS 批处理文件),当你执行另一个批处理文件时,那个批处理文件设置的变量会在同一个环境中生效。在 *NIX 系统中,你需要使用一个特殊的命令 source 来在同一个环境中运行一个脚本,但在批处理文件中就是这样工作的。不过,一旦一个进程结束,你是无法让变量继续存在的。

撰写回答