running a bat file though python in current process

邮差的信 提交于 2019-12-13 13:28:25

问题


I am attempting to build a large system through a python script. I first need to set up the environment for Visual Studio. Having problems I decided to see if I could just set up and launch Visual Studio. I first set several environment variables and then call C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat x64.

Once this finishes I call devenv /useenv. If I do these from the command prompt everything works fine and I can do what I need to do in VS. My python code for doing this is:

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. 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.

Thank you.


回答1:


What you are trying to do won't work. vcvarsall.bat sets environment variables, which only work inside a particular process. And there is no way for a Python process to run a CMD.exe process within the same process space.

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. 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. 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. 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.

Or, hmm. Maybe the best thing is just to write a batch file that runs vcvarsall.bat and then runs the devenv command. 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. 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. But you will never get variables to persist after a process has terminated.




回答2:


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. I found a way to do it. First create a wrapper script called 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:

    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]



回答3:


Building on the answer by @derekswanson08 I came up with this which is a bit more fully-fledged. Uses wvwhere.exe which comes with VS 2017.

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]



回答4:


What you should be using is a module in the standard library called 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. your command might even be a third bat file that encompasses the two bat files so you get all the environment variables.




回答5:


Another solution is to call vcvarsall.bat within the same os.system than the build command:

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



回答6:


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.



来源:https://stackoverflow.com/questions/14697629/running-a-bat-file-though-python-in-current-process

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!