Rework win_toolchains a bit and copy the vs runtime DLLs as needed.

In order to run both the visual studio tools and the binaries built
by them (and ninja), we need to ensure that the VS runtime DLLs
are available in the path.

In the GYP build, we accomplish this by copying them into the
Debug and Debug_x64 dirs as appropriate inside the gyp_chromium
script.

In the pure-GN build, then, things would be broken, so we need to
modify the GN build to do the copy as well, or we need to inject
a step somewhere that happens after GN runs but before Ninja tries
to run (since none of the toolchain binaries will work).

This patch accomplishes this by calling out to vs_toolchain.py to
copy the DLLs as neede when the toolchain is defined. This is somewhat
less than ideal (makes 'gn gen' slower) but seems better than forcing
devs to have to run an additional command.

In addition, the GYP build writes targets into Debug and Debug_x64
concurrently. This doesn't really carry over into GN correctly, and
we probably only ever want to write targets into Debug and Debug/64
(or some such).

However, the way the toolchains are currently implemented, it's not
clear if this really works and the interplay between 32-bit and 64-bit
is weird (we apparently normally "force" 32-bit even if we set cpu_arch
to 64-bit, and require you to specify force_win64). To work around this
and make sure that we copy the right DLLs for the right arch into the
outer Debug/ directory, this patch temporarily disables the cross-arch
part of the build, forcing the host_toolchain to match the target_toolchain.

This likely means that 'cpu_arch="x86"' works (the default), but the 'host'
binaries like image_diff and mksnapshot will be compiled in 32-bit mode,
not 64-bit mode. 'cpu_arch="x64" force_win64=true' should also work, and
produce all-64-bit binaries. 'cpu_arch="x64"' does not work at all and
won't until we can clean up the above stuff.

R=scottmg@chromium.org, brettw@chromium.org
BUG=430661

Review URL: https://codereview.chromium.org/722723004

Cr-Original-Commit-Position: refs/heads/master@{#304310}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 0b95195e49489b7a4d87048d2ce4b747173a5b8a
This commit is contained in:
dpranke 2014-11-14 16:09:14 -08:00 коммит произвёл Commit bot
Родитель 34a19a3ac9
Коммит 7265358749
3 изменённых файлов: 83 добавлений и 76 удалений

Просмотреть файл

@ -34,15 +34,6 @@ declare_args() {
# to configure warnings.
is_clang = (os == "mac" || os == "ios" || os == "linux" || os == "chromeos")
# Forces a 64-bit build on Windows. Does nothing on other platforms. Normally
# we build 32-bit on Windows regardless of the current host OS bit depth.
# Setting this flag will override this logic and generate 64-bit toolchains.
#
# Normally this would get set automatically when you specify a target using
# the 64-bit toolchain. You can also set this on the command line to convert
# the default toolchain to 64-bit.
force_win64 = false
# Selects the desired build flavor. Official builds get additional
# processing to prepare for release. Normally you will want to develop and
# test with this flag off.
@ -174,16 +165,6 @@ is_desktop_linux = is_linux && !is_chromeos
# CPU ARCHITECTURE
# =============================================================================
if (is_win) {
# Always use 32-bit on Windows, even when compiling on a 64-bit host OS,
# unless the override flag is specified.
if (force_win64) {
cpu_arch = "x64"
} else {
cpu_arch = "x86"
}
}
if (is_android) {
# TODO(cjhopman): enable this assert once bots are updated to not set
# cpu_arch.
@ -495,19 +476,14 @@ set_defaults("test") {
# default toolchain.
if (is_win) {
# TODO(brettw) name the toolchains the same as cpu_arch as with Linux below
# to eliminate these conditionals.
if (build_cpu_arch == "x64") {
# On windows we use the same toolchain for host and target by default.
# TODO(dpranke): rename the toolchains to x64 and x86 to match cpu_arch.
if (cpu_arch == "x64") {
host_toolchain = "//build/toolchain/win:64"
} else if (build_cpu_arch == "x86") {
} else if (cpu_arch == "x86") {
host_toolchain = "//build/toolchain/win:32"
}
if (cpu_arch == "x64") {
set_default_toolchain("//build/toolchain/win:64")
} else if (cpu_arch == "x86") {
set_default_toolchain("//build/toolchain/win:32")
}
set_default_toolchain("$host_toolchain")
} else if (is_android) {
# Use clang for the x86/64 Linux host builds.
if (build_cpu_arch == "x86" || build_cpu_arch == "x64") {

Просмотреть файл

@ -24,7 +24,6 @@ concurrent_links = exec_script("../get_concurrent_links.py", [], "value")
# Parameters:
# cpu_arch: cpu_arch to pass as a build arg
# environment: File name of environment file.
# force_win64 (optional): value for this build arg.
template("msvc_toolchain") {
if (defined(invoker.concurrent_links)) {
concurrent_links = invoker.concurrent_links
@ -32,6 +31,16 @@ template("msvc_toolchain") {
env = invoker.environment
if (is_debug) {
configuration = "Debug"
} else {
configuration = "Release"
}
exec_script("../../vs_toolchain.py", ["copy_dlls",
rebase_path(root_build_dir),
configuration,
invoker.cpu_arch])
toolchain(target_name) {
# Make these apply to all tools below.
lib_switch = ""
@ -154,23 +163,24 @@ template("msvc_toolchain") {
# passed to the build. They are ignored when this is the default toolchain.
toolchain_args() {
cpu_arch = invoker.cpu_arch
# Normally the build config resets the CPU architecture to 32-bits. Setting
# this flag overrides that behavior.
if (defined(invoker.force_win64)) {
force_win64 = invoker.force_win64
}
}
}
}
msvc_toolchain("32") {
environment = "environment.x86"
cpu_arch = "x64"
# TODO(dpranke): Declare both toolchains all of the time when we
# get it sorted out how we want to support them both in a single build.
# Right now only one of these can be enabled at a time because the
# runtime libraries get copied to root_build_dir and would collide.
if (cpu_arch == "x86") {
msvc_toolchain("32") {
environment = "environment.x86"
cpu_arch = "x86"
}
}
msvc_toolchain("64") {
environment = "environment.x64"
cpu_arch = "x64"
force_win64 = true
if (cpu_arch == "x64") {
msvc_toolchain("64") {
environment = "environment.x64"
cpu_arch = "x64"
}
}

Просмотреть файл

@ -63,6 +63,29 @@ def SetEnvironmentAndGetRuntimeDllDirs():
return vs2013_runtime_dll_dirs
def _CopyRuntimeImpl(target, source):
"""Copy |source| to |target| if it doesn't already exist or if it
needs to be updated.
"""
if (os.path.isdir(os.path.dirname(target)) and
(not os.path.isfile(target) or
os.stat(target).st_mtime != os.stat(source).st_mtime)):
print 'Copying %s to %s...' % (source, target)
if os.path.exists(target):
os.unlink(target)
shutil.copy2(source, target)
def _CopyRuntime(target_dir, source_dir, dll_pattern):
"""Copy both the msvcr and msvcp runtime DLLs, only if the target doesn't
exist, but the target directory does exist."""
for which in ('p', 'r'):
dll = dll_pattern % which
target = os.path.join(target_dir, dll)
source = os.path.join(source_dir, dll)
_CopyRuntimeImpl(target, source)
def CopyVsRuntimeDlls(output_dir, runtime_dirs):
"""Copies the VS runtime DLLs from the given |runtime_dirs| to the output
directory so that even if not system-installed, built binaries are likely to
@ -73,27 +96,6 @@ def CopyVsRuntimeDlls(output_dir, runtime_dirs):
"""
assert sys.platform.startswith(('win32', 'cygwin'))
def copy_runtime_impl(target, source):
"""Copy |source| to |target| if it doesn't already exist or if it need to be
updated.
"""
if (os.path.isdir(os.path.dirname(target)) and
(not os.path.isfile(target) or
os.stat(target).st_mtime != os.stat(source).st_mtime)):
print 'Copying %s to %s...' % (source, target)
if os.path.exists(target):
os.unlink(target)
shutil.copy2(source, target)
def copy_runtime(target_dir, source_dir, dll_pattern):
"""Copy both the msvcr and msvcp runtime DLLs, only if the target doesn't
exist, but the target directory does exist."""
for which in ('p', 'r'):
dll = dll_pattern % which
target = os.path.join(target_dir, dll)
source = os.path.join(source_dir, dll)
copy_runtime_impl(target, source)
x86, x64 = runtime_dirs
out_debug = os.path.join(output_dir, 'Debug')
out_debug_nacl64 = os.path.join(output_dir, 'Debug', 'x64')
@ -106,12 +108,12 @@ def CopyVsRuntimeDlls(output_dir, runtime_dirs):
os.makedirs(out_debug_nacl64)
if os.path.exists(out_release) and not os.path.exists(out_release_nacl64):
os.makedirs(out_release_nacl64)
copy_runtime(out_debug, x86, 'msvc%s120d.dll')
copy_runtime(out_release, x86, 'msvc%s120.dll')
copy_runtime(out_debug_x64, x64, 'msvc%s120d.dll')
copy_runtime(out_release_x64, x64, 'msvc%s120.dll')
copy_runtime(out_debug_nacl64, x64, 'msvc%s120d.dll')
copy_runtime(out_release_nacl64, x64, 'msvc%s120.dll')
_CopyRuntime(out_debug, x86, 'msvc%s120d.dll')
_CopyRuntime(out_release, x86, 'msvc%s120.dll')
_CopyRuntime(out_debug_x64, x64, 'msvc%s120d.dll')
_CopyRuntime(out_release_x64, x64, 'msvc%s120.dll')
_CopyRuntime(out_debug_nacl64, x64, 'msvc%s120d.dll')
_CopyRuntime(out_release_nacl64, x64, 'msvc%s120.dll')
# Copy the PGO runtime library to the release directories.
if os.environ.get('GYP_MSVS_OVERRIDE_PATH'):
@ -121,11 +123,31 @@ def CopyVsRuntimeDlls(output_dir, runtime_dirs):
pgo_runtime_dll = 'pgort120.dll'
source_x86 = os.path.join(pgo_x86_runtime_dir, pgo_runtime_dll)
if os.path.exists(source_x86):
copy_runtime_impl(os.path.join(out_release, pgo_runtime_dll), source_x86)
_CopyRuntimeImpl(os.path.join(out_release, pgo_runtime_dll), source_x86)
source_x64 = os.path.join(pgo_x64_runtime_dir, pgo_runtime_dll)
if os.path.exists(source_x64):
copy_runtime_impl(os.path.join(out_release_x64, pgo_runtime_dll),
source_x64)
_CopyRuntimeImpl(os.path.join(out_release_x64, pgo_runtime_dll),
source_x64)
def CopyDlls(target_dir, configuration, cpu_arch):
"""Copy the VS runtime DLLs into the requested directory as needed.
configuration is one of 'Debug' or 'Release'.
cpu_arch is one of 'x86' or 'x64'.
The debug configuration gets both the debug and release DLLs; the
release config only the latter.
"""
vs2013_runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs()
if not vs2013_runtime_dll_dirs:
return
x64_runtime, x86_runtime = vs2013_runtime_dll_dirs
runtime_dir = x64_runtime if cpu_arch == 'x64' else x86_runtime
_CopyRuntime(target_dir, runtime_dir, 'msvc%s120.dll')
if configuration == 'Debug':
_CopyRuntime(target_dir, runtime_dir, 'msvc%s120d.dll')
def _GetDesiredVsToolchainHashes():
@ -188,13 +210,12 @@ def main():
commands = {
'update': Update,
'get_toolchain_dir': GetToolchainDir,
# TODO(scottmg): Add copy_dlls for GN builds (gyp_chromium calls
# CopyVsRuntimeDlls via import, currently).
'copy_dlls': CopyDlls,
}
if len(sys.argv) < 2 or sys.argv[1] not in commands:
print >>sys.stderr, 'Expected one of: %s' % ', '.join(commands)
return 1
return commands[sys.argv[1]]()
return commands[sys.argv[1]](*sys.argv[2:])
if __name__ == '__main__':