简体   繁体   English

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

[英]running a bat file though python in current process

I am attempting to build a large system through a python script. 我正在尝试通过python脚本构建大型系统。 I first need to set up the environment for Visual Studio. 我首先需要为Visual Studio设置环境。 Having problems I decided to see if I could just set up and launch Visual Studio. 遇到问题后,我决定看看是否可以设置并启动Visual Studio。 I first set several environment variables and then call C:\\Program Files (x86)\\Microsoft Visual Studio 11.0\\VC\\vcvarsall.bat x64 . 我首先设置了几个环境变量,然后调用C:\\Program Files (x86)\\Microsoft Visual Studio 11.0\\VC\\vcvarsall.bat x64

Once this finishes I call devenv /useenv . 完成此操作后,我将调用devenv /useenv If I do these from the command prompt everything works fine and I can do what I need to do in VS. 如果我从命令提示符处执行这些操作,则一切正常,并且可以执行VS中需要做的事情。 My python code for doing this is: 我这样做的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)

If I run this, the bat file will run and when it tries the devenv command I get that it is not recognized. 如果运行此命令,bat文件将运行,当它尝试使用devenv命令时,我得到它无法识别。 It looks like to bat file runs in a different subprocess than the one that the script is running in. I really need to get this running in my current process. 看起来文件运行在与脚本运行所在的子进程不同的子进程中。我确实需要在当前进程中运行它。 My eventual goal is to do the entire build inside the python script and there will be many calls to devenv to do a major portion of the build. 我最终的目标是在python脚本内完成整个构建,并且会有很多调用devenv来完成构建的主要部分。

Thank you. 谢谢。

I had the exact same problem as you. 我和你有完全一样的问题。 I was trying to run vcvarsall.bat as part of a build script written in python and I needed the environment created by vcvarsall. 我试图将vcvarsall.bat作为python编写的构建脚本的一部分运行,并且我需要vcvarsall创建的环境。 I found a way to do it. 我找到了一种方法。 First create a wrapper script called setup_environment.bat: 首先创建一个名为setup_environment.bat的包装器脚本:

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

Then in your python script where you would have called vcvarsall.bat, run the wrapper script, then read the environment variables from the text file into your current environment: 然后在您将调用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]

What you are trying to do won't work. 您尝试做的事行不通。 vcvarsall.bat sets environment variables, which only work inside a particular process. vcvarsall.bat设置仅在特定进程内工作的环境变量。 And there is no way for a Python process to run a CMD.exe process within the same process space. 而且,Python进程无法在同一进程空间内运行CMD.exe进程。

I have several solutions for you. 我为您提供几种解决方案。

One is to run vcvarsall.bat , then figure out all the environment variables it sets and make Python set them for you. 一种是运行vcvarsall.bat ,然后找出它设置的所有环境变量,然后让Python为您设置它们。 You can use the command set > file.txt to save all the environment variables from a CMD shell, then write Python code to parse this file and set the environment variables. 您可以使用命令set > file.txt从CMD Shell中保存所有环境变量,然后编写Python代码来解析此文件并设置环境变量。 Probably too much work. 可能是太多的工作。

The other is to make a batch file that runs vcvarsall.bat , and then fires up a new Python interpreter from inside that batch file. 另一种是制作一个运行vcvarsall.bat的批处理文件,然后从该批处理文件内部启动一个新的Python解释器。 The new Python interpreter will be in a new process, but it will be a child process under the CMD.exe process, and it will inherit all the environment variables. 新的Python解释器将处于新进程中,但它将是CMD.exe进程下的CMD.exe进程,并且它将继承所有环境变量。

Or, hmm. 或者,嗯。 Maybe the best thing is just to write a batch file that runs vcvarsall.bat and then runs the devenv command. 也许最好的办法就是编写一个运行vcvarsall.bat的批处理文件,然后运行devenv命令。 Yeah, that's probably simplest, and simple is good. 是的,这可能是最简单的,简单也很好。

The important thing to note is that in the Windows batch file language (and DOS batch file before it), when you execute another batch file, variables set by the other batch file are set in the same environment. 需要注意的重要一点是,在Windows批处理文件语言(及其之前的DOS批处理文件)中,当您执行另一个批处理文件时,由另一个批处理文件设置的变量将在同一环境中设置。 In *NIX you need to use a special command source to run a shell script in the same environment, but in batch that's just how it works. 在* NIX中,您需要使用特殊的命令source来在相同的环境中运行Shell脚本,但是批处理就是这样工作的。 But you will never get variables to persist after a process has terminated. 但是,在进程终止后,您将永远不会保留变量。

Building on the answer by @derekswanson08 I came up with this which is a bit more fully-fledged. 在@ derekswanson08的答案的基础上,我想到了这个功能,它更加成熟。 Uses wvwhere.exe which comes with VS 2017. 使用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]

What you should be using is a module in the standard library called subprocess 您应该使用的是标准库中称为subprocess的模块

I have linked you to an example in the standard library here. 我已经将您链接到此处的标准库中的示例

Here is an example with your situation. 这是您情况的一个示例。

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

That should execute it also return stderr if you need to know what happened with the call. 如果您需要知道调用发生了什么,那应该执行它并返回stderr。 your command might even be a third bat file that encompasses the two bat files so you get all the environment variables. 您的命令甚至可能是包含两个bat文件的第三个bat文件,因此您可以获得所有环境变量。

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

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

Here is a simple example, should work out of box: 这是一个简单的示例,应该可以立即使用:

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")

Please note that environment variables don't have effect after python script exits. 请注意,在退出python脚本后,环境变量无效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM