tor-browser

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

toolchain.gni (33436B)


      1 # Copyright 2022 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/rust.gni")
      8 import("//chromium/build/config/sanitizers/sanitizers.gni")
      9 import("//chromium/build/config/win/visual_studio_version.gni")
     10 import("//chromium/build/toolchain/cc_wrapper.gni")
     11 import("//chromium/build/toolchain/rbe.gni")
     12 import("//chromium/build/toolchain/toolchain.gni")
     13 import("//chromium/build/toolchain/win/win_toolchain_data.gni")
     14 
     15 assert(is_win, "Should only be running on Windows")
     16 
     17 # This tool will is used as a wrapper for various commands below.
     18 _tool_wrapper_path =
     19     rebase_path("//chromium/build/toolchain/win/tool_wrapper.py", root_build_dir)
     20 
     21 if (host_os == "win") {
     22   _exe = ".exe"
     23 } else {
     24   _exe = ""
     25 }
     26 
     27 _clang_bin_path = rebase_path("$clang_base_path/bin", root_build_dir)
     28 
     29 # Makes a single MSVC toolchain.
     30 #
     31 # Parameters:
     32 #   environment: File name of environment file.
     33 #
     34 # You would also define a toolchain_args variable with at least these set:
     35 #   target_cpu: target_cpu to pass as a build arg
     36 #   current_os: current_os to pass as a build arg
     37 template("msvc_toolchain") {
     38   toolchain(target_name) {
     39     # When invoking this toolchain not as the default one, these args will be
     40     # passed to the build. They are ignored when this is the default toolchain.
     41     assert(defined(invoker.toolchain_args))
     42     toolchain_args = {
     43       forward_variables_from(invoker.toolchain_args, "*")
     44 
     45       # This value needs to be passed through unchanged.
     46       host_toolchain = host_toolchain
     47     }
     48 
     49     if (defined(toolchain_args.is_clang)) {
     50       toolchain_is_clang = toolchain_args.is_clang
     51     } else {
     52       toolchain_is_clang = is_clang
     53     }
     54 
     55     # When the invoker has explicitly overridden use_reclient or cc_wrapper in
     56     # the toolchain args, use those values, otherwise default to the global one.
     57     # This works because the only reasonable override that toolchains might
     58     # supply for these values are to force-disable them.
     59     if (defined(toolchain_args.use_reclient)) {
     60       toolchain_uses_reclient = toolchain_args.use_reclient
     61     } else {
     62       toolchain_uses_reclient = use_reclient
     63     }
     64     if (defined(toolchain_args.cc_wrapper)) {
     65       toolchain_cc_wrapper = toolchain_args.cc_wrapper
     66     } else {
     67       toolchain_cc_wrapper = cc_wrapper
     68     }
     69     assert(!(toolchain_cc_wrapper != "" && toolchain_uses_reclient),
     70            "re-client and cc_wrapper can't be used together.")
     71 
     72     if (toolchain_uses_reclient) {
     73       if (toolchain_is_clang) {
     74         cl_prefix = "${reclient_bin_dir}/rewrapper -cfg=${reclient_cc_cfg_file}${rbe_bug_326584510_missing_inputs} -exec_root=${rbe_exec_root} -labels=type=compile,compiler=clang-cl,lang=cpp "
     75       } else {
     76         cl_prefix = ""
     77       }
     78     } else if (toolchain_cc_wrapper != "" && toolchain_is_clang) {
     79       cl_prefix = toolchain_cc_wrapper + " "
     80     } else {
     81       cl_prefix = ""
     82     }
     83 
     84     cl = "${cl_prefix}${invoker.cl}"
     85     if (host_os == "win") {
     86       # Flip the slashes so that copy/paste of the command works.
     87       cl = string_replace(cl, "/", "\\")
     88     }
     89 
     90     # Make these apply to all tools below.
     91     lib_switch = ""
     92     lib_dir_switch = "/LIBPATH:"
     93 
     94     # Object files go in this directory.
     95     object_subdir = "{{target_out_dir}}/{{label_name}}"
     96 
     97     env = invoker.environment
     98 
     99     if (use_lld) {
    100       # lld-link includes a replacement for lib.exe that can produce thin
    101       # archives and understands bitcode (for lto builds).
    102       link = "${_clang_bin_path}/lld-link${_exe}"
    103       cc_linkflags = ""
    104       if (toolchain_has_rust) {
    105         rust_linkflags = ""
    106       }
    107       if (host_os == "win") {
    108         # Flip the slashes so that copy/paste of the commands works.
    109         link = string_replace(link, "/", "\\")
    110       }
    111       lib = "$link /lib"
    112       if (host_os != "win") {
    113         # See comment adding --rsp-quoting to $cl above for more information.
    114         cc_linkflags += " --rsp-quoting=posix"
    115         if (toolchain_has_rust) {
    116           rust_linkflags += " -Clink-arg=--rsp-quoting=posix"
    117         }
    118       }
    119     } else {
    120       lib = "lib.exe"
    121       link = "link.exe"
    122       cc_linkflags = ""
    123       if (toolchain_has_rust) {
    124         rust_linkflags = ""
    125       }
    126     }
    127 
    128     # If possible, pass system includes as flags to the compiler.  When that's
    129     # not possible, load a full environment file (containing %INCLUDE% and
    130     # %PATH%) -- e.g. 32-bit MSVS builds require %PATH% to be set and just
    131     # passing in a list of include directories isn't enough.
    132     if (defined(invoker.sys_include_flags)) {
    133       env_wrapper = ""
    134       sys_include_flags =
    135           "${invoker.sys_include_flags} "  # Note trailing space.
    136     } else {
    137       # clang-cl doesn't need this env hoop, so omit it there.
    138       assert(!toolchain_is_clang)
    139       env_wrapper = "ninja -t msvc -e $env -- "  # Note trailing space.
    140       sys_include_flags = ""
    141     }
    142 
    143     if (host_os != "win" || (use_lld && defined(invoker.sys_lib_flags))) {
    144       linker_wrapper = ""
    145       sys_lib_flags = "${invoker.sys_lib_flags}"
    146 
    147       # TODO(thakis): Remove once crbug.com/1300005 is fixed
    148       assert(toolchain_args.target_cpu == "x64" ||
    149                  toolchain_args.target_cpu == "x86" ||
    150                  toolchain_args.target_cpu == "arm" ||
    151                  toolchain_args.target_cpu == "arm64",
    152              "Only supports x64, x86, arm and arm64 CPUs")
    153       if (toolchain_args.target_cpu == "x64") {
    154         sys_lib_flags += " /MACHINE:X64"
    155       } else if (toolchain_args.target_cpu == "x86") {
    156         sys_lib_flags += " /MACHINE:X86"
    157       } else if (toolchain_args.target_cpu == "arm") {
    158         sys_lib_flags += " /MACHINE:ARM"
    159       } else if (toolchain_args.target_cpu == "arm64") {
    160         sys_lib_flags += " /MACHINE:ARM64"
    161       }
    162 
    163       sys_lib_flags += " "  # Note trailing space.
    164     } else {
    165       # link.exe must be run under a wrapper to set up the environment
    166       # (it needs %LIB% set to find libraries), and to work around its bugs.
    167       # Note trailing space:
    168       linker_wrapper =
    169           "\"$python_path\" $_tool_wrapper_path link-wrapper $env False "
    170       sys_lib_flags = ""
    171     }
    172 
    173     if (defined(toolchain_args.use_clang_coverage)) {
    174       toolchain_use_clang_coverage = toolchain_args.use_clang_coverage
    175     } else {
    176       toolchain_use_clang_coverage = use_clang_coverage
    177     }
    178 
    179     if (toolchain_use_clang_coverage) {
    180       assert(toolchain_is_clang,
    181              "use_clang_coverage should only be used with Clang")
    182       if (defined(toolchain_args.coverage_instrumentation_input_file)) {
    183         toolchain_coverage_instrumentation_input_file =
    184             toolchain_args.coverage_instrumentation_input_file
    185       } else {
    186         toolchain_coverage_instrumentation_input_file =
    187             coverage_instrumentation_input_file
    188       }
    189 
    190       coverage_wrapper =
    191           rebase_path("//chromium/build/toolchain/clang_code_coverage_wrapper.py",
    192                       root_build_dir)
    193       coverage_wrapper = coverage_wrapper + " --target-os=" + target_os
    194       if (toolchain_coverage_instrumentation_input_file != "") {
    195         coverage_wrapper =
    196             coverage_wrapper + " --files-to-instrument=" +
    197             rebase_path(toolchain_coverage_instrumentation_input_file,
    198                         root_build_dir)
    199       }
    200       coverage_wrapper = "\"$python_path\" " + coverage_wrapper + " "
    201     } else {
    202       coverage_wrapper = ""
    203     }
    204 
    205     # Disabled with cc_wrapper because of
    206     # https://github.com/mozilla/sccache/issues/1013
    207     if (toolchain_is_clang && toolchain_cc_wrapper == "") {
    208       # This flag omits system includes from /showIncludes output, to reduce
    209       # the amount of data to parse and store in .ninja_deps. We do this on
    210       # non-Windows too, and already make sure rebuilds after winsdk/libc++/
    211       # clang header updates happen via changing command line flags.
    212       show_includes = "/showIncludes:user"
    213     } else {
    214       show_includes = "/showIncludes"
    215     }
    216 
    217     tool("cc") {
    218       precompiled_header_type = "msvc"
    219       pdbname = "{{target_out_dir}}/{{label_name}}_c.pdb"
    220 
    221       # Label names may have spaces in them so the pdbname must be quoted. The
    222       # source and output don't need to be quoted because GN knows they're a
    223       # full file name and will quote automatically when necessary.
    224       depsformat = "msvc"
    225       description = "CC {{output}}"
    226       outputs = [ "$object_subdir/{{source_name_part}}.obj" ]
    227 
    228       # Note that the code coverage wrapper scripts assumes that {{source}}
    229       # comes immediately after /c.
    230       command = "$coverage_wrapper$env_wrapper$cl /c {{source}} /nologo $show_includes $sys_include_flags{{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} /Fo{{output}} /Fd\"$pdbname\""
    231     }
    232 
    233     tool("cxx") {
    234       precompiled_header_type = "msvc"
    235 
    236       # The PDB name needs to be different between C and C++ compiled files.
    237       pdbname = "{{target_out_dir}}/{{label_name}}_cc.pdb"
    238 
    239       # See comment in CC tool about quoting.
    240       depsformat = "msvc"
    241       description = "CXX {{output}}"
    242       outputs = [ "$object_subdir/{{source_name_part}}.obj" ]
    243 
    244       # Note that the code coverage wrapper scripts assumes that {{source}}
    245       # comes immediately after /c.
    246       command = "$coverage_wrapper$env_wrapper$cl /c {{source}} /Fo{{output}} /nologo $show_includes $sys_include_flags{{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} /Fd\"$pdbname\""
    247     }
    248 
    249     tool("rc") {
    250       if (treat_warnings_as_errors) {
    251         werror = "-Werror "
    252       } else {
    253         werror = ""
    254       }
    255       command = "\"$python_path\" $_tool_wrapper_path rc-wrapper $env rc.exe /nologo $werror$sys_include_flags{{defines}} {{include_dirs}} /fo{{output}} {{source}}"
    256       depsformat = "msvc"
    257       outputs = [ "$object_subdir/{{source_name_part}}.res" ]
    258       description = "RC {{output}}"
    259     }
    260 
    261     tool("asm") {
    262       is_msvc_assembler = true
    263 
    264       if (toolchain_args.target_cpu == "arm64") {
    265         if (toolchain_is_clang) {
    266           ml = "${cl_prefix}${_clang_bin_path}/clang-cl${_exe} --target=aarch64-pc-windows"
    267           if (host_os == "win") {
    268             # Flip the slashes so that copy/paste of the command works.
    269             ml = string_replace(ml, "/", "\\")
    270           }
    271           ml += " -c -o{{output}} $show_includes"
    272           is_msvc_assembler = false
    273           depsformat = "msvc"
    274         } else {
    275           # Only affects Arm builds with is_clang = false, implemented for
    276           # building V8 for Windows on Arm systems with the MSVC toolchain.
    277           ml = "armasm64.exe"
    278         }
    279       } else {
    280         if (toolchain_is_clang && !disable_llvm_ml) {
    281           prefix = rebase_path("$clang_base_path/bin", root_build_dir)
    282           ml = "$prefix/llvm-ml${_exe}"
    283           if (toolchain_args.target_cpu == "x64") {
    284             ml += " -m64"
    285           } else {
    286             ml += " -m32"
    287           }
    288         } else {
    289           if (toolchain_args.target_cpu == "x64") {
    290             ml = "ml64.exe"
    291           } else {
    292             ml = "ml.exe"
    293           }
    294         }
    295       }
    296 
    297       if (is_msvc_assembler) {
    298         ml += " /nologo /Fo{{output}}"
    299 
    300         # Suppress final-stage linking on x64/x86 builds. (Armasm64 does not
    301         # require /c because it doesn't support linking.)
    302         if (toolchain_args.target_cpu != "arm64") {
    303           ml += " /c"
    304         }
    305         if (use_lld && (!toolchain_is_clang || disable_llvm_ml)) {
    306           # Wrap ml(64).exe with a script that makes its output deterministic.
    307           # It's lld only because the script zaps obj Timestamp which
    308           # link.exe /incremental looks at.
    309           ml_py = rebase_path("//chromium/build/toolchain/win/ml.py", root_build_dir)
    310           ml = "\"$python_path\" $ml_py $ml"
    311         }
    312 
    313         if (toolchain_args.target_cpu == "arm64") {
    314           # armasm64.exe does not support definitions passed via the command
    315           # line. (Fortunately, they're not needed for compiling the V8
    316           # snapshot, which is the only time this assembler is required.)
    317           command = "\"$python_path\" $_tool_wrapper_path asm-wrapper $env $ml {{include_dirs}} {{asmflags}} {{source}}"
    318         } else {
    319           command = "\"$python_path\" $_tool_wrapper_path asm-wrapper $env $ml {{defines}} {{include_dirs}} {{asmflags}} {{source}}"
    320         }
    321       } else {
    322         command = "$ml {{defines}} {{include_dirs}} {{asmflags}} {{source}}"
    323       }
    324 
    325       description = "ASM {{output}}"
    326       outputs = [ "$object_subdir/{{source_name_part}}.obj" ]
    327     }
    328 
    329     if (toolchain_has_rust) {
    330       rust_sysroot_relative = rebase_path(rust_sysroot, root_build_dir)
    331       rustc = "$rust_sysroot_relative/bin/rustc"
    332       rustc_wrapper =
    333           rebase_path("//chromium/build/rust/rustc_wrapper.py", root_build_dir)
    334       rustc_windows_args = " -Clinker=$link$rust_linkflags $rustc_common_args"
    335 
    336       tool("rust_staticlib") {
    337         libname = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
    338         rspfile = "$libname.rsp"
    339         depfile = "$libname.d"
    340 
    341         default_output_extension = ".lib"
    342         output_prefix = "lib"
    343 
    344         # Static libraries go in the target out directory by default so we can
    345         # generate different targets with the same name and not have them
    346         # collide.
    347         default_output_dir = "{{target_out_dir}}"
    348         description = "RUST(STATICLIB) {{output}}"
    349         outputs = [ libname ]
    350 
    351         rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}"
    352         command = "\"$python_path\" \"$rustc_wrapper\" --target-windows --rustc=$rustc --depfile=$depfile --rsp=$rspfile -- $rustc_windows_args --emit=dep-info=$depfile,link -o $libname LDFLAGS RUSTENV {{rustenv}}"
    353         rust_sysroot = rust_sysroot_relative
    354       }
    355 
    356       tool("rust_rlib") {
    357         # We must always prefix with `lib` even if the library already starts
    358         # with that prefix or else our stdlib is unable to find libc.rlib (or
    359         # actually liblibc.rlib).
    360         rlibname =
    361             "{{output_dir}}/lib{{target_output_name}}{{output_extension}}"
    362         rspfile = "$rlibname.rsp"
    363         depfile = "$rlibname.d"
    364 
    365         default_output_extension = ".rlib"
    366 
    367         # This is prefixed unconditionally in `rlibname`.
    368         # output_prefix = "lib"
    369 
    370         # Static libraries go in the target out directory by default so we can
    371         # generate different targets with the same name and not have them
    372         # collide.
    373         default_output_dir = "{{target_out_dir}}"
    374         description = "RUST {{output}}"
    375         outputs = [ rlibname ]
    376 
    377         rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}"
    378         command = "\"$python_path\" \"$rustc_wrapper\" --target-windows --rustc=$rustc --depfile=$depfile --rsp=$rspfile -- $rustc_windows_args --emit=dep-info=$depfile,link -o $rlibname {{rustdeps}} {{externs}} LDFLAGS RUSTENV {{rustenv}}"
    379         rust_sysroot = rust_sysroot_relative
    380       }
    381 
    382       tool("rust_bin") {
    383         exename = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
    384         pdbname = "$exename.pdb"
    385         rspfile = "$exename.rsp"
    386         depfile = "$exename.d"
    387         pool = "//chromium/build/toolchain:link_pool($default_toolchain)"
    388 
    389         default_output_extension = ".exe"
    390         default_output_dir = "{{root_out_dir}}"
    391         description = "RUST(BIN) {{output}}"
    392         outputs = [
    393           # The first entry here is used for dependency tracking.
    394           exename,
    395           pdbname,
    396         ]
    397         runtime_outputs = outputs
    398 
    399         rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}"
    400         dynamic_link_switch = ""
    401         command = "\"$python_path\" \"$rustc_wrapper\" --target-windows --rustc=$rustc --depfile=$depfile --rsp=$rspfile -- $rustc_windows_args --emit=dep-info=$depfile,link -o $exename LDFLAGS {{ldflags}} $sys_lib_flags /PDB:$pdbname RUSTENV {{rustenv}}"
    402         rust_sysroot = rust_sysroot_relative
    403       }
    404 
    405       tool("rust_cdylib") {
    406         # E.g. "foo.dll":
    407         dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
    408         libname = "$dllname.lib"  # e.g. foo.dll.lib
    409         pdbname = "$dllname.pdb"
    410         rspfile = "$dllname.rsp"
    411         depfile = "$dllname.d"
    412         pool = "//chromium/build/toolchain:link_pool($default_toolchain)"
    413 
    414         default_output_extension = ".dll"
    415         default_output_dir = "{{root_out_dir}}"
    416         description = "RUST(CDYLIB) {{output}}"
    417         outputs = [
    418           # The first entry here is used for dependency tracking. Dylibs are
    419           # linked into other targets and that linking must be done through
    420           # the .lib file, not the .dll file. So the .lib file is the primary
    421           # output here.
    422           libname,
    423           dllname,
    424           pdbname,
    425         ]
    426         runtime_outputs = [
    427           dllname,
    428           pdbname,
    429         ]
    430 
    431         rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}"
    432         dynamic_link_switch = ""
    433         command = "\"$python_path\" \"$rustc_wrapper\" --target-windows --rustc=$rustc --depfile=$depfile --rsp=$rspfile -- $rustc_windows_args --emit=dep-info=$depfile,link -o $dllname LDFLAGS {{ldflags}} $sys_lib_flags /PDB:$pdbname /IMPLIB:$libname RUSTENV {{rustenv}}"
    434         rust_sysroot = rust_sysroot_relative
    435 
    436         # Since the above commands only updates the .lib file when it changes,
    437         # ask Ninja to check if the timestamp actually changed to know if
    438         # downstream dependencies should be recompiled.
    439         restat = true
    440       }
    441 
    442       tool("rust_macro") {
    443         # E.g. "foo.dll":
    444         dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
    445         pdbname = "$dllname.pdb"
    446         rspfile = "$dllname.rsp"
    447         depfile = "$dllname.d"
    448         pool = "//chromium/build/toolchain:link_pool($default_toolchain)"
    449 
    450         default_output_extension = ".dll"
    451         default_output_dir = "{{root_out_dir}}"
    452         description = "RUST(MACRO) {{output}}"
    453         outputs = [
    454           # The first entry here is used for dependency tracking. Proc macros
    455           # are consumed as dlls directly, loaded a runtime, so the dll is the
    456           # primary output here. If we make a .lib file the primary output, we
    457           # end up trying to load the .lib file as a procmacro which fails.
    458           #
    459           # Since depending on a macro target for linking would fail (it would
    460           # try to link primary .dll target) we omit the .lib here entirely.
    461           dllname,
    462           pdbname,
    463         ]
    464         runtime_outputs = outputs
    465 
    466         rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}"
    467         dynamic_link_switch = ""
    468         command = "\"$python_path\" \"$rustc_wrapper\" --target-windows --rustc=$rustc --depfile=$depfile --rsp=$rspfile -- $rustc_windows_args --emit=dep-info=$depfile,link -o $dllname LDFLAGS {{ldflags}} $sys_lib_flags /PDB:$pdbname RUSTENV {{rustenv}}"
    469         rust_sysroot = rust_sysroot_relative
    470 
    471         # Since the above commands only updates the .lib file when it changes,
    472         # ask Ninja to check if the timestamp actually changed to know if
    473         # downstream dependencies should be recompiled.
    474         restat = true
    475       }
    476     }
    477 
    478     tool("alink") {
    479       rspfile = "{{output}}.rsp"
    480       command = "$linker_wrapper$lib \"/OUT:{{output}}\" /nologo {{arflags}} \"@$rspfile\""
    481       description = "LIB {{output}}"
    482       outputs = [
    483         # Ignore {{output_extension}} and always use .lib, there's no reason to
    484         # allow targets to override this extension on Windows.
    485         "{{output_dir}}/{{target_output_name}}.lib",
    486       ]
    487       default_output_extension = ".lib"
    488       default_output_dir = "{{target_out_dir}}"
    489 
    490       # The use of inputs_newline is to work around a fixed per-line buffer
    491       # size in the linker.
    492       rspfile_content = "{{inputs_newline}}"
    493     }
    494 
    495     tool("solink") {
    496       # E.g. "foo.dll":
    497       dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
    498       libname = "${dllname}.lib"  # e.g. foo.dll.lib
    499       pdbname = "${dllname}.pdb"
    500       rspfile = "${dllname}.rsp"
    501       pool = "//chromium/build/toolchain:link_pool($default_toolchain)"
    502 
    503       command = "$linker_wrapper$link$cc_linkflags \"/OUT:$dllname\" /nologo ${sys_lib_flags} \"/IMPLIB:$libname\" /DLL \"/PDB:$pdbname\" \"@$rspfile\""
    504 
    505       default_output_extension = ".dll"
    506       default_output_dir = "{{root_out_dir}}"
    507       description = "LINK(DLL) {{output}}"
    508       outputs = [
    509         dllname,
    510         libname,
    511         pdbname,
    512       ]
    513       link_output = libname
    514       depend_output = libname
    515       runtime_outputs = [
    516         dllname,
    517         pdbname,
    518       ]
    519 
    520       # Since the above commands only updates the .lib file when it changes,
    521       # ask Ninja to check if the timestamp actually changed to know if
    522       # downstream dependencies should be recompiled.
    523       restat = true
    524 
    525       # The use of inputs_newline is to work around a fixed per-line buffer
    526       # size in the linker.
    527       rspfile_content =
    528           "{{libs}} {{solibs}} {{inputs_newline}} {{ldflags}} {{rlibs}}"
    529     }
    530 
    531     tool("solink_module") {
    532       # E.g. "foo.dll":
    533       dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
    534       pdbname = "${dllname}.pdb"
    535       rspfile = "${dllname}.rsp"
    536       pool = "//chromium/build/toolchain:link_pool($default_toolchain)"
    537 
    538       command = "$linker_wrapper$link$cc_linkflags \"/OUT:$dllname\" /nologo ${sys_lib_flags} /DLL \"/PDB:$pdbname\" \"@$rspfile\""
    539 
    540       default_output_extension = ".dll"
    541       default_output_dir = "{{root_out_dir}}"
    542       description = "LINK_MODULE(DLL) {{output}}"
    543       outputs = [
    544         dllname,
    545         pdbname,
    546       ]
    547       runtime_outputs = outputs
    548 
    549       # The use of inputs_newline is to work around a fixed per-line buffer
    550       # size in the linker.
    551       rspfile_content =
    552           "{{libs}} {{solibs}} {{inputs_newline}} {{ldflags}} {{rlibs}}"
    553     }
    554 
    555     tool("link") {
    556       exename = "{{output_dir}}/{{target_output_name}}{{output_extension}}"
    557       pdbname = "$exename.pdb"
    558       rspfile = "$exename.rsp"
    559       pool = "//chromium/build/toolchain:link_pool($default_toolchain)"
    560 
    561       command = "$linker_wrapper$link$cc_linkflags \"/OUT:$exename\" /nologo ${sys_lib_flags} \"/PDB:$pdbname\" \"@$rspfile\""
    562 
    563       default_output_extension = ".exe"
    564       default_output_dir = "{{root_out_dir}}"
    565       description = "LINK {{output}}"
    566       outputs = [
    567         exename,
    568         pdbname,
    569       ]
    570       runtime_outputs = outputs
    571 
    572       # The use of inputs_newline is to work around a fixed per-line buffer
    573       # size in the linker.
    574       rspfile_content =
    575           "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}} {{rlibs}}"
    576     }
    577 
    578     # These two are really entirely generic, but have to be repeated in
    579     # each toolchain because GN doesn't allow a template to be used here.
    580     # See //build/toolchain/toolchain.gni for details.
    581     tool("stamp") {
    582       command = stamp_command
    583       description = stamp_description
    584       pool = "//chromium/build/toolchain:action_pool($default_toolchain)"
    585     }
    586     tool("copy") {
    587       command = copy_command
    588       description = copy_description
    589       pool = "//chromium/build/toolchain:action_pool($default_toolchain)"
    590     }
    591 
    592     tool("action") {
    593       pool = "//chromium/build/toolchain:action_pool($default_toolchain)"
    594     }
    595   }
    596 }
    597 
    598 # Make an additional toolchain which is used for making tools that are run
    599 # on the host machine as part of the build process (such as proc macros
    600 # and Cargo build scripts). This toolchain uses the prebuilt stdlib that
    601 # comes with the compiler, so it doesn't have to wait for the stdlib to be
    602 # built before building other stuff. And this ensures its proc macro
    603 # outputs have the right ABI to be loaded by the compiler, and it can be
    604 # used to compile build scripts that are part of the stdlib that is built
    605 # for the default toolchain.
    606 template("msvc_rust_host_build_tools_toolchain") {
    607   msvc_toolchain(target_name) {
    608     assert(defined(invoker.toolchain_args))
    609     forward_variables_from(invoker,
    610                            "*",
    611                            [
    612                              "toolchain_args",
    613                              "visibility",
    614                              "testonly",
    615                            ])
    616     toolchain_args = {
    617       # Populate toolchain args from the invoker.
    618       forward_variables_from(invoker.toolchain_args, "*")
    619       toolchain_for_rust_host_build_tools = true
    620 
    621       # The host build tools are static release builds to make the Chromium
    622       # build faster. They do not need PGO etc, so no official builds.
    623       is_debug = false
    624       is_component_build = false
    625       is_official_build = false
    626       use_clang_coverage = false
    627       use_sanitizer_coverage = false
    628       generate_linker_map = false
    629       use_thin_lto = false
    630     }
    631   }
    632 }
    633 
    634 # If PartitionAlloc is part of the build (even as a transitive dependency), then
    635 # it replaces the system allocator. If this toolchain is used, that will be
    636 # overridden and the system allocator will be used regardless. This is important
    637 # in some third-party binaries outside of Chrome.
    638 template("msvc_system_allocator_toolchain") {
    639   msvc_toolchain(target_name) {
    640     assert(defined(invoker.toolchain_args))
    641     forward_variables_from(invoker,
    642                            "*",
    643                            [
    644                              "toolchain_args",
    645                              "visibility",
    646                              "testonly",
    647                            ])
    648     toolchain_args = {
    649       # Populate toolchain args from the invoker.
    650       forward_variables_from(invoker.toolchain_args, "*")
    651       toolchain_allows_use_partition_alloc_as_malloc = false
    652 
    653       # Disable component build so that we can copy the exes to the
    654       # root_build_dir and support the default_toolchain redirection on Windows.
    655       # See also the comment in //build/symlink.gni.
    656       is_component_build = false
    657 
    658       # Only one toolchain can be configured with MSAN support with our current
    659       # GN setup, or they all try to make the instrumented libraries and
    660       # collide.
    661       is_msan = false
    662     }
    663   }
    664 }
    665 
    666 template("win_toolchains") {
    667   # On Windows, cross-compile for x86 changes the `host_toolchain`
    668   # into x86 too so as to avoid compiling things twice (see
    669   # //build/config/BUILDCONFIG.gn). But the prebuilt stdlib does not
    670   # exist for Windows x86 and it's exceedingly difficult to get it
    671   # built from a single build_rust.py invocation. So we just don't follow
    672   # along in the `build_tools_toolchain` toolchains, and always use the host
    673   # cpu type (which will be x64 in that case). Things built with these
    674   # toolchains are never built for the target_cpu anyhow, so the optimization
    675   # there does not benefit them.
    676   #
    677   # Thus, in build_tools_toolchain, for the host machine:
    678   # * Use `rust_host_toolchain_arch` instead of `toolchain_arch`.
    679   # * Use `rust_host_win_toolchain_data` instead of `win_toolchain_data`.
    680 
    681   assert(defined(invoker.toolchain_arch))
    682   toolchain_arch = invoker.toolchain_arch
    683   rust_host_toolchain_arch = host_cpu
    684 
    685   # The toolchain data for `msvc_toolchain()`.
    686   if (toolchain_arch == "x86") {
    687     win_toolchain_data = win_toolchain_data_x86
    688   } else if (toolchain_arch == "x64") {
    689     win_toolchain_data = win_toolchain_data_x64
    690   } else if (toolchain_arch == "arm64") {
    691     win_toolchain_data = win_toolchain_data_arm64
    692   } else {
    693     error("Unsupported toolchain_arch, add it to win_toolchain_data.gni")
    694   }
    695 
    696   # The toolchain data for `build_tools_toolchain` for the host machine.
    697   if (rust_host_toolchain_arch == "x86") {
    698     rust_host_win_toolchain_data = win_toolchain_data_x86
    699   } else if (rust_host_toolchain_arch == "x64") {
    700     rust_host_win_toolchain_data = win_toolchain_data_x64
    701   } else if (rust_host_toolchain_arch == "arm64") {
    702     rust_host_win_toolchain_data = win_toolchain_data_arm64
    703   } else {
    704     error(
    705         "Unsupported rust_host_toolchain_arch, add it to win_toolchain_data.gni")
    706   }
    707 
    708   # The toolchain using MSVC only makes sense when not doing cross builds.
    709   # Chromium exclusively uses the win_clang_ toolchain below, but V8 and
    710   # WebRTC still use this MSVC toolchain in some cases.
    711   if (host_os == "win") {
    712     if (defined(invoker.cl_toolchain_prefix)) {
    713       cl_toolchain_prefix = invoker.cl_toolchain_prefix
    714     } else {
    715       cl_toolchain_prefix = ""
    716     }
    717     msvc_toolchain(cl_toolchain_prefix + target_name) {
    718       environment = "environment." + toolchain_arch
    719       cl = "\"${win_toolchain_data.vc_bin_dir}/cl.exe\""
    720 
    721       toolchain_args = {
    722         if (defined(invoker.toolchain_args)) {
    723           forward_variables_from(invoker.toolchain_args, "*")
    724         }
    725         is_clang = false
    726         use_clang_coverage = false
    727         current_os = "win"
    728         target_cpu = toolchain_arch
    729       }
    730     }
    731     msvc_system_allocator_toolchain(
    732         cl_toolchain_prefix + target_name + "_host_with_system_allocator") {
    733       environment = "environment." + rust_host_toolchain_arch
    734       cl = "\"${rust_host_win_toolchain_data.vc_bin_dir}/cl.exe\""
    735 
    736       toolchain_args = {
    737         if (defined(invoker.toolchain_args)) {
    738           forward_variables_from(invoker.toolchain_args, "*")
    739         }
    740         is_clang = false
    741         use_clang_coverage = false
    742         current_os = "win"
    743         target_cpu = rust_host_toolchain_arch
    744       }
    745     }
    746     msvc_system_allocator_toolchain(
    747         cl_toolchain_prefix + target_name + "_with_system_allocator") {
    748       environment = "environment." + toolchain_arch
    749       cl = "\"${win_toolchain_data.vc_bin_dir}/cl.exe\""
    750 
    751       toolchain_args = {
    752         if (defined(invoker.toolchain_args)) {
    753           forward_variables_from(invoker.toolchain_args, "*")
    754         }
    755         is_clang = false
    756         use_clang_coverage = false
    757         current_os = "win"
    758         target_cpu = toolchain_arch
    759       }
    760     }
    761     msvc_rust_host_build_tools_toolchain(
    762         cl_toolchain_prefix + target_name + "_for_rust_host_build_tools") {
    763       environment = "environment." + rust_host_toolchain_arch
    764       cl = "\"${rust_host_win_toolchain_data.vc_bin_dir}/cl.exe\""
    765 
    766       toolchain_args = {
    767         if (defined(invoker.toolchain_args)) {
    768           forward_variables_from(invoker.toolchain_args, "*")
    769         }
    770         is_clang = false
    771         use_clang_coverage = false
    772         current_os = "win"
    773         target_cpu = rust_host_toolchain_arch
    774       }
    775     }
    776   }
    777 
    778   if (defined(invoker.clang_toolchain_prefix)) {
    779     clang_toolchain_prefix = invoker.clang_toolchain_prefix
    780   } else {
    781     clang_toolchain_prefix = "win_clang_"
    782   }
    783 
    784   if (use_lld) {
    785     _clang_lib_dir =
    786         rebase_path("$clang_base_path/lib/clang/$clang_version/lib/windows",
    787                     root_build_dir)
    788   }
    789 
    790   msvc_toolchain(clang_toolchain_prefix + target_name) {
    791     environment = "environment." + toolchain_arch
    792     cl = "${_clang_bin_path}/clang-cl${_exe}"
    793 
    794     sys_include_flags = "${win_toolchain_data.include_flags_imsvc}"
    795     if (use_lld) {
    796       sys_lib_flags = "-libpath:$_clang_lib_dir " +
    797                       "${win_toolchain_data.libpath_lldlink_flags}"
    798     }
    799 
    800     toolchain_args = {
    801       if (defined(invoker.toolchain_args)) {
    802         forward_variables_from(invoker.toolchain_args, "*")
    803       }
    804       is_clang = true
    805       current_os = "win"
    806       target_cpu = toolchain_arch
    807     }
    808   }
    809   msvc_system_allocator_toolchain(
    810       clang_toolchain_prefix + target_name + "_host_with_system_allocator") {
    811     environment = "environment." + rust_host_toolchain_arch
    812     cl = "${_clang_bin_path}/clang-cl${_exe}"
    813 
    814     sys_include_flags = "${rust_host_win_toolchain_data.include_flags_imsvc}"
    815     if (use_lld) {
    816       sys_lib_flags = "-libpath:$_clang_lib_dir " +
    817                       "${rust_host_win_toolchain_data.libpath_lldlink_flags}"
    818     }
    819 
    820     toolchain_args = {
    821       if (defined(invoker.toolchain_args)) {
    822         forward_variables_from(invoker.toolchain_args, "*")
    823       }
    824       is_clang = true
    825       current_os = "win"
    826       target_cpu = rust_host_toolchain_arch
    827     }
    828   }
    829   msvc_system_allocator_toolchain(
    830       clang_toolchain_prefix + target_name + "_with_system_allocator") {
    831     environment = "environment." + toolchain_arch
    832     cl = "${_clang_bin_path}/clang-cl${_exe}"
    833 
    834     sys_include_flags = "${win_toolchain_data.include_flags_imsvc}"
    835     if (use_lld) {
    836       sys_lib_flags = "-libpath:$_clang_lib_dir " +
    837                       "${win_toolchain_data.libpath_lldlink_flags}"
    838     }
    839 
    840     toolchain_args = {
    841       if (defined(invoker.toolchain_args)) {
    842         forward_variables_from(invoker.toolchain_args, "*")
    843       }
    844       is_clang = true
    845       current_os = "win"
    846       target_cpu = toolchain_arch
    847     }
    848   }
    849   msvc_rust_host_build_tools_toolchain(
    850       clang_toolchain_prefix + target_name + "_for_rust_host_build_tools") {
    851     environment = "environment." + rust_host_toolchain_arch
    852     cl = "${_clang_bin_path}/clang-cl${_exe}"
    853 
    854     sys_include_flags = "${rust_host_win_toolchain_data.include_flags_imsvc}"
    855     if (use_lld) {
    856       sys_lib_flags = "-libpath:$_clang_lib_dir " +
    857                       "${rust_host_win_toolchain_data.libpath_lldlink_flags}"
    858     }
    859 
    860     toolchain_args = {
    861       if (defined(invoker.toolchain_args)) {
    862         forward_variables_from(invoker.toolchain_args, "*")
    863       }
    864       is_clang = true
    865       current_os = "win"
    866       target_cpu = rust_host_toolchain_arch
    867     }
    868   }
    869 }