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

时间:2013-02-04 23:26:32

标签: python build visual-studio-2012

我正在尝试通过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命令时,我得到它无法识别。它似乎是在不同于运行脚本的子进程中运行文件运行。我真的需要在当前进程中运行它。我最终的目标是在python脚本中完成整个构建,并且会有很多调用devenv来完成构建的主要部分。

谢谢。

6 个答案:

答案 0 :(得分:3)

我和你有完全相同的问题。我试图运行vcvarsall.bat作为用python编写的构建脚本的一部分,我需要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 :(得分: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脚本,但是批处理只是它的工作方式。但是,在进程终止后,你永远不会让变量持久存在。

答案 2 :(得分:1)

在@ derekswanson08的答案基础上,我想出了一个更完全成熟的答案。使用VS 2017附带的wvwhere.exe。

System.Text.StringBuilder myQuery = new System.Text.StringBuilder();
myQuery.AppendFormat("SELECT TABLE_NAME FROM {0}.INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'", valueOfCombobox);

using (SqlCommand com = new SqlCommand(myQuery.ToString(), con))
{
    using (SqlDataReader reader = com.ExecuteReader())
    {
        //comboBox1.Items.Clear();
        while (reader.Read())
        {
            comboBox1.Items.Add((string)reader["TABLE_NAME"]);
        }
    }
}

答案 3 :(得分:0)

您应该使用的是标准库中名为subprocess

的模块

我已将您链接到标准库here.

中的示例

以下是您的情况示例。

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

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

答案 4 :(得分:0)

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

os.system("cd " + vcFolder + " & vcvarsall.bat amd64 & cd " + buildFolder + " & make")

答案 5 :(得分:0)

这是一个简单的示例,应该可以立即使用:

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脚本后,环境变量无效。