diff options
Diffstat (limited to 'chromium/build/toolchain')
-rw-r--r-- | chromium/build/toolchain/android/BUILD.gn | 3 | ||||
-rwxr-xr-x | chromium/build/toolchain/clang_static_analyzer_wrapper.py | 106 | ||||
-rwxr-xr-x | chromium/build/toolchain/gcc_link_wrapper.py | 10 | ||||
-rwxr-xr-x | chromium/build/toolchain/gcc_solink_wrapper.py | 10 | ||||
-rw-r--r-- | chromium/build/toolchain/gcc_toolchain.gni | 122 | ||||
-rw-r--r-- | chromium/build/toolchain/linux/BUILD.gn | 12 | ||||
-rw-r--r-- | chromium/build/toolchain/nacl/BUILD.gn | 11 | ||||
-rw-r--r-- | chromium/build/toolchain/nacl_toolchain.gni | 1 | ||||
-rw-r--r-- | chromium/build/toolchain/win/BUILD.gn | 9 | ||||
-rw-r--r-- | chromium/build/toolchain/win/setup_toolchain.py | 10 | ||||
-rw-r--r-- | chromium/build/toolchain/win/tool_wrapper.py | 10 | ||||
-rw-r--r-- | chromium/build/toolchain/wrapper_utils.py | 46 |
12 files changed, 252 insertions, 98 deletions
diff --git a/chromium/build/toolchain/android/BUILD.gn b/chromium/build/toolchain/android/BUILD.gn index ad7b76278aa..9b3b162ca6d 100644 --- a/chromium/build/toolchain/android/BUILD.gn +++ b/chromium/build/toolchain/android/BUILD.gn @@ -25,6 +25,9 @@ template("android_gcc_toolchain") { toolchain_args = invoker.toolchain_args toolchain_args.current_os = "android" + # Output linker map files for binary size analysis. + enable_linker_map = true + # Make our manually injected libs relative to the build dir. _ndk_lib = rebase_path(invoker.sysroot + "/" + invoker.lib_dir, root_build_dir) diff --git a/chromium/build/toolchain/clang_static_analyzer_wrapper.py b/chromium/build/toolchain/clang_static_analyzer_wrapper.py index cc13888f3c2..0ae62dabf7b 100755 --- a/chromium/build/toolchain/clang_static_analyzer_wrapper.py +++ b/chromium/build/toolchain/clang_static_analyzer_wrapper.py @@ -1,61 +1,77 @@ #!/usr/bin/env python -# Copyright 2016 The Chromium Authors. All rights reserved. +# Copyright 2017 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. -"""Invokes the Clang static analysis command using arguments provided on the -command line. +"""Adds an analysis build step to invocations of the Clang C/C++ compiler. + +Usage: clang_static_analyzer_wrapper.py <compiler> [args...] """ import argparse import fnmatch +import itertools import os -import shutil import sys -import tempfile - import wrapper_utils +# Flags used to enable analysis for Clang invocations. +analyzer_enable_flags = [ + '--analyze', +] + +# Flags used to configure the analyzer's behavior. +analyzer_option_flags = [ + '-fdiagnostics-show-option', + '-analyzer-checker=cplusplus', + '-analyzer-opt-analyze-nested-blocks', + '-analyzer-eagerly-assume', + '-analyzer-output=text', + '-analyzer-config', + 'suppress-c++-stdlib=true', + +# List of checkers to execute. +# The full list of checkers can be found at +# https://clang-analyzer.llvm.org/available_checks.html. + '-analyzer-checker=core', + '-analyzer-checker=unix', + '-analyzer-checker=deadcode', +] + + +# Prepends every element of a list |args| with |token|. +# e.g. ['-analyzer-foo', '-analyzer-bar'] => ['-Xanalyzer', '-analyzer-foo', +# '-Xanalyzer', '-analyzer-bar'] +def interleave_args(args, token): + return list(sum(zip([token] * len(args), args), ())) + def main(): - parser = argparse.ArgumentParser(description=__doc__) - parser.add_argument('--clang-cc-path', - help='Path to the clang compiler.', - metavar='PATH') - parser.add_argument('--clang-cxx-path', - help='Path to the clang++ compiler', - metavar='PATH') - parser.add_argument('--analyzer', - help='Path to the language-specific Clang analysis tool.', + parser = argparse.ArgumentParser() + parser.add_argument('--mode', + choices=['clang', 'cl'], required=True, - metavar='PATH') - args, compile_args = parser.parse_known_args() - - # Check that only one of --clang-cc-path or --clang-cxx-path are set. - assert ((args.clang_cc_path != None) != (args.clang_cxx_path != None)) - - is_cxx = args.clang_cxx_path != None - env = os.environ - env['CCC_ANALYZER_FORCE_ANALYZE_DEBUG_CODE'] = '0' - env['CCC_ANALYZER_OUTPUT_FORMAT'] = 'text' - clang_path = args.clang_cxx_path or args.clang_cc_path - if is_cxx: - env['CCC_CXX'] = clang_path - env['CLANG_CXX'] = clang_path - else: - env['CCC_CC'] = clang_path - env['CLANG'] = clang_path - - # TODO(kmarshall): Place the summarized output in a useful directory. - temp_dir = tempfile.mkdtemp() - try: - env['CCC_ANALYZER_HTML'] = temp_dir - returncode, stderr = wrapper_utils.CaptureCommandStderr( - wrapper_utils.CommandToRun([args.analyzer] + compile_args), env) - sys.stderr.write(stderr) - return returncode - finally: - shutil.rmtree(temp_dir) - -if __name__ == "__main__": + help='Specifies the compiler argument convention to use.') + parser.add_argument('args', nargs=argparse.REMAINDER) + parsed_args = parser.parse_args() + + prefix = '-Xclang' if parsed_args.mode == 'cl' else '-Xanalyzer' + cmd = parsed_args.args + analyzer_enable_flags + \ + interleave_args(analyzer_option_flags, prefix) + returncode, stderr = wrapper_utils.CaptureCommandStderr( + wrapper_utils.CommandToRun(cmd)) + sys.stderr.write(stderr) + if returncode != 0: + sys.stderr.write( + """WARNING! The Clang static analyzer exited with error code %d. + Please share the error details in crbug.com/695243 if this looks like + a new regression.\n""" % (returncode)) + + returncode, stderr = wrapper_utils.CaptureCommandStderr( + wrapper_utils.CommandToRun(parsed_args.args)) + sys.stderr.write(stderr) + + return returncode + +if __name__ == '__main__': sys.exit(main()) diff --git a/chromium/build/toolchain/gcc_link_wrapper.py b/chromium/build/toolchain/gcc_link_wrapper.py index c589fe330d4..0e256fab2fb 100755 --- a/chromium/build/toolchain/gcc_link_wrapper.py +++ b/chromium/build/toolchain/gcc_link_wrapper.py @@ -15,6 +15,8 @@ import os import subprocess import sys +import wrapper_utils + # When running on a Windows host and using a toolchain whose tools are # actually wrapper scripts (i.e. .bat files on Windows) rather than binary @@ -37,9 +39,12 @@ def main(): help='The strip binary to run', metavar='PATH') parser.add_argument('--unstripped-file', - required=True, help='Executable file produced by linking command', metavar='FILE') + parser.add_argument('--map-file', + help=('Use --Wl,-Map to generate a map file. Will be ' + 'gzipped if extension ends with .gz'), + metavar='FILE') parser.add_argument('--output', required=True, help='Final output executable file', @@ -51,7 +56,8 @@ def main(): # Work-around for gold being slow-by-default. http://crbug.com/632230 fast_env = dict(os.environ) fast_env['LC_ALL'] = 'C' - result = subprocess.call(CommandToRun(args.command), env=fast_env) + result = wrapper_utils.RunLinkWithOptionalMapFile(args.command, env=fast_env, + map_file=args.map_file) if result != 0: return result diff --git a/chromium/build/toolchain/gcc_solink_wrapper.py b/chromium/build/toolchain/gcc_solink_wrapper.py index 426f9d66332..7efc4906e13 100755 --- a/chromium/build/toolchain/gcc_solink_wrapper.py +++ b/chromium/build/toolchain/gcc_solink_wrapper.py @@ -78,6 +78,10 @@ def main(): required=True, help='Output table-of-contents file', metavar='FILE') + parser.add_argument('--map-file', + help=('Use --Wl,-Map to generate a map file. Will be ' + 'gzipped if extension ends with .gz'), + metavar='FILE') parser.add_argument('--output', required=True, help='Final output shared object file', @@ -99,8 +103,10 @@ def main(): whitelist_candidates, args.resource_whitelist) # First, run the actual link. - result = subprocess.call( - wrapper_utils.CommandToRun(args.command), env=fast_env) + command = wrapper_utils.CommandToRun(args.command) + result = wrapper_utils.RunLinkWithOptionalMapFile(command, env=fast_env, + map_file=args.map_file) + if result != 0: return result diff --git a/chromium/build/toolchain/gcc_toolchain.gni b/chromium/build/toolchain/gcc_toolchain.gni index b31980668d8..dfd187954cd 100644 --- a/chromium/build/toolchain/gcc_toolchain.gni +++ b/chromium/build/toolchain/gcc_toolchain.gni @@ -12,6 +12,13 @@ import("//build/toolchain/clang_static_analyzer.gni") import("//build/toolchain/goma.gni") import("//build/toolchain/toolchain.gni") +# Path to the Clang static analysis wrapper script. +# REVIEWERS: can you suggest a better location for this? +# GN is really picky about dead stores of variables except at the global scope. +analyzer_wrapper = + rebase_path("//build/toolchain/clang_static_analyzer_wrapper.py", + root_build_dir) + " --mode=clang" + # This template defines a toolchain for something that works like gcc # (including clang). # @@ -126,22 +133,49 @@ template("gcc_toolchain") { } else { toolchain_cc_wrapper = cc_wrapper } + assert(!(toolchain_cc_wrapper != "" && toolchain_uses_goma), + "Goma and cc_wrapper can't be used together.") - # Compute the compiler prefix. + # When the invoker has explicitly overridden use_goma or cc_wrapper in the + # toolchain args, use those values, otherwise default to the global one. + # This works because the only reasonable override that toolchains might + # supply for these values are to force-disable them. if (toolchain_uses_goma) { - assert(toolchain_cc_wrapper == "", - "Goma and cc_wrapper can't be used together.") - compiler_prefix = "$goma_dir/gomacc " - } else if (toolchain_cc_wrapper != "") { - compiler_prefix = toolchain_cc_wrapper + " " + goma_path = "$goma_dir/gomacc" + + # Use the static analysis script if static analysis is turned on + # AND the tool has not opted out by setting + # 'is_clang_static_analysis_supported' to false. + if (is_clang && use_clang_static_analyzer && + (!defined(invoker.is_clang_analysis_supported) || + invoker.is_clang_analysis_supported)) { + compiler_prefix = "${analyzer_wrapper} ${goma_path} " + + # Create a distinct variable for "asm", since analysis runs pass + # a bunch of flags to clang/clang++ that are nonsensical on assembler + # runs. + asm = "${goma_path} ${invoker.cc}" + } else { + compiler_prefix = "${goma_path} " + } } else { - compiler_prefix = "" + if (is_clang && use_clang_static_analyzer && + (!defined(invoker.is_clang_analysis_supported) || + invoker.is_clang_analysis_supported)) { + compiler_prefix = "${analyzer_wrapper} " + asm = invoker.cc + } else { + compiler_prefix = "${toolchain_cc_wrapper} " + } } cc = compiler_prefix + invoker.cc cxx = compiler_prefix + invoker.cxx ar = invoker.ar ld = invoker.ld + if (!defined(asm)) { + asm = cc + } if (defined(invoker.readelf)) { readelf = invoker.readelf } else { @@ -214,6 +248,9 @@ template("gcc_toolchain") { extra_ldflags = "" } + enable_linker_map = + defined(invoker.enable_linker_map) && invoker.enable_linker_map + # These library switches can apply to all tools below. lib_switch = "-l" lib_dir_switch = "-L" @@ -260,7 +297,7 @@ template("gcc_toolchain") { tool("asm") { # For GCC we can just use the C compiler to compile assembly. depfile = "{{output}}.d" - command = "$cc -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}" + command = "$asm -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}" depsformat = "gcc" description = "ASM {{output}}" outputs = [ @@ -319,18 +356,27 @@ template("gcc_toolchain") { link_command = "$ld -shared {{ldflags}}${extra_ldflags} -o \"$unstripped_sofile\" -Wl,-soname=\"$soname\" @\"$rspfile\"" + # Generate a map file to be used for binary size analysis. + # Map file adds ~10% to the link time on a z620. + # With target_os="android", libchrome.so.map.gz is ~20MB. + map_switch = "" + if (enable_linker_map && is_official_build) { + map_file = "$unstripped_sofile.map.gz" + map_switch = " --map-file \"$map_file\"" + } + assert(defined(readelf), "to solink you must have a readelf") assert(defined(nm), "to solink you must have an nm") strip_switch = "" if (defined(invoker.strip)) { - strip_switch = "--strip=${invoker.strip}" + strip_switch = "--strip=${invoker.strip} " } # This needs a Python script to avoid using a complex shell command # requiring sh control structures, pipelines, and POSIX utilities. # The host might not have a POSIX shell and utilities (e.g. Windows). solink_wrapper = rebase_path("//build/toolchain/gcc_solink_wrapper.py") - command = "$python_path \"$solink_wrapper\" --readelf=\"$readelf\" --nm=\"$nm\" $strip_switch --sofile=\"$unstripped_sofile\" --tocfile=\"$tocfile\" --output=\"$sofile\"$whitelist_flag -- $link_command" + command = "$python_path \"$solink_wrapper\" --readelf=\"$readelf\" --nm=\"$nm\" $strip_switch--sofile=\"$unstripped_sofile\" --tocfile=\"$tocfile\"$map_switch --output=\"$sofile\"$whitelist_flag -- $link_command" rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive $solink_libs_section_prefix {{libs}} $solink_libs_section_postfix" @@ -365,6 +411,9 @@ template("gcc_toolchain") { if (sofile != unstripped_sofile) { outputs += [ unstripped_sofile ] } + if (defined(map_file)) { + outputs += [ map_file ] + } link_output = sofile depend_output = tocfile } @@ -433,12 +482,25 @@ template("gcc_toolchain") { unstripped_outfile = "{{root_out_dir}}/exe.unstripped/$exename" } - command = "$ld {{ldflags}}${extra_ldflags} -o \"$unstripped_outfile\" -Wl,--start-group @\"$rspfile\" {{solibs}} -Wl,--end-group $libs_section_prefix {{libs}} $libs_section_postfix" + # Generate a map file to be used for binary size analysis. + # Map file adds ~10% to the link time on a z620. + # With target_os="android", libchrome.so.map.gz is ~20MB. + map_switch = "" + if (enable_linker_map && is_official_build) { + map_file = "$unstripped_outfile.map.gz" + map_switch = " --map-file \"$map_file\"" + } + + link_command = "$ld {{ldflags}}${extra_ldflags} -o \"$unstripped_outfile\" -Wl,--start-group @\"$rspfile\" {{solibs}} -Wl,--end-group $libs_section_prefix {{libs}} $libs_section_postfix" + + strip_switch = "" if (defined(invoker.strip)) { - link_wrapper = - rebase_path("//build/toolchain/gcc_link_wrapper.py", root_build_dir) - command = "$python_path \"$link_wrapper\" --strip=\"${invoker.strip}\" --unstripped-file=\"$unstripped_outfile\" --output=\"$outfile\" -- $command" + strip_switch = " --strip=\"${invoker.strip}\" --unstripped-file=\"$unstripped_outfile\"" } + + link_wrapper = + rebase_path("//build/toolchain/gcc_link_wrapper.py", root_build_dir) + command = "$python_path \"$link_wrapper\" --output=\"$outfile\"$strip_switch$map_switch -- $link_command" description = "LINK $outfile" rspfile_content = "{{inputs}}" outputs = [ @@ -450,6 +512,9 @@ template("gcc_toolchain") { if (defined(invoker.link_outputs)) { outputs += invoker.link_outputs } + if (defined(map_file)) { + outputs += [ map_file ] + } } # These two are really entirely generic, but have to be repeated in @@ -487,31 +552,16 @@ template("clang_toolchain") { cc = "$prefix/clang" cxx = "$prefix/clang++" ld = cxx - - if (use_clang_static_analyzer) { - # Static analysis isn't supported under GOMA. See crbug.com/687245 - # for progress on this issue. - assert(!use_goma, "'use_clang_static_analyzer' cannot be used with GOMA.") - - # Call "ccc-analyzer" or "c++-analyzer" instead of directly calling Clang. - # |wrapper_tool| sets the environment variables which are read by the - # analyzer tools. - analyzer_wrapper = - rebase_path("//build/toolchain/clang_static_analyzer_wrapper.py", - root_build_dir) - cc = analyzer_wrapper + " --clang-cc-path=${cc} --analyzer=" + - rebase_path("//third_party/scan-build/src/libexec/ccc-analyzer", - root_build_dir) - cxx = analyzer_wrapper + " --clang-cxx-path=${cxx} --analyzer=" + - rebase_path("//third_party/scan-build/src/libexec/c++-analyzer", - root_build_dir) - } - readelf = "${toolprefix}readelf" - ar = "${toolprefix}ar" + ar = "${prefix}/llvm-ar" nm = "${toolprefix}nm" - forward_variables_from(invoker, [ "strip" ]) + forward_variables_from(invoker, + [ + "strip", + "is_clang_analysis_supported", + "enable_linker_map", + ]) toolchain_args = { if (defined(invoker.toolchain_args)) { diff --git a/chromium/build/toolchain/linux/BUILD.gn b/chromium/build/toolchain/linux/BUILD.gn index 86cd7dabc6e..3be5c36bca6 100644 --- a/chromium/build/toolchain/linux/BUILD.gn +++ b/chromium/build/toolchain/linux/BUILD.gn @@ -58,6 +58,9 @@ gcc_toolchain("arm") { } clang_toolchain("clang_x86") { + # Output linker map files for binary size analysis. + enable_linker_map = true + toolchain_args = { current_cpu = "x86" current_os = "linux" @@ -89,6 +92,9 @@ gcc_toolchain("x86") { ar = "ar" ld = cxx + # Output linker map files for binary size analysis. + enable_linker_map = true + toolchain_args = { current_cpu = "x86" current_os = "linux" @@ -97,6 +103,9 @@ gcc_toolchain("x86") { } clang_toolchain("clang_x64") { + # Output linker map files for binary size analysis. + enable_linker_map = true + toolchain_args = { current_cpu = "x64" current_os = "linux" @@ -128,6 +137,9 @@ gcc_toolchain("x64") { ar = "ar" ld = cxx + # Output linker map files for binary size analysis. + enable_linker_map = true + toolchain_args = { current_cpu = "x64" current_os = "linux" diff --git a/chromium/build/toolchain/nacl/BUILD.gn b/chromium/build/toolchain/nacl/BUILD.gn index 89e642eb9cf..c5899873a5c 100644 --- a/chromium/build/toolchain/nacl/BUILD.gn +++ b/chromium/build/toolchain/nacl/BUILD.gn @@ -74,13 +74,16 @@ template("pnacl_toolchain") { if (defined(invoker.strip)) { strip = scriptprefix + toolprefix + invoker.strip + scriptsuffix } + forward_variables_from(invoker, + [ + "executable_extension", + "is_clang_analysis_supported", + ]) # Note this is not the usual "ld = cxx" because "ld" uses are # never run via goma, so this needs scriptprefix. ld = scriptprefix + toolprefix + "clang++" + scriptsuffix - executable_extension = invoker.executable_extension - toolchain_args = { is_clang = true current_cpu = "pnacl" @@ -104,6 +107,10 @@ pnacl_toolchain("newlib_pnacl") { pnacl_toolchain("newlib_pnacl_nonsfi") { executable_extension = "" strip = "strip" + + if (use_clang_static_analyzer) { + is_clang_analysis_supported = false + } } template("nacl_glibc_toolchain") { diff --git a/chromium/build/toolchain/nacl_toolchain.gni b/chromium/build/toolchain/nacl_toolchain.gni index eb6ffcce0c0..e51a26de02c 100644 --- a/chromium/build/toolchain/nacl_toolchain.gni +++ b/chromium/build/toolchain/nacl_toolchain.gni @@ -32,6 +32,7 @@ template("nacl_toolchain") { "cc", "cxx", "deps", + "is_clang_analysis_supported", "ld", "link_outputs", "nm", diff --git a/chromium/build/toolchain/win/BUILD.gn b/chromium/build/toolchain/win/BUILD.gn index dd1017fb3d9..296f829cbb3 100644 --- a/chromium/build/toolchain/win/BUILD.gn +++ b/chromium/build/toolchain/win/BUILD.gn @@ -6,6 +6,7 @@ import("//build/config/clang/clang.gni") import("//build/config/compiler/compiler.gni") import("//build/config/sanitizers/sanitizers.gni") import("//build/config/win/visual_studio_version.gni") +import("//build/toolchain/clang_static_analyzer.gni") import("//build/toolchain/goma.gni") import("//build/toolchain/toolchain.gni") @@ -95,6 +96,14 @@ template("msvc_toolchain") { cl = invoker.cl } + if (toolchain_uses_clang && use_clang_static_analyzer) { + analyzer_prefix = + "$python_path " + + rebase_path("//build/toolchain/clang_static_analyzer_wrapper.py", + root_build_dir) + " --mode=cl" + cl = "${analyzer_prefix} ${cl}" + } + if (use_lld) { if (host_os == "win") { lld_link = "lld-link.exe" diff --git a/chromium/build/toolchain/win/setup_toolchain.py b/chromium/build/toolchain/win/setup_toolchain.py index ec60564070c..e8b08495745 100644 --- a/chromium/build/toolchain/win/setup_toolchain.py +++ b/chromium/build/toolchain/win/setup_toolchain.py @@ -127,6 +127,11 @@ def _LoadToolchainEnv(cpu, sdk_dir): os.environ['GYP_MSVS_OVERRIDE_PATH'], 'VC/vcvarsall.bat')) if not os.path.exists(script_path): + # vcvarsall.bat for VS 2017 fails if run after running vcvarsall.bat from + # VS 2013 or VS 2015. Fix this by clearing the vsinstalldir environment + # variable. + if 'VSINSTALLDIR' in os.environ: + del os.environ['VSINSTALLDIR'] other_path = os.path.normpath(os.path.join( os.environ['GYP_MSVS_OVERRIDE_PATH'], 'VC/Auxiliary/Build/vcvarsall.bat')) @@ -134,7 +139,10 @@ def _LoadToolchainEnv(cpu, sdk_dir): raise Exception('%s is missing - make sure VC++ tools are installed.' % script_path) script_path = other_path - args = [script_path, 'amd64_x86' if cpu == 'x86' else 'amd64'] + # Chromium requires the 10.0.14393.0 SDK. Previous versions don't have all + # of the required declarations, and 10.0.15063.0 is buggy. + args = [script_path, 'amd64_x86' if cpu == 'x86' else 'amd64', + '10.0.14393.0'] variables = _LoadEnvFromBat(args) return _ExtractImportantEnvironment(variables) diff --git a/chromium/build/toolchain/win/tool_wrapper.py b/chromium/build/toolchain/win/tool_wrapper.py index 4e69deafb5f..3a81368f346 100644 --- a/chromium/build/toolchain/win/tool_wrapper.py +++ b/chromium/build/toolchain/win/tool_wrapper.py @@ -315,16 +315,6 @@ class WinTool(object): dirname = dirname[0] if dirname else None return subprocess.call(args, shell=True, env=env, cwd=dirname) - def ExecClCompile(self, project_dir, selected_files): - """Executed by msvs-ninja projects when the 'ClCompile' target is used to - build selected C/C++ files.""" - project_dir = os.path.relpath(project_dir, BASE_DIR) - selected_files = selected_files.split(';') - ninja_targets = [os.path.join(project_dir, filename) + '^^' - for filename in selected_files] - cmd = ['ninja.exe'] - cmd.extend(ninja_targets) - return subprocess.call(cmd, shell=True, cwd=BASE_DIR) if __name__ == '__main__': sys.exit(main(sys.argv[1:])) diff --git a/chromium/build/toolchain/wrapper_utils.py b/chromium/build/toolchain/wrapper_utils.py index 467d85d9e2a..f76192e2063 100644 --- a/chromium/build/toolchain/wrapper_utils.py +++ b/chromium/build/toolchain/wrapper_utils.py @@ -4,16 +4,31 @@ """Helper functions for gcc_toolchain.gni wrappers.""" +import gzip import os import re import subprocess import shlex +import shutil import sys +import threading _BAT_PREFIX = 'cmd /c call ' _WHITELIST_RE = re.compile('whitelisted_resource_(?P<resource_id>[0-9]+)') +def _GzipThenDelete(src_path, dest_path): + # Results for Android map file with GCC on a z620: + # Uncompressed: 207MB + # gzip -9: 16.4MB, takes 8.7 seconds. + # gzip -1: 21.8MB, takes 2.0 seconds. + # Piping directly from the linker via -print-map (or via -Map with a fifo) + # adds a whopping 30-45 seconds! + with open(src_path, 'rb') as f_in, gzip.GzipFile(dest_path, 'wb', 1) as f_out: + shutil.copyfileobj(f_in, f_out) + os.unlink(src_path) + + def CommandToRun(command): """Generates commands compatible with Windows. @@ -36,6 +51,37 @@ def CommandToRun(command): return command +def RunLinkWithOptionalMapFile(command, env=None, map_file=None): + """Runs the given command, adding in -Wl,-Map when |map_file| is given. + + Also takes care of gzipping when |map_file| ends with .gz. + + Args: + command: List of arguments comprising the command. + env: Environment variables. + map_file: Path to output map_file. + + Returns: + The exit code of running |command|. + """ + tmp_map_path = None + if map_file and map_file.endswith('.gz'): + tmp_map_path = map_file + '.tmp' + command.append('-Wl,-Map,' + tmp_map_path) + elif map_file: + command.append('-Wl,-Map,' + map_file) + + result = subprocess.call(command, env=env) + + if tmp_map_path and result == 0: + threading.Thread( + target=lambda: _GzipThenDelete(tmp_map_path, map_file)).start() + elif tmp_map_path and os.path.exists(tmp_map_path): + os.unlink(tmp_map_path) + + return result + + def ResolveRspLinks(inputs): """Return a list of files contained in a response file. |