GN: Autodetect Visual Studio versions
This searches the local system for Visual Studio versions like GYP. It enables specifically requesting one version, as well as overriding the directory like GYP. BUG= R=scottmg@chromium.org Review URL: https://codereview.chromium.org/126073005 git-svn-id: http://src.chromium.org/svn/trunk/src/build@243612 4ff67af0-8c30-449e-8e8b-ad334ec8d88c
This commit is contained in:
Родитель
c4dfd98310
Коммит
d26952a6e6
|
@ -2,13 +2,13 @@
|
|||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import("//build/config/win/visual_studio_version.gni")
|
||||
|
||||
declare_args() {
|
||||
# Full path to the Windows SDK, not including a backslash at the end.
|
||||
# This value is the default location, override if you have a different
|
||||
# installation location.
|
||||
windows_sdk_path = "C:\Program Files (x86)\Windows Kits\8.0"
|
||||
|
||||
# Full path to the Visual Studio installation, not including a backslash
|
||||
# at the end.
|
||||
visual_studio_path = "C:\Program Files (x86)\Microsoft Visual Studio 10.0"
|
||||
}
|
||||
|
||||
# Compiler setup for the Windows SDK. Applied to all targets.
|
||||
|
|
|
@ -0,0 +1,175 @@
|
|||
# Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import errno
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
"""
|
||||
This script searches for Visual Studio versions on the current system.
|
||||
|
||||
Pass in the preferred VS version on the command line, or pass "auto" for
|
||||
autodetect.
|
||||
|
||||
This script prints a string containing the VS root directory. On failure it
|
||||
returns the empty string.
|
||||
"""
|
||||
|
||||
def _ConvertToCygpath(path):
|
||||
"""Convert to cygwin path if we are using cygwin."""
|
||||
if sys.platform == 'cygwin':
|
||||
p = subprocess.Popen(['cygpath', path], stdout=subprocess.PIPE)
|
||||
path = p.communicate()[0].strip()
|
||||
return path
|
||||
|
||||
|
||||
def _RegistryQueryBase(sysdir, key, value):
|
||||
"""Use reg.exe to read a particular key.
|
||||
|
||||
While ideally we might use the win32 module, we would like gyp to be
|
||||
python neutral, so for instance cygwin python lacks this module.
|
||||
|
||||
Arguments:
|
||||
sysdir: The system subdirectory to attempt to launch reg.exe from.
|
||||
key: The registry key to read from.
|
||||
value: The particular value to read.
|
||||
Return:
|
||||
stdout from reg.exe, or None for failure.
|
||||
"""
|
||||
# Setup params to pass to and attempt to launch reg.exe
|
||||
cmd = [os.path.join(os.environ.get('WINDIR', ''), sysdir, 'reg.exe'),
|
||||
'query', key]
|
||||
if value:
|
||||
cmd.extend(['/v', value])
|
||||
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
# Obtain the stdout from reg.exe, reading to the end so p.returncode is valid
|
||||
# Note that the error text may be in [1] in some cases
|
||||
text = p.communicate()[0]
|
||||
# Check return code from reg.exe; officially 0==success and 1==error
|
||||
if p.returncode:
|
||||
return None
|
||||
return text
|
||||
|
||||
|
||||
def _RegistryQuery(key, value=None):
|
||||
"""Use reg.exe to read a particular key through _RegistryQueryBase.
|
||||
|
||||
First tries to launch from %WinDir%\Sysnative to avoid WoW64 redirection. If
|
||||
that fails, it falls back to System32. Sysnative is available on Vista and
|
||||
up and available on Windows Server 2003 and XP through KB patch 942589. Note
|
||||
that Sysnative will always fail if using 64-bit python due to it being a
|
||||
virtual directory and System32 will work correctly in the first place.
|
||||
|
||||
KB 942589 - http://support.microsoft.com/kb/942589/en-us.
|
||||
|
||||
Arguments:
|
||||
key: The registry key.
|
||||
value: The particular registry value to read (optional).
|
||||
Return:
|
||||
stdout from reg.exe, or None for failure.
|
||||
"""
|
||||
text = None
|
||||
try:
|
||||
text = _RegistryQueryBase('Sysnative', key, value)
|
||||
except OSError, e:
|
||||
if e.errno == errno.ENOENT:
|
||||
text = _RegistryQueryBase('System32', key, value)
|
||||
else:
|
||||
raise
|
||||
return text
|
||||
|
||||
|
||||
def _RegistryGetValue(key, value):
|
||||
"""Use reg.exe to obtain the value of a registry key.
|
||||
|
||||
Args:
|
||||
key: The registry key.
|
||||
value: The particular registry value to read.
|
||||
Return:
|
||||
contents of the registry key's value, or None on failure.
|
||||
"""
|
||||
text = _RegistryQuery(key, value)
|
||||
if not text:
|
||||
return None
|
||||
# Extract value.
|
||||
match = re.search(r'REG_\w+\s+([^\r]+)\r\n', text)
|
||||
if not match:
|
||||
return None
|
||||
return match.group(1)
|
||||
|
||||
|
||||
def _DetectVisualStudioVersion(versions_to_check, force_express):
|
||||
"""Gets the path of the preferred Visual Studio version.
|
||||
|
||||
Returns:
|
||||
The base path of Visual Studio based on the registry and a quick check if
|
||||
devenv.exe exists.
|
||||
|
||||
Possibilities are:
|
||||
2010(e) - Visual Studio 2010 (10)
|
||||
2012(e) - Visual Studio 2012 (11)
|
||||
2013(e) - Visual Studio 2013 (12)
|
||||
Where (e) is e for express editions of MSVS and blank otherwise.
|
||||
"""
|
||||
versions = []
|
||||
for version in versions_to_check:
|
||||
# Old method of searching for which VS version is installed
|
||||
# We don't use the 2010-encouraged-way because we also want to get the
|
||||
# path to the binaries, which it doesn't offer.
|
||||
keys = [r'HKLM\Software\Microsoft\VisualStudio\%s' % version,
|
||||
r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\%s' % version,
|
||||
r'HKLM\Software\Microsoft\VCExpress\%s' % version,
|
||||
r'HKLM\Software\Wow6432Node\Microsoft\VCExpress\%s' % version]
|
||||
for index in range(len(keys)):
|
||||
path = _RegistryGetValue(keys[index], 'InstallDir')
|
||||
if not path:
|
||||
continue
|
||||
path = _ConvertToCygpath(path)
|
||||
# Check for full.
|
||||
full_path = os.path.join(path, 'devenv.exe')
|
||||
express_path = os.path.join(path, '*express.exe')
|
||||
if not force_express and os.path.exists(full_path):
|
||||
return os.path.normpath(os.path.join(path, '..', '..'))
|
||||
# Check for express.
|
||||
elif glob.glob(express_path):
|
||||
return os.path.normpath(os.path.join(path, '..', '..'))
|
||||
|
||||
# The old method above does not work when only SDK is installed.
|
||||
keys = [r'HKLM\Software\Microsoft\VisualStudio\SxS\VC7',
|
||||
r'HKLM\Software\Wow6432Node\Microsoft\VisualStudio\SxS\VC7']
|
||||
for index in range(len(keys)):
|
||||
path = _RegistryGetValue(keys[index], version)
|
||||
if not path:
|
||||
continue
|
||||
path = _ConvertToCygpath(path)
|
||||
return os.path.normpath(os.path.join(path, '..'))
|
||||
|
||||
return None
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print 'Usage: get_visual_studio_path.py <version>'
|
||||
print 'Use "auto" for the version to autodetect.'
|
||||
sys.exit(2)
|
||||
version_map = {
|
||||
'auto': ('10.0', '12.0', '11.0'),
|
||||
'2010': ('10.0',),
|
||||
'2010e': ('10.0',),
|
||||
'2012': ('11.0',),
|
||||
'2012e': ('11.0',),
|
||||
'2013': ('12.0',),
|
||||
'2013e': ('12.0',),
|
||||
}
|
||||
|
||||
requested_version = sys.argv[1]
|
||||
vs_path = _DetectVisualStudioVersion(version_map[requested_version],
|
||||
'e' in requested_version)
|
||||
if not vs_path:
|
||||
# No Visual Studio version detected.
|
||||
print '""' # Return empty string to .gn file.
|
||||
sys.exit(1);
|
||||
|
||||
# Return Visual Studio path to the .gn file.
|
||||
print '"%s"' % vs_path
|
|
@ -0,0 +1,36 @@
|
|||
# Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
declare_args() {
|
||||
# Version of Visual Studio to use.
|
||||
#
|
||||
# Possible values:
|
||||
# - "auto"
|
||||
# - "2010"
|
||||
# - "2010e"
|
||||
# - "2012"
|
||||
# - "2012e"
|
||||
# - "2013"
|
||||
# - "2013e"
|
||||
#
|
||||
# The "e" variants denote "Express". The default, "auto" will find the
|
||||
# preferred one of all Visual Studios installed on the current system.
|
||||
visual_studio_version = "auto"
|
||||
|
||||
# The path to use as the root of a Visual Studio install. If nonempty,
|
||||
# this path will be used instead of any autodetected install locations,
|
||||
# which allows you to have the Visual Studio files in a directory without
|
||||
# actually "installing" it.
|
||||
#
|
||||
# When empty, we will autodetect the best Visual Studio path to use. The
|
||||
# autodetected one is usually something like
|
||||
# "C:\Program Files (x86)\Microsoft Visual Studio 10.0".
|
||||
visual_studio_path = ""
|
||||
}
|
||||
|
||||
if (visual_studio_path == "") {
|
||||
visual_studio_path = exec_script("get_visual_studio_path.py",
|
||||
[ visual_studio_version ], "value")
|
||||
}
|
||||
|
|
@ -177,6 +177,15 @@ def GetArgsStringForGN(supplemental_files):
|
|||
if v in vars_dict:
|
||||
gn_args += ' ' + v + '=' + EscapeStringForGN(vars_dict[v])
|
||||
|
||||
# Some other flags come from GYP environment variables.
|
||||
gyp_msvs_version = os.environ.get('GYP_MSVS_VERSION', '')
|
||||
if gyp_msvs_version:
|
||||
gn_args += ' visual_studio_version=' + EscapeStringForGN(gyp_msvs_version)
|
||||
gyp_msvs_override_path = os.environ.get('GYP_MSVS_OVERRIDE_PATH', '')
|
||||
if gyp_msvs_override_path:
|
||||
gn_args += ' visual_studio_override_path=' + \
|
||||
EscapeStringForGN(gyp_msvs_override_path)
|
||||
|
||||
# Set the GYP flag so BUILD files know they're being invoked in GYP mode.
|
||||
gn_args += ' is_gyp=true'
|
||||
return gn_args.strip()
|
||||
|
|
|
@ -7,23 +7,17 @@ import("//build/toolchain/goma.gni")
|
|||
# Should only be running on Windows.
|
||||
assert(is_win)
|
||||
|
||||
import("//build/config/win/visual_studio_version.gni")
|
||||
|
||||
# Setup the Visual Studio state.
|
||||
#
|
||||
# Its argument is the location to write the environment files.
|
||||
# It will write "environment.x86" and "environment.x64" to this directory,
|
||||
# and return a list to us.
|
||||
#
|
||||
# The list contains the include path as its only element. (I'm expecting to
|
||||
# add more so it's currently a list inside a list.)
|
||||
#exec_script("get_msvc_config.py",
|
||||
# [relative_root_output_dir],
|
||||
# "value")
|
||||
|
||||
# This will save the environment block and and copy the gyp-win-tool to the
|
||||
# build directory. We pass in the source file of the win tool.
|
||||
gyp_win_tool_source =
|
||||
rebase_path("//tools/gyp/pylib/gyp/win_tool.py", ".", root_build_dir)
|
||||
exec_script("setup_toolchain.py", [ gyp_win_tool_source ], "value")
|
||||
# Its arguments are the VS path and the compiler wrapper tool. It will write
|
||||
# "environment.x86" and "environment.x64" to the build directory and return a
|
||||
# list to us.
|
||||
gyp_win_tool_path = rebase_path("//tools/gyp/pylib/gyp/win_tool.py", ".",
|
||||
root_build_dir)
|
||||
exec_script("setup_toolchain.py", [ visual_studio_path, gyp_win_tool_path ],
|
||||
"string")
|
||||
|
||||
stamp_command = "$python_path gyp-win-tool stamp \$out"
|
||||
copy_command = "$python_path gyp-win-tool recursive-mirror \$in \$out"
|
||||
|
|
|
@ -2,10 +2,23 @@
|
|||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
import errno
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
"""
|
||||
Copies the given "win tool" (which the toolchain uses to wrap compiler
|
||||
invocations) and the environment blocks for the 32-bit and 64-bit builds on
|
||||
Windows to the build directory.
|
||||
|
||||
The arguments are the visual studio install location and the location of the
|
||||
win tool. The script assumes that the root build directory is the current dir
|
||||
and the files will be written to the current directory.
|
||||
"""
|
||||
|
||||
|
||||
def ExtractImportantEnvironment():
|
||||
"""Extracts environment variables required for the toolchain from the
|
||||
current environment."""
|
||||
|
@ -36,48 +49,6 @@ def ExtractImportantEnvironment():
|
|||
return result
|
||||
|
||||
|
||||
# VC setup will add a path like this in 32-bit mode:
|
||||
# c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\BIN
|
||||
# And this in 64-bit mode:
|
||||
# c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\BIN\amd64
|
||||
# Note that in 64-bit it's duplicated but the 64-bit one comes first.
|
||||
#
|
||||
# What we get as the path when running this will depend on which VS setup
|
||||
# script you've run. The following two functions try to do this.
|
||||
|
||||
# For 32-bit compiles remove anything that ends in "\VC\WIN\amd64".
|
||||
def FixupPath32(path):
|
||||
find_64 = re.compile("VC\\\\BIN\\\\amd64\\\\*$", flags=re.IGNORECASE)
|
||||
|
||||
for i in range(len(path)):
|
||||
if find_64.search(path[i]):
|
||||
# Found 32-bit path, insert the 64-bit one immediately before it.
|
||||
dir_64 = path[i].rstrip("\\")
|
||||
dir_64 = dir_64[:len(dir_64) - 6] # Trim off "\amd64".
|
||||
path[i] = dir_64
|
||||
break
|
||||
return path
|
||||
|
||||
# For 64-bit compiles, append anything ending in "\VC\BIN" with "\amd64" as
|
||||
# long as that thing isn't already in the list, and append it immediately
|
||||
# before the non-amd64-one.
|
||||
def FixupPath64(path):
|
||||
find_32 = re.compile("VC\\\\BIN\\\\*$", flags=re.IGNORECASE)
|
||||
|
||||
for i in range(len(path)):
|
||||
if find_32.search(path[i]):
|
||||
# Found 32-bit path, insert the 64-bit one immediately before it.
|
||||
dir_32 = path[i]
|
||||
if dir_32[len(dir_32) - 1] == '\\':
|
||||
dir_64 = dir_32 + "amd64"
|
||||
else:
|
||||
dir_64 = dir_32 + "\\amd64"
|
||||
path.insert(i, dir_64)
|
||||
break
|
||||
|
||||
return path
|
||||
|
||||
|
||||
def FormatAsEnvironmentBlock(envvar_dict):
|
||||
"""Format as an 'environment block' directly suitable for CreateProcess.
|
||||
Briefly this is a list of key=value\0, terminated by an additional \0. See
|
||||
|
@ -89,6 +60,7 @@ def FormatAsEnvironmentBlock(envvar_dict):
|
|||
block += nul
|
||||
return block
|
||||
|
||||
|
||||
def CopyTool(source_path):
|
||||
"""Copies the given tool to the current directory, including a warning not
|
||||
to edit it."""
|
||||
|
@ -102,22 +74,27 @@ def CopyTool(source_path):
|
|||
'# Generated by setup_toolchain.py do not edit.\n']
|
||||
+ tool_source[1:]))
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
print 'Usage setup_toolchain.py <visual studio path> <win tool path>'
|
||||
sys.exit(2)
|
||||
vs_path = sys.argv[1]
|
||||
tool_source = sys.argv[2]
|
||||
|
||||
# Find the tool source, it's the first argument, and copy it.
|
||||
if len(sys.argv) != 2:
|
||||
print "Need one argument (win_tool source path)."
|
||||
sys.exit(1)
|
||||
CopyTool(sys.argv[1])
|
||||
CopyTool(tool_source)
|
||||
|
||||
important_env_vars = ExtractImportantEnvironment()
|
||||
path = important_env_vars["PATH"].split(";")
|
||||
|
||||
important_env_vars["PATH"] = ";".join(FixupPath32(path))
|
||||
# Add 32-bit compiler path to the beginning and write the block.
|
||||
path32 = [os.path.join(vs_path, "VC\\BIN")] + path
|
||||
important_env_vars["PATH"] = ";".join(path32)
|
||||
environ = FormatAsEnvironmentBlock(important_env_vars)
|
||||
with open('environment.x86', 'wb') as env_file:
|
||||
env_file.write(environ)
|
||||
|
||||
important_env_vars["PATH"] = ";".join(FixupPath64(path))
|
||||
# Add 64-bit compiler path to the beginning and write the block.
|
||||
path64 = [os.path.join(vs_path, "VC\\BIN\\amd64")] + path
|
||||
important_env_vars["PATH"] = ";".join(path64)
|
||||
environ = FormatAsEnvironmentBlock(important_env_vars)
|
||||
with open('environment.x64', 'wb') as env_file:
|
||||
env_file.write(environ)
|
||||
|
|
Загрузка…
Ссылка в новой задаче