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