Skip to content

Instantly share code, notes, and snippets.

@wtnbgo
Last active November 1, 2022 09:01
Show Gist options
  • Save wtnbgo/48260da414ef1ea0393d1f5b153b7215 to your computer and use it in GitHub Desktop.
Save wtnbgo/48260da414ef1ea0393d1f5b153b7215 to your computer and use it in GitHub Desktop.
get visual studio's Environment Variables on WSL bash
#!/usr/bin/env python
# -*- coding: utf-8 -*-
COMMAND_DESCRIPTION = "copy vc++ environment variables for WSL/CYGWIN/MSYS"
import sys
import argparse
import subprocess
import re
import json
import io
import logging
logger = logging.getLogger("base")
logger.addHandler(logging.StreamHandler())
import distutils.spawn
if distutils.spawn.find_executable("wslpath") != None:
CYGPATH = "wslpath"
else:
CYGPATH = "cygpath"
if sys.platform == 'windows':
CMD_ENCODING = 'mbcs'
elif sys.platform == 'msys' or sys.platform == "win32":
from ctypes import windll
cp = windll.kernel32.GetConsoleOutputCP()
if cp == 65001:
CMD_ENCODING = 'utf-8'
else:
CMD_ENCODING = f'cp{cp}'
else:
CMD_ENCODING = 'utf-8'
def exec_result(cmd):
'''
@param cmd commandline
@return execute stdout
'''
logger.debug(cmd)
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
stdout_data = proc.communicate()[0].decode(CMD_ENCODING)
return stdout_data.strip()
def path_env(winpath):
'''
convert windows path to environment native path
@param winpath Windows Path
@return environment Path
'''
# win の場合はそのまま返す
if sys.platform == 'windows' or sys.platform == "win32":
return winpath
# 変換コマンドを通す
cmd = [CYGPATH, '-u', winpath]
return exec_result(cmd)
def get_lines(cmd, stdin_data=None):
'''
@param cmd command line
@return command stdout lines as iterator
'''
logger.debug(cmd)
if stdin_data != None:
proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout_data, stderr_data = proc.communicate((stdin_data + "\n").encode(CMD_ENCODING))
else:
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout_data, stderr_data = proc.communicate()
lines = io.StringIO(stdout_data.decode(CMD_ENCODING))
while True:
line = lines.readline()
if line:
yield line.strip()
else:
break
def parse_envfile(lines):
'''
@param lines NAME=VALUE lines
@return variables dictionary
'''
variables = {}
reg = re.compile(r'\s*([\w()]+)\s*=\s*(.*)\s*$')
for line in lines:
line = line.strip()
if line and line[0] != '#':
m = reg.search(line)
if m:
g = m.groups()
variables[g[0]] = g[1]
return variables
def vswhere(win_env):
'''
where is visual studio
https://github.com/Microsoft/vswhere
@win_env windows environment variables dict
@return vswhere information
'''
base = win_env['ProgramFiles(x86)']
vswhere_exe = '{}\\Microsoft Visual Studio\\Installer\\vswhere.exe'.format(base)
cmd = [path_env(vswhere_exe), '-all', '-prerelease', '-format', 'json']
return json.loads(exec_result(cmd))
def get_vcvarsall(win_env, version):
'''
find vcversall.bat
@param win_env windows environment variables
@param version VisualStudio Verison (2008,2010,2012,2013,2015,2017)
'''
vsvers = {'2008':'90', '2010':'100', '2012':'110', '2013':'120', '2015':'140'}
if version in vsvers:
varname = 'VS{}COMNTOOLS'.format(vsvers[version])
if varname in win_env:
return '{}..\\..\\VC\\vcvarsall.bat'.format(win_env[varname])
return None
for vsinfo in vswhere(win_env):
if vsinfo['catalog']['productLineVersion'] == version:
return '{}\\VC\\Auxiliary\\Build\\vcvarsall.bat'.format(vsinfo['installationPath'])
def main():
parser = argparse.ArgumentParser(description=COMMAND_DESCRIPTION)
parser.add_argument('-debug', action='store_true', help="show debug info" )
parser.add_argument('-quiet', action='store_true', help="quiet console" )
parser.add_argument('-copyvar', help='copy matching variable from windows env', default='Sdk|SDK|Dir|DIR|ROOT')
parser.add_argument('-vcvars', help='vcvars batch file')
parser.add_argument('-version', help='find vcvars batch from Visual Studio Version')
parser.add_argument('-type', help='varvars option (normaly x86 or amd64)', default='x86')
args = parser.parse_args()
if args.debug:
logLevel = logging.DEBUG
elif args.quiet:
logLevel = logging.ERROR
else:
logLevel = logging.INFO
logger.setLevel(logLevel)
# get windows environment variables
win_env = parse_envfile(get_lines(["cmd.exe", "/c", "set"]))
if args.vcvars:
vcvarsall = args.vcvars
else:
# find vcvarsall.bat
vcvarsall = get_vcvarsall(win_env, args.version)
if vcvarsall == None:
logger.info('Visual Studio {} : Not found'.format(args.version))
sys.exit(1)
logger.info('Visual Studio {} : {}'.format(args.version, vcvarsall))
# get vcvarsall result environment variables
cmdline = 'call "{}" {} & set'.format(vcvarsall, args.type)
new_env = parse_envfile(get_lines(["cmd.exe"], cmdline))
# output for export
reg = re.compile(args.copyvar)
for name in new_env.keys():
if name not in win_env or reg.search(name):
value = new_env[name]
print('export {}=\'{}\''.format(name,value))
if __name__ == '__main__':
main()
@wtnbgo
Copy link
Author

wtnbgo commented Sep 19, 2018

以下のように使います。必要な環境変数定義が export NAME=VALUE の形で標準出力に出力されるので、source で処理します。
2015の部分は VSの番号

$ source <(python vcvarsall.py -version 2022 -type amd64)

# 追加でパス処理する例(msys用)
dir=$(cygpath "${DevEnvDir}")
cmakedir=$(cygpath "${DevEnvDir}CommonExtensions/Microsoft/CMake")
export PATH="$PATH:$dir:$cmakedir/CMake/bin:$cmakedir/Ninja"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment