tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

gcc_toolchain.gni (37373B)


      1 # Copyright 2013 The Chromium Authors
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import("//chromium/build/config/clang/clang.gni")
      6 import("//chromium/build/config/compiler/compiler.gni")
      7 import("//chromium/build/config/coverage/coverage.gni")
      8 import("//chromium/build/config/rust.gni")
      9 import("//chromium/build/config/sanitizers/sanitizers.gni")
     10 import("//chromium/build/config/sysroot.gni")
     11 import("//chromium/build/config/v8_target_cpu.gni")
     12 import("//chromium/build/toolchain/cc_wrapper.gni")
     13 import("//chromium/build/toolchain/rbe.gni")
     14 import("//chromium/build/toolchain/toolchain.gni")
     15 
     16 if (is_nacl) {
     17   # To keep NaCl variables out of builds that don't include NaCl, all
     18   # variables defined in nacl/config.gni referenced here should be protected by
     19   # is_nacl conditions.
     20   import("//chromium/build/config/nacl/config.gni")
     21 }
     22 
     23 declare_args() {
     24   # Enables allowlist generation for IDR_ grit defines seen by the compiler.
     25   # Currently works only on some platforms and enabled by default for official
     26   # builds. Requires debug info.
     27   enable_resource_allowlist_generation =
     28       is_official_build &&
     29       # Don't enable for Android-on-Chrome OS.
     30       (target_os == "android" || target_os == "win")
     31 
     32   # Use -MD instead of -MMD for compiler commands. This is useful for tracking
     33   # the comprehensive set of dependencies.  It's also required when building
     34   # without the sysroot so that updates to system header files trigger a
     35   # rebuild (when using the sysroot, the CR_SYSROOT_KEY define takes care of
     36   # this already).
     37   system_headers_in_deps = !use_sysroot
     38 }
     39 
     40 # When the arg is set via args.gn, it applies to all toolchains. In order to not
     41 # hit the assert in grit_rule.gni, explicitly disable for host toolchains.
     42 if ((is_linux || is_chromeos) && target_os == "android") {
     43   enable_resource_allowlist_generation = false
     44 }
     45 
     46 # Ensure enable_resource_allowlist_generation is enabled only when it will work.
     47 if (enable_resource_allowlist_generation) {
     48   assert(
     49       !strip_debug_info,
     50       "enable_resource_allowlist_generation=true requires strip_debug_info=false")
     51   assert(
     52       !is_component_build,
     53       "enable_resource_allowlist_generation=true requires is_component_build=false")
     54   assert(
     55       target_os == "android" || target_os == "win",
     56       "enable_resource_allowlist_generation=true does not work for target_os=$target_os")
     57 }
     58 
     59 # This template defines a toolchain for something that works like gcc
     60 # (including clang).
     61 #
     62 # It requires the following variables specifying the executables to run:
     63 #  - ar
     64 #  - cc
     65 #  - cxx
     66 #  - ld
     67 #
     68 # Optional parameters that control the tools:
     69 #
     70 #  - extra_cflags
     71 #      Extra flags to be appended when compiling C files (but not C++ files).
     72 #  - extra_cppflags
     73 #      Extra flags to be appended when compiling both C and C++ files. "CPP"
     74 #      stands for "C PreProcessor" in this context, although it can be
     75 #      used for non-preprocessor flags as well. Not to be confused with
     76 #      "CXX" (which follows).
     77 #  - extra_cxxflags
     78 #      Extra flags to be appended when compiling C++ files (but not C files).
     79 #  - extra_asmflags
     80 #      Extra flags to be appended when compiling assembly.
     81 #  - extra_ldflags
     82 #      Extra flags to be appended when linking
     83 #
     84 #  - link_outputs
     85 #      The content of this array, if specified, will be added to the list of
     86 #      outputs from the link command. This can be useful in conjunction with
     87 #      the post_link parameter.
     88 #  - use_unstripped_as_runtime_outputs
     89 #      When |strip| is set, mark unstripped executables as runtime deps rather
     90 #      than stripped ones.
     91 #  - post_link
     92 #      The content of this string, if specified, will be run as a separate
     93 #      command following the the link command.
     94 #  - deps
     95 #      Just forwarded to the toolchain definition.
     96 #  - executable_extension
     97 #      If this string is specified it will be used for the file extension
     98 #      for an executable, rather than using no extension; targets will
     99 #      still be able to override the extension using the output_extension
    100 #      variable.
    101 #  - rebuild_define
    102 #      The contents of this string, if specified, will be passed as a #define
    103 #      to the toolchain. It can be used to force recompiles whenever a
    104 #      toolchain is updated.
    105 #  - shlib_extension
    106 #      If this string is specified it will be used for the file extension
    107 #      for a shared library, rather than default value specified in
    108 #      toolchain.gni
    109 #  - strip
    110 #      Location of the strip executable. When specified, strip will be run on
    111 #      all shared libraries and executables as they are built. The pre-stripped
    112 #      artifacts will be put in lib.unstripped/ and exe.unstripped/.
    113 #
    114 # Callers will normally want to invoke "gcc_toolchain" instead, which makes an
    115 # additional toolchain for Rust targets that are build-time artificts such as
    116 # proc macros.
    117 template("single_gcc_toolchain") {
    118   toolchain(target_name) {
    119     assert(defined(invoker.ar), "gcc_toolchain() must specify a \"ar\" value")
    120     assert(defined(invoker.cc), "gcc_toolchain() must specify a \"cc\" value")
    121     assert(defined(invoker.cxx), "gcc_toolchain() must specify a \"cxx\" value")
    122     assert(defined(invoker.ld), "gcc_toolchain() must specify a \"ld\" value")
    123 
    124     # This define changes when the toolchain changes, forcing a rebuild.
    125     # Nothing should ever use this define.
    126     if (defined(invoker.rebuild_define)) {
    127       rebuild_string = "-D" + invoker.rebuild_define + " "
    128     } else {
    129       rebuild_string = ""
    130     }
    131 
    132     # GN's syntax can't handle more than one scope dereference at once, like
    133     # "invoker.toolchain_args.foo", so make a temporary to hold the toolchain
    134     # args so we can do "invoker_toolchain_args.foo".
    135     assert(defined(invoker.toolchain_args),
    136            "Toolchains must specify toolchain_args")
    137     invoker_toolchain_args = invoker.toolchain_args
    138     assert(defined(invoker_toolchain_args.target_cpu),
    139            "toolchain_args must specify a target_cpu")
    140     assert(defined(invoker_toolchain_args.current_os),
    141            "toolchain_args must specify a current_os")
    142 
    143     # use_reclient is default to use_remoteexec
    144     if (!defined(invoker_toolchain_args.use_reclient) &&
    145         defined(invoker_toolchain_args.use_remoteexec)) {
    146       invoker_toolchain_args.use_reclient =
    147           invoker_toolchain_args.use_remoteexec
    148     }
    149 
    150     # When invoking this toolchain not as the default one, these args will be
    151     # passed to the build. They are ignored when this is the default toolchain.
    152     toolchain_args = {
    153       # Populate toolchain args from the invoker.
    154       forward_variables_from(invoker_toolchain_args, "*")
    155 
    156       # The host toolchain value computed by the default toolchain's setup
    157       # needs to be passed through unchanged to all secondary toolchains to
    158       # ensure that it's always the same, regardless of the values that may be
    159       # set on those toolchains.
    160       host_toolchain = host_toolchain
    161 
    162       if (!defined(invoker_toolchain_args.v8_target_cpu)) {
    163         v8_target_cpu = invoker_toolchain_args.target_cpu
    164       }
    165     }
    166 
    167     # When the invoker has explicitly overridden use_remoteexec or
    168     # cc_wrapper in the toolchain args, use those values, otherwise default
    169     # to the global one.  This works because the only reasonable override
    170     # that toolchains might supply for these values are to force-disable them.
    171     if (defined(toolchain_args.use_reclient)) {
    172       toolchain_uses_reclient = toolchain_args.use_reclient
    173     } else {
    174       toolchain_uses_reclient = use_reclient
    175     }
    176 
    177     if (defined(toolchain_args.cc_wrapper)) {
    178       toolchain_cc_wrapper = toolchain_args.cc_wrapper
    179     } else {
    180       toolchain_cc_wrapper = cc_wrapper
    181     }
    182     assert(!(toolchain_cc_wrapper != "" && toolchain_uses_reclient),
    183            "re-client and cc_wrapper can't be used together.")
    184 
    185     # When the invoker has explicitly overridden cc_wrapper in the
    186     # toolchain args, use those values, otherwise default to the global one.
    187     # This works because the only reasonable override that toolchains might
    188     # supply for these values are to force-disable them.
    189     # But if needs_rewrapper_path_arg is set in a Chrome OS build, the
    190     # toolchain wrapper will have picked up rewrapper via cmd-line arg. So
    191     # need to prepend rewrapper in that case.
    192     if (toolchain_uses_reclient &&
    193         (!defined(invoker.needs_rewrapper_path_arg) ||
    194          !invoker.needs_rewrapper_path_arg)) {
    195       if (defined(toolchain_args.reclient_cc_cfg_file)) {
    196         toolchain_reclient_cc_cfg_file = toolchain_args.reclient_cc_cfg_file
    197       } else {
    198         toolchain_reclient_cc_cfg_file = reclient_cc_cfg_file
    199       }
    200 
    201       # C/C++ (clang) rewrapper prefix to use when use_reclient is true.
    202       compiler_prefix = "${reclient_bin_dir}/rewrapper -cfg=${toolchain_reclient_cc_cfg_file}${rbe_bug_326584510_missing_inputs} -exec_root=${rbe_exec_root} "
    203     } else {
    204       compiler_prefix = "${toolchain_cc_wrapper} "
    205 
    206       # Prevent warning about unused variable since it is not read in the code
    207       # paths when reclient is not needed.
    208       not_needed(invoker, [ "needs_rewrapper_path_arg" ])
    209     }
    210 
    211     # A specific toolchain may wish to avoid coverage instrumentation, so we
    212     # allow the global "use_clang_coverage" arg to be overridden.
    213     if (defined(toolchain_args.use_clang_coverage)) {
    214       toolchain_use_clang_coverage = toolchain_args.use_clang_coverage
    215     } else {
    216       toolchain_use_clang_coverage = use_clang_coverage
    217     }
    218 
    219     # For a coverage build, we use the wrapper script globally so that it can
    220     # remove coverage cflags from files that should not have them.
    221     if (toolchain_use_clang_coverage) {
    222       # "coverage_instrumentation_input_file" is set in args.gn, but it can be
    223       # overridden by a toolchain config.
    224       if (defined(toolchain_args.coverage_instrumentation_input_file)) {
    225         toolchain_coverage_instrumentation_input_file =
    226             toolchain_args.coverage_instrumentation_input_file
    227       } else {
    228         toolchain_coverage_instrumentation_input_file =
    229             coverage_instrumentation_input_file
    230       }
    231 
    232       _coverage_wrapper =
    233           rebase_path("//chromium/build/toolchain/clang_code_coverage_wrapper.py",
    234                       root_build_dir)
    235 
    236       # The wrapper needs to know what OS we target because it uses that to
    237       # select a list of files that should not be instrumented.
    238       _coverage_wrapper = _coverage_wrapper + " --target-os=" +
    239                           invoker_toolchain_args.current_os
    240 
    241       # We want to instrument everything if there is no input file set.
    242       # If there is a file we need to give it to the wrapper script so it can
    243       # instrument only those files.
    244       if (toolchain_coverage_instrumentation_input_file != "") {
    245         _coverage_wrapper =
    246             _coverage_wrapper + " --files-to-instrument=" +
    247             rebase_path(toolchain_coverage_instrumentation_input_file,
    248                         root_build_dir)
    249       }
    250       compiler_prefix =
    251           "\"$python_path\" ${_coverage_wrapper} " + compiler_prefix
    252     }
    253 
    254     cc = compiler_prefix + invoker.cc
    255     cxx = compiler_prefix + invoker.cxx
    256 
    257     # "asm" doesn't support any of toolchain_cc_wrapper and
    258     # toolchain_uses_reclient. The coverage flags are also nonsensical on
    259     # assembler runs.
    260     asm = invoker.cc
    261     ar = invoker.ar
    262     ld = invoker.ld
    263     if (defined(invoker.readelf)) {
    264       readelf = invoker.readelf
    265     } else {
    266       readelf = "readelf"
    267     }
    268     if (defined(invoker.nm)) {
    269       nm = invoker.nm
    270     } else {
    271       nm = "nm"
    272     }
    273     if (defined(invoker.dwp)) {
    274       dwp_switch = " --dwp=\"${invoker.dwp}\""
    275     } else {
    276       dwp_switch = ""
    277     }
    278 
    279     if (defined(invoker.shlib_extension)) {
    280       default_shlib_extension = invoker.shlib_extension
    281     } else {
    282       default_shlib_extension = shlib_extension
    283     }
    284 
    285     if (defined(invoker.default_shlib_subdir)) {
    286       default_shlib_subdir = invoker.default_shlib_subdir
    287     } else {
    288       default_shlib_subdir = ""
    289     }
    290 
    291     if (defined(invoker.executable_extension)) {
    292       default_executable_extension = invoker.executable_extension
    293     } else {
    294       default_executable_extension = ""
    295     }
    296 
    297     # Bring these into our scope for string interpolation with default values.
    298     if (defined(invoker.extra_cflags) && invoker.extra_cflags != "") {
    299       extra_cflags = " " + invoker.extra_cflags
    300     } else {
    301       extra_cflags = ""
    302     }
    303 
    304     if (defined(invoker.extra_cppflags) && invoker.extra_cppflags != "") {
    305       extra_cppflags = " " + invoker.extra_cppflags
    306     } else {
    307       extra_cppflags = ""
    308     }
    309 
    310     if (defined(invoker.extra_cxxflags) && invoker.extra_cxxflags != "") {
    311       extra_cxxflags = " " + invoker.extra_cxxflags
    312     } else {
    313       extra_cxxflags = ""
    314     }
    315 
    316     if (defined(invoker.extra_asmflags) && invoker.extra_asmflags != "") {
    317       extra_asmflags = " " + invoker.extra_asmflags
    318     } else {
    319       extra_asmflags = ""
    320     }
    321 
    322     if (defined(invoker.extra_ldflags) && invoker.extra_ldflags != "") {
    323       extra_ldflags = " " + invoker.extra_ldflags
    324     } else {
    325       extra_ldflags = ""
    326     }
    327 
    328     if (system_headers_in_deps) {
    329       md = "-MD"
    330     } else {
    331       md = "-MMD"
    332     }
    333 
    334     enable_linker_map = defined(invoker.enable_linker_map) &&
    335                         invoker.enable_linker_map && generate_linker_map
    336 
    337     # These library switches can apply to all tools below.
    338     lib_switch = "-l"
    339     lib_dir_switch = "-L"
    340 
    341     # Object files go in this directory.
    342     object_subdir = "{{target_out_dir}}/{{label_name}}"
    343 
    344     tool("cc") {
    345       depfile = "{{output}}.d"
    346       precompiled_header_type = "gcc"
    347       command = "$cc $md -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{cflags}} {{cflags_c}}${extra_cppflags}${extra_cflags} -c {{source}} -o {{output}}"
    348       depsformat = "gcc"
    349       description = "CC {{output}}"
    350       outputs = [ "$object_subdir/{{source_name_part}}.o" ]
    351     }
    352 
    353     tool("cxx") {
    354       depfile = "{{output}}.d"
    355       precompiled_header_type = "gcc"
    356       command = "$cxx $md -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}}${extra_cppflags}${extra_cxxflags} {{module_deps_no_self}} -c {{source}} -o {{output}}"
    357       depsformat = "gcc"
    358       description = "CXX {{output}}"
    359       outputs = [ "$object_subdir/{{source_name_part}}.o" ]
    360     }
    361 
    362     tool("cxx_module") {
    363       depfile = "{{output}}.d"
    364       command = "$cxx -MD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}}${extra_cppflags}${extra_cxxflags} {{module_deps_no_self}} -fmodule-name={{label_name}} -c -x c++ -Xclang -emit-module {{source}} -o {{output}}"
    365       depsformat = "gcc"
    366       description = "CXX_MODULE {{output}}"
    367       outputs = [ "$object_subdir/{{source_name_part}}.pcm" ]
    368     }
    369 
    370     tool("asm") {
    371       # For GCC we can just use the C compiler to compile assembly.
    372       depfile = "{{output}}.d"
    373       command = "$asm $md -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{asmflags}}${extra_asmflags} -c {{source}} -o {{output}}"
    374       depsformat = "gcc"
    375       description = "ASM {{output}}"
    376       outputs = [ "$object_subdir/{{source_name_part}}.o" ]
    377     }
    378 
    379     tool("alink") {
    380       if (current_os == "aix") {
    381         # AIX does not support either -D (deterministic output) or response
    382         # files.
    383         command = "$ar -X64 {{arflags}} -r -c {{output}} {{inputs}}"
    384       } else {
    385         rspfile = "{{output}}.rsp"
    386         rspfile_content = "{{inputs}}"
    387         command = "\"$ar\" {{arflags}} -r -c -D {{output}} @\"$rspfile\""
    388       }
    389 
    390       # Remove the output file first so that ar doesn't try to modify the
    391       # existing file.
    392       if (host_os == "win") {
    393         tool_wrapper_path =
    394             rebase_path("//chromium/build/toolchain/win/tool_wrapper.py", root_build_dir)
    395         command = "cmd /s /c \"\"$python_path\" $tool_wrapper_path delete-file {{output}} && $command\""
    396       } else {
    397         command = "rm -f {{output}} && $command"
    398       }
    399 
    400       # Almost all targets build with //build/config/compiler:thin_archive which
    401       # adds -T -S to arflags.
    402       description = "AR {{output}}"
    403       outputs = [ "{{output_dir}}/{{target_output_name}}{{output_extension}}" ]
    404 
    405       # Static libraries go in the target out directory by default so we can
    406       # generate different targets with the same name and not have them collide.
    407       default_output_dir = "{{target_out_dir}}"
    408       default_output_extension = ".a"
    409       output_prefix = "lib"
    410     }
    411 
    412     tool("solink") {
    413       soname = "{{target_output_name}}{{output_extension}}"  # e.g. "libfoo.so".
    414       sofile = "{{output_dir}}/$soname"  # Possibly including toolchain dir.
    415       rspfile = sofile + ".rsp"
    416 
    417       pool = "//chromium/build/toolchain:link_pool($default_toolchain)"
    418 
    419       if (defined(invoker.strip)) {
    420         unstripped_sofile = "{{root_out_dir}}/lib.unstripped/$soname"
    421       } else {
    422         unstripped_sofile = sofile
    423       }
    424 
    425       # These variables are not built into GN but are helpers that
    426       # implement (1) linking to produce a .so, (2) extracting the symbols
    427       # from that file (3) if the extracted list differs from the existing
    428       # .TOC file, overwrite it, otherwise, don't change it.
    429       tocfile = sofile + ".TOC"
    430 
    431       soname_flag = ""
    432       if (current_os != "aix") {
    433         # -soname flag is not available on aix ld
    434         soname_flag = "-Wl,-soname=\"$soname\""
    435       }
    436       link_command = "$ld -shared $soname_flag {{ldflags}}${extra_ldflags} -o \"$unstripped_sofile\" @\"$rspfile\" {{rlibs}}"
    437 
    438       # Generate a map file to be used for binary size analysis.
    439       # Map file adds ~10% to the link time on a z620.
    440       # With target_os="android", libchrome.so.map.gz is ~20MB.
    441       map_switch = ""
    442       if (enable_linker_map) {
    443         map_file = "$unstripped_sofile.map.gz"
    444         map_switch = " --map-file \"$map_file\""
    445       }
    446 
    447       assert(defined(readelf), "to solink you must have a readelf")
    448       assert(defined(nm), "to solink you must have an nm")
    449       strip_switch = ""
    450       if (defined(invoker.strip)) {
    451         strip_switch = "--strip=${invoker.strip} "
    452       }
    453 
    454       # This needs a Python script to avoid using a complex shell command
    455       # requiring sh control structures, pipelines, and POSIX utilities.
    456       # The host might not have a POSIX shell and utilities (e.g. Windows).
    457       solink_wrapper =
    458           rebase_path("//chromium/build/toolchain/gcc_solink_wrapper.py", root_build_dir)
    459       solink_extra_flags = ""
    460       if (current_os == "aix") {
    461         # to be intercepted by solink_wrapper, so that we exit immediately
    462         # after linking the shared object, without generating the TOC file
    463         # (skipped on Aix)
    464         solink_extra_flags = "--partitioned-library"
    465       }
    466       command = "\"$python_path\" \"$solink_wrapper\" --readelf=\"$readelf\" --nm=\"$nm\" $strip_switch$dwp_switch --sofile=\"$unstripped_sofile\" --tocfile=\"$tocfile\"$map_switch --output=\"$sofile\" -- $link_command $solink_extra_flags"
    467 
    468       if (target_cpu == "mipsel" && is_component_build && is_android) {
    469         rspfile_content = "-Wl,--start-group -Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}} -Wl,--end-group"
    470       } else if (current_os == "aix") {
    471         # --whole-archive, --no-whole-archive flags are not available on the aix
    472         # ld.
    473         rspfile_content = "{{inputs}} {{solibs}} {{libs}}"
    474       } else {
    475         rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}}"
    476       }
    477 
    478       description = "SOLINK $sofile"
    479 
    480       # Use this for {{output_extension}} expansions unless a target manually
    481       # overrides it (in which case {{output_extension}} will be what the target
    482       # specifies).
    483       default_output_extension = default_shlib_extension
    484 
    485       default_output_dir = "{{root_out_dir}}${default_shlib_subdir}"
    486 
    487       output_prefix = "lib"
    488 
    489       # Since the above commands only updates the .TOC file when it changes, ask
    490       # Ninja to check if the timestamp actually changed to know if downstream
    491       # dependencies should be recompiled.
    492       restat = true
    493 
    494       # Tell GN about the output files. It will link to the sofile but use the
    495       # tocfile for dependency management.
    496       outputs = [
    497         sofile,
    498         tocfile,
    499       ]
    500       if (sofile != unstripped_sofile) {
    501         outputs += [ unstripped_sofile ]
    502         if (defined(invoker.use_unstripped_as_runtime_outputs) &&
    503             invoker.use_unstripped_as_runtime_outputs) {
    504           runtime_outputs = [ unstripped_sofile ]
    505         }
    506       }
    507 
    508       # Clank build will generate DWP files when Fission is used.
    509       # Other builds generate DWP files outside of the gn link targets, if at
    510       # all.
    511       if (defined(invoker.dwp)) {
    512         outputs += [ unstripped_sofile + ".dwp" ]
    513         if (defined(invoker.use_unstripped_as_runtime_outputs) &&
    514             invoker.use_unstripped_as_runtime_outputs) {
    515           runtime_outputs += [ unstripped_sofile + ".dwp" ]
    516         }
    517       }
    518       if (defined(map_file)) {
    519         outputs += [ map_file ]
    520       }
    521       link_output = sofile
    522       depend_output = tocfile
    523     }
    524 
    525     tool("solink_module") {
    526       soname = "{{target_output_name}}{{output_extension}}"  # e.g. "libfoo.so".
    527       sofile = "{{output_dir}}/$soname"
    528       rspfile = sofile + ".rsp"
    529 
    530       pool = "//chromium/build/toolchain:link_pool($default_toolchain)"
    531 
    532       if (defined(invoker.strip)) {
    533         unstripped_sofile = "{{root_out_dir}}/lib.unstripped/$soname"
    534       } else {
    535         unstripped_sofile = sofile
    536       }
    537 
    538       soname_flag = ""
    539       whole_archive_flag = ""
    540       no_whole_archive_flag = ""
    541       if (current_os != "aix") {
    542         # -soname, --whole-archive, --no-whole-archive flags are not available
    543         # on aix ld
    544         soname_flag = "-Wl,-soname=\"$soname\""
    545         whole_archive_flag = "-Wl,--whole-archive"
    546         no_whole_archive_flag = "-Wl,--no-whole-archive"
    547       }
    548       command = "$ld -shared {{ldflags}}${extra_ldflags} -o \"$unstripped_sofile\" $soname_flag @\"$rspfile\""
    549 
    550       if (defined(invoker.strip)) {
    551         strip_command = "${invoker.strip} -o \"$sofile\" \"$unstripped_sofile\""
    552         command += " && " + strip_command
    553       }
    554       rspfile_content = "$whole_archive_flag {{inputs}} {{solibs}} $no_whole_archive_flag {{libs}} {{rlibs}}"
    555 
    556       description = "SOLINK_MODULE $sofile"
    557 
    558       # Use this for {{output_extension}} expansions unless a target manually
    559       # overrides it (in which case {{output_extension}} will be what the target
    560       # specifies).
    561       if (defined(invoker.loadable_module_extension)) {
    562         default_output_extension = invoker.loadable_module_extension
    563       } else {
    564         default_output_extension = default_shlib_extension
    565       }
    566 
    567       default_output_dir = "{{root_out_dir}}${default_shlib_subdir}"
    568 
    569       output_prefix = "lib"
    570 
    571       outputs = [ sofile ]
    572       if (sofile != unstripped_sofile) {
    573         outputs += [ unstripped_sofile ]
    574         if (defined(invoker.use_unstripped_as_runtime_outputs) &&
    575             invoker.use_unstripped_as_runtime_outputs) {
    576           runtime_outputs = [ unstripped_sofile ]
    577         }
    578       }
    579     }
    580 
    581     tool("link") {
    582       exename = "{{target_output_name}}{{output_extension}}"
    583       outfile = "{{output_dir}}/$exename"
    584       rspfile = "$outfile.rsp"
    585       unstripped_outfile = outfile
    586 
    587       pool = "//chromium/build/toolchain:link_pool($default_toolchain)"
    588 
    589       # Use this for {{output_extension}} expansions unless a target manually
    590       # overrides it (in which case {{output_extension}} will be what the target
    591       # specifies).
    592       default_output_extension = default_executable_extension
    593 
    594       default_output_dir = "{{root_out_dir}}"
    595 
    596       if (defined(invoker.strip)) {
    597         unstripped_outfile = "{{root_out_dir}}/exe.unstripped/$exename"
    598       }
    599 
    600       start_group_flag = ""
    601       end_group_flag = ""
    602       if (current_os != "aix") {
    603         # the "--start-group .. --end-group" feature isn't available on the aix
    604         # ld.
    605         start_group_flag = "-Wl,--start-group"
    606         end_group_flag = "-Wl,--end-group "
    607       }
    608 
    609       # We need to specify link groups, at least, for single pass linkers. I.e.
    610       # Rust libraries are alpha-sorted instead of by dependencies so they fail
    611       # to link if not properly ordered or grouped.
    612       link_command = "$ld {{ldflags}}${extra_ldflags} -o \"$unstripped_outfile\" $start_group_flag @\"$rspfile\" $end_group_flag {{solibs}} {{libs}} $start_group_flag {{rlibs}} $end_group_flag"
    613 
    614       # Generate a map file to be used for binary size analysis.
    615       # Map file adds ~10% to the link time on a z620.
    616       # With target_os="android", libchrome.so.map.gz is ~20MB.
    617       map_switch = ""
    618       if (enable_linker_map) {
    619         map_file = "$unstripped_outfile.map.gz"
    620         map_switch = " --map-file \"$map_file\""
    621       }
    622 
    623       strip_switch = ""
    624       if (defined(invoker.strip)) {
    625         strip_switch = " --strip=\"${invoker.strip}\" --unstripped-file=\"$unstripped_outfile\""
    626       }
    627 
    628       link_wrapper =
    629           rebase_path("//chromium/build/toolchain/gcc_link_wrapper.py", root_build_dir)
    630       command = "\"$python_path\" \"$link_wrapper\" --output=\"$outfile\"$strip_switch$map_switch$dwp_switch -- $link_command"
    631 
    632       description = "LINK $outfile"
    633 
    634       rspfile_content = "{{inputs}}"
    635       outputs = [ outfile ]
    636       if (outfile != unstripped_outfile) {
    637         outputs += [ unstripped_outfile ]
    638         if (defined(invoker.use_unstripped_as_runtime_outputs) &&
    639             invoker.use_unstripped_as_runtime_outputs) {
    640           runtime_outputs = [ unstripped_outfile ]
    641         }
    642       }
    643 
    644       # Clank build will generate DWP files when Fission is used.
    645       # Other builds generate DWP files outside of the gn link targets, if at
    646       # all.
    647       if (defined(invoker.dwp)) {
    648         outputs += [ unstripped_outfile + ".dwp" ]
    649         if (defined(invoker.use_unstripped_as_runtime_outputs) &&
    650             invoker.use_unstripped_as_runtime_outputs) {
    651           runtime_outputs += [ unstripped_outfile + ".dwp" ]
    652         }
    653       }
    654       if (defined(invoker.link_outputs)) {
    655         outputs += invoker.link_outputs
    656       }
    657       if (defined(map_file)) {
    658         outputs += [ map_file ]
    659       }
    660     }
    661 
    662     # These two are really entirely generic, but have to be repeated in
    663     # each toolchain because GN doesn't allow a template to be used here.
    664     # See //build/toolchain/toolchain.gni for details.
    665     tool("stamp") {
    666       command = stamp_command
    667       description = stamp_description
    668     }
    669     tool("copy") {
    670       command = copy_command
    671       description = copy_description
    672     }
    673 
    674     tool("action") {
    675       pool = "//chromium/build/toolchain:action_pool($default_toolchain)"
    676     }
    677 
    678     if (toolchain_has_rust) {
    679       if (!defined(rust_compiler_prefix)) {
    680         rust_compiler_prefix = ""
    681       }
    682       rust_sysroot_relative = rebase_path(rust_sysroot, root_build_dir)
    683       rustc_bin = "$rust_sysroot_relative/bin/rustc"
    684       rustc = "$rust_compiler_prefix${rustc_bin}"
    685       rustc_wrapper =
    686           rebase_path("//chromium/build/rust/rustc_wrapper.py", root_build_dir)
    687 
    688       # RSP manipulation due to https://bugs.chromium.org/p/gn/issues/detail?id=249
    689       tool("rust_staticlib") {
    690         libname = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
    691         rspfile = "$libname.rsp"
    692         depfile = "$libname.d"
    693 
    694         default_output_extension = ".a"
    695         output_prefix = "lib"
    696 
    697         # Static libraries go in the target out directory by default so we can
    698         # generate different targets with the same name and not have them
    699         # collide.
    700         default_output_dir = "{{target_out_dir}}"
    701         description = "RUST(STATICLIB) {{output}}"
    702         outputs = [ libname ]
    703 
    704         rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}"
    705         command = "\"$python_path\" \"$rustc_wrapper\" --rustc=$rustc --depfile=$depfile --rsp=$rspfile -- -Clinker=\"${invoker.cxx}\" $rustc_common_args --emit=dep-info=$depfile,link -o $libname LDFLAGS RUSTENV {{rustenv}}"
    706         rust_sysroot = rust_sysroot_relative
    707       }
    708 
    709       tool("rust_rlib") {
    710         # We must always prefix with `lib` even if the library already starts
    711         # with that prefix or else our stdlib is unable to find libc.rlib (or
    712         # actually liblibc.rlib).
    713         rlibname =
    714             "{{output_dir}}/lib{{target_output_name}}{{output_extension}}"
    715         rspfile = "$rlibname.rsp"
    716         depfile = "$rlibname.d"
    717 
    718         default_output_extension = ".rlib"
    719 
    720         # This is prefixed unconditionally in `rlibname`.
    721         # output_prefix = "lib"
    722         # Static libraries go in the target out directory by default so we can
    723         # generate different targets with the same name and not have them
    724         # collide.
    725         default_output_dir = "{{target_out_dir}}"
    726         description = "RUST {{output}}"
    727         outputs = [ rlibname ]
    728 
    729         rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}"
    730         command = "\"$python_path\" \"$rustc_wrapper\" --rustc=$rustc --depfile=$depfile --rsp=$rspfile -- -Clinker=\"${invoker.cxx}\" $rustc_common_args --emit=dep-info=$depfile,link -o $rlibname LDFLAGS RUSTENV {{rustenv}}"
    731         rust_sysroot = rust_sysroot_relative
    732       }
    733 
    734       tool("rust_bin") {
    735         exename = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
    736         depfile = "$exename.d"
    737         rspfile = "$exename.rsp"
    738         pool = "//chromium/build/toolchain:link_pool($default_toolchain)"
    739 
    740         default_output_extension = default_executable_extension
    741         default_output_dir = "{{root_out_dir}}"
    742         description = "RUST(BIN) {{output}}"
    743         outputs = [ exename ]
    744 
    745         rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}"
    746         command = "\"$python_path\" \"$rustc_wrapper\" --rustc=$rustc --depfile=$depfile --rsp=$rspfile -- -Clinker=\"${invoker.cxx}\" $rustc_common_args --emit=dep-info=$depfile,link -o $exename LDFLAGS {{ldflags}} ${extra_ldflags} RUSTENV {{rustenv}}"
    747         rust_sysroot = rust_sysroot_relative
    748       }
    749 
    750       tool("rust_cdylib") {
    751         dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
    752         depfile = "$dllname.d"
    753         rspfile = "$dllname.rsp"
    754         pool = "//chromium/build/toolchain:link_pool($default_toolchain)"
    755 
    756         default_output_extension = default_shlib_extension
    757         output_prefix = "lib"
    758         default_output_dir = "{{root_out_dir}}${default_shlib_subdir}"
    759         description = "RUST(CDYLIB) {{output}}"
    760         outputs = [ dllname ]
    761 
    762         rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}"
    763         command = "\"$python_path\" \"$rustc_wrapper\" --rustc=$rustc --depfile=$depfile --rsp=$rspfile -- -Clinker=\"${invoker.cxx}\" $rustc_common_args --emit=dep-info=$depfile,link -o $dllname LDFLAGS {{ldflags}} ${extra_ldflags} RUSTENV {{rustenv}}"
    764         rust_sysroot = rust_sysroot_relative
    765       }
    766 
    767       tool("rust_macro") {
    768         dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
    769         depfile = "$dllname.d"
    770         rspfile = "$dllname.rsp"
    771         pool = "//chromium/build/toolchain:link_pool($default_toolchain)"
    772 
    773         default_output_extension = default_shlib_extension
    774         output_prefix = "lib"
    775         default_output_dir = "{{root_out_dir}}${default_shlib_subdir}"
    776         description = "RUST(MACRO) {{output}}"
    777         outputs = [ dllname ]
    778 
    779         rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}"
    780         command = "\"$python_path\" \"$rustc_wrapper\" --rustc=$rustc --depfile=$depfile --rsp=$rspfile -- -Clinker=\"${invoker.cxx}\" $rustc_common_args --emit=dep-info=$depfile,link -o $dllname LDFLAGS {{ldflags}} ${extra_ldflags} RUSTENV {{rustenv}}"
    781         rust_sysroot = rust_sysroot_relative
    782       }
    783     }
    784 
    785     forward_variables_from(invoker,
    786                            [
    787                              "deps",
    788                              "propagates_configs",
    789                            ])
    790   }
    791 }
    792 
    793 # Make an additional toolchain which is used for making tools that are run
    794 # on the host machine as part of the build process (such as proc macros
    795 # and Cargo build scripts). This toolchain uses the prebuilt stdlib that
    796 # comes with the compiler, so it doesn't have to wait for the stdlib to be
    797 # built before building other stuff. And this ensures its proc macro
    798 # outputs have the right ABI to be loaded by the compiler, and it can be
    799 # used to compile build scripts that are part of the stdlib that is built
    800 # for the default toolchain.
    801 template("gcc_rust_host_build_tools_toolchain") {
    802   single_gcc_toolchain(target_name) {
    803     assert(defined(invoker.toolchain_args),
    804            "Toolchains must declare toolchain_args")
    805     forward_variables_from(invoker,
    806                            "*",
    807                            TESTONLY_AND_VISIBILITY + [ "toolchain_args" ])
    808     toolchain_args = {
    809       # Populate toolchain args from the invoker.
    810       forward_variables_from(invoker.toolchain_args, "*")
    811       toolchain_for_rust_host_build_tools = true
    812 
    813       # The host build tools are static release builds to make the Chromium
    814       # build faster.
    815       is_debug = false
    816       is_component_build = false
    817       is_official_build = false
    818       use_clang_coverage = false
    819       use_sanitizer_coverage = false
    820       generate_linker_map = false
    821       use_thin_lto = false
    822     }
    823 
    824     # When cross-compiling we don't want to use the target platform's file
    825     # extensions.
    826     shlib_extension = host_shlib_extension
    827   }
    828 }
    829 
    830 # If PartitionAlloc is part of the build (even as a transitive dependency), then
    831 # it replaces the system allocator. If this toolchain is used, that will be
    832 # overridden and the system allocator will be used regardless. This is important
    833 # in some third-party binaries outside of Chrome.
    834 template("gcc_system_allocator_toolchain") {
    835   single_gcc_toolchain(target_name) {
    836     assert(defined(invoker.toolchain_args),
    837            "Toolchains must declare toolchain_args")
    838     forward_variables_from(invoker,
    839                            "*",
    840                            TESTONLY_AND_VISIBILITY + [ "toolchain_args" ])
    841     toolchain_args = {
    842       # Populate toolchain args from the invoker.
    843       forward_variables_from(invoker.toolchain_args, "*")
    844       toolchain_allows_use_partition_alloc_as_malloc = false
    845 
    846       # Disable component build so that we can copy the exes to the
    847       # root_build_dir and support the default_toolchain redirection on Windows.
    848       # See also the comment in //build/symlink.gni.
    849       is_component_build = false
    850 
    851       # Only one toolchain can be configured with MSAN support with our current
    852       # GN setup, or they all try to make the instrumented libraries and
    853       # collide.
    854       is_msan = false
    855     }
    856   }
    857 }
    858 
    859 # Makes a GCC toolchain for the target, and an equivalent toolchain with the
    860 # prebuilt Rust stdlib for building proc macros (and other for-build-use
    861 # artifacts).
    862 template("gcc_toolchain") {
    863   single_gcc_toolchain(target_name) {
    864     assert(defined(invoker.toolchain_args),
    865            "Toolchains must declare toolchain_args")
    866     forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)
    867 
    868     # No need to forward visibility and test_only as they apply to targets not
    869     # toolchains, but presubmit checks require that we explicitly exclude them
    870   }
    871 
    872   gcc_rust_host_build_tools_toolchain(
    873       "${target_name}_for_rust_host_build_tools") {
    874     assert(defined(invoker.toolchain_args),
    875            "Toolchains must declare toolchain_args")
    876     forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)
    877   }
    878 
    879   gcc_system_allocator_toolchain("${target_name}_host_with_system_allocator") {
    880     assert(defined(invoker.toolchain_args),
    881            "Toolchains must declare toolchain_args")
    882     forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)
    883   }
    884   gcc_system_allocator_toolchain("${target_name}_with_system_allocator") {
    885     assert(defined(invoker.toolchain_args),
    886            "Toolchains must declare toolchain_args")
    887     forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)
    888   }
    889 }
    890 
    891 # This is a shorthand for gcc_toolchain instances based on the Chromium-built
    892 # version of Clang. Only the toolchain_cpu and toolchain_os variables need to
    893 # be specified by the invoker, and optionally toolprefix if it's a
    894 # cross-compile case. Note that for a cross-compile case this toolchain
    895 # requires a config to pass the appropriate -target option, or else it will
    896 # actually just be doing a native compile.
    897 template("clang_toolchain") {
    898   gcc_toolchain(target_name) {
    899     _path = "$clang_base_path/bin"
    900     _is_path_absolute = get_path_info(_path, "abspath") == _path
    901 
    902     # Preserve absolute paths for tools like distcc.
    903     if (_is_path_absolute && filter_include([ _path ], [ "//*" ]) == []) {
    904       prefix = _path
    905     } else {
    906       prefix = rebase_path(_path, root_build_dir)
    907     }
    908 
    909     cc = "${prefix}/clang"
    910     cxx = "${prefix}/clang++"
    911     ld = cxx
    912     readelf = "${prefix}/llvm-readelf"
    913     ar = "${prefix}/llvm-ar"
    914     nm = "${prefix}/llvm-nm"
    915 
    916     forward_variables_from(invoker, "*", [ "toolchain_args" ])
    917 
    918     toolchain_args = {
    919       if (defined(invoker.toolchain_args)) {
    920         forward_variables_from(invoker.toolchain_args, "*")
    921       }
    922       is_clang = true
    923     }
    924   }
    925 }