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} -labels=type=compile,compiler=clang-cl,lang=cpp " 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") { 320 # armasm64.exe does not support definitions passed via the command 321 # line. (Fortunately, they're not needed for compiling the V8 322 # snapshot, which is the only time this assembler is required.) 323 command = "\"$python_path\" $_tool_wrapper_path asm-wrapper $env $ml {{include_dirs}} {{asmflags}} {{source}}" 324 } else { 325 command = "\"$python_path\" $_tool_wrapper_path asm-wrapper $env $ml {{defines}} {{include_dirs}} {{asmflags}} {{source}}" 326 } 327 } else { 328 command = "$ml {{defines}} {{include_dirs}} {{asmflags}} {{source}}" 329 } 330 331 description = "ASM {{output}}" 332 outputs = [ "$object_subdir/{{source_name_part}}.obj" ] 333 } 334 335 if (toolchain_has_rust) { 336 rust_sysroot_relative = rebase_path(rust_sysroot, root_build_dir) 337 rustc = "$rust_sysroot_relative/bin/rustc" 338 rustc_wrapper = 339 rebase_path("//build/rust/rustc_wrapper.py", root_build_dir) 340 rustc_windows_args = " -Clinker=$link$rust_linkflags $rustc_common_args" 341 342 tool("rust_staticlib") { 343 libname = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 344 rspfile = "$libname.rsp" 345 depfile = "$libname.d" 346 347 default_output_extension = ".lib" 348 output_prefix = "lib" 349 default_output_dir = "{{root_out_dir}}" 350 description = "RUST(STATICLIB) {{output}}" 351 outputs = [ libname ] 352 353 rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}" 354 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}}" 355 rust_sysroot = rust_sysroot_relative 356 } 357 358 tool("rust_rlib") { 359 # We must always prefix with `lib` even if the library already starts 360 # with that prefix or else our stdlib is unable to find libc.rlib (or 361 # actually liblibc.rlib). 362 rlibname = 363 "{{output_dir}}/lib{{target_output_name}}{{output_extension}}" 364 rspfile = "$rlibname.rsp" 365 depfile = "$rlibname.d" 366 367 default_output_extension = ".rlib" 368 369 # This is prefixed unconditionally in `rlibname`. 370 # output_prefix = "lib" 371 default_output_dir = "{{root_out_dir}}" 372 description = "RUST {{output}}" 373 outputs = [ rlibname ] 374 375 rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}" 376 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}}" 377 rust_sysroot = rust_sysroot_relative 378 } 379 380 tool("rust_bin") { 381 exename = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 382 pdbname = "$exename.pdb" 383 rspfile = "$exename.rsp" 384 depfile = "$exename.d" 385 pool = "//build/toolchain:link_pool($default_toolchain)" 386 387 default_output_extension = ".exe" 388 default_output_dir = "{{root_out_dir}}" 389 description = "RUST(BIN) {{output}}" 390 outputs = [ 391 # The first entry here is used for dependency tracking. 392 exename, 393 pdbname, 394 ] 395 runtime_outputs = outputs 396 397 rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}" 398 dynamic_link_switch = "" 399 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}}" 400 rust_sysroot = rust_sysroot_relative 401 } 402 403 tool("rust_cdylib") { 404 # E.g. "foo.dll": 405 dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 406 libname = "$dllname.lib" # e.g. foo.dll.lib 407 pdbname = "$dllname.pdb" 408 rspfile = "$dllname.rsp" 409 depfile = "$dllname.d" 410 pool = "//build/toolchain:link_pool($default_toolchain)" 411 412 default_output_extension = ".dll" 413 default_output_dir = "{{root_out_dir}}" 414 description = "RUST(CDYLIB) {{output}}" 415 outputs = [ 416 # The first entry here is used for dependency tracking. Dylibs are 417 # linked into other targets and that linking must be done through 418 # the .lib file, not the .dll file. So the .lib file is the primary 419 # output here. 420 libname, 421 dllname, 422 pdbname, 423 ] 424 runtime_outputs = [ 425 dllname, 426 pdbname, 427 ] 428 429 rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}" 430 dynamic_link_switch = "" 431 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}}" 432 rust_sysroot = rust_sysroot_relative 433 434 # Since the above commands only updates the .lib file when it changes, 435 # ask Ninja to check if the timestamp actually changed to know if 436 # downstream dependencies should be recompiled. 437 restat = true 438 } 439 440 tool("rust_macro") { 441 # E.g. "foo.dll": 442 dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 443 pdbname = "$dllname.pdb" 444 rspfile = "$dllname.rsp" 445 depfile = "$dllname.d" 446 pool = "//build/toolchain:link_pool($default_toolchain)" 447 448 default_output_extension = ".dll" 449 default_output_dir = "{{root_out_dir}}" 450 description = "RUST(MACRO) {{output}}" 451 outputs = [ 452 # The first entry here is used for dependency tracking. Proc macros 453 # are consumed as dlls directly, loaded a runtime, so the dll is the 454 # primary output here. If we make a .lib file the primary output, we 455 # end up trying to load the .lib file as a procmacro which fails. 456 # 457 # Since depending on a macro target for linking would fail (it would 458 # try to link primary .dll target) we omit the .lib here entirely. 459 dllname, 460 pdbname, 461 ] 462 runtime_outputs = outputs 463 464 rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}" 465 dynamic_link_switch = "" 466 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}}" 467 rust_sysroot = rust_sysroot_relative 468 469 # Since the above commands only updates the .lib file when it changes, 470 # ask Ninja to check if the timestamp actually changed to know if 471 # downstream dependencies should be recompiled. 472 restat = true 473 } 474 } 475 476 tool("alink") { 477 rspfile = "{{output}}.rsp" 478 command = "$linker_wrapper$lib \"/OUT:{{output}}\" /nologo {{arflags}} \"@$rspfile\"" 479 description = "LIB {{output}}" 480 outputs = [ 481 # Ignore {{output_extension}} and always use .lib, there's no reason to 482 # allow targets to override this extension on Windows. 483 "{{output_dir}}/{{target_output_name}}.lib", 484 ] 485 default_output_extension = ".lib" 486 default_output_dir = "{{target_out_dir}}" 487 488 # The use of inputs_newline is to work around a fixed per-line buffer 489 # size in the linker. 490 rspfile_content = "{{inputs_newline}}" 491 } 492 493 tool("solink") { 494 # E.g. "foo.dll": 495 dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 496 libname = "${dllname}.lib" # e.g. foo.dll.lib 497 pdbname = "${dllname}.pdb" 498 rspfile = "${dllname}.rsp" 499 pool = "//build/toolchain:link_pool($default_toolchain)" 500 501 command = "$linker_wrapper$link$cc_linkflags \"/OUT:$dllname\" /nologo ${sys_lib_flags} \"/IMPLIB:$libname\" /DLL \"/PDB:$pdbname\" \"@$rspfile\"" 502 503 default_output_extension = ".dll" 504 default_output_dir = "{{root_out_dir}}" 505 description = "LINK(DLL) {{output}}" 506 outputs = [ 507 dllname, 508 libname, 509 pdbname, 510 ] 511 link_output = libname 512 depend_output = libname 513 runtime_outputs = [ 514 dllname, 515 pdbname, 516 ] 517 518 # Since the above commands only updates the .lib file when it changes, 519 # ask Ninja to check if the timestamp actually changed to know if 520 # downstream dependencies should be recompiled. 521 restat = true 522 523 # The use of inputs_newline is to work around a fixed per-line buffer 524 # size in the linker. 525 rspfile_content = 526 "{{libs}} {{solibs}} {{inputs_newline}} {{ldflags}} {{rlibs}}" 527 } 528 529 tool("solink_module") { 530 # E.g. "foo.dll": 531 dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 532 pdbname = "${dllname}.pdb" 533 rspfile = "${dllname}.rsp" 534 pool = "//build/toolchain:link_pool($default_toolchain)" 535 536 command = "$linker_wrapper$link$cc_linkflags \"/OUT:$dllname\" /nologo ${sys_lib_flags} /DLL \"/PDB:$pdbname\" \"@$rspfile\"" 537 538 default_output_extension = ".dll" 539 default_output_dir = "{{root_out_dir}}" 540 description = "LINK_MODULE(DLL) {{output}}" 541 outputs = [ 542 dllname, 543 pdbname, 544 ] 545 runtime_outputs = outputs 546 547 # The use of inputs_newline is to work around a fixed per-line buffer 548 # size in the linker. 549 rspfile_content = 550 "{{libs}} {{solibs}} {{inputs_newline}} {{ldflags}} {{rlibs}}" 551 } 552 553 tool("link") { 554 exename = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 555 pdbname = "$exename.pdb" 556 rspfile = "$exename.rsp" 557 pool = "//build/toolchain:link_pool($default_toolchain)" 558 559 command = "$linker_wrapper$link$cc_linkflags \"/OUT:$exename\" /nologo ${sys_lib_flags} \"/PDB:$pdbname\" \"@$rspfile\"" 560 561 default_output_extension = ".exe" 562 default_output_dir = "{{root_out_dir}}" 563 description = "LINK {{output}}" 564 outputs = [ 565 exename, 566 pdbname, 567 ] 568 runtime_outputs = outputs 569 570 # The use of inputs_newline is to work around a fixed per-line buffer 571 # size in the linker. 572 rspfile_content = 573 "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}} {{rlibs}}" 574 } 575 576 # These two are really entirely generic, but have to be repeated in 577 # each toolchain because GN doesn't allow a template to be used here. 578 # See //build/toolchain/toolchain.gni for details. 579 tool("stamp") { 580 command = stamp_command 581 description = stamp_description 582 pool = "//build/toolchain:action_pool($default_toolchain)" 583 } 584 tool("copy") { 585 command = copy_command 586 description = copy_description 587 pool = "//build/toolchain:action_pool($default_toolchain)" 588 } 589 590 tool("action") { 591 pool = "//build/toolchain:action_pool($default_toolchain)" 592 } 593 } 594} 595 596template("msvc_rust_host_build_tools_toolchain") { 597 assert(defined(invoker.toolchain_args)) 598 if (enable_rust) { 599 msvc_toolchain("${target_name}_for_rust_host_build_tools") { 600 forward_variables_from(invoker, 601 "*", 602 [ 603 "toolchain_args", 604 "visibility", 605 "testonly", 606 ]) 607 toolchain_args = { 608 # Populate toolchain args from the invoker. 609 forward_variables_from(invoker.toolchain_args, "*") 610 toolchain_for_rust_host_build_tools = true 611 612 # The host build tools are static release builds to make the Chromium 613 # build faster. They do not need PGO etc, so no official builds. 614 is_debug = false 615 is_component_build = false 616 is_official_build = false 617 use_clang_coverage = false 618 use_sanitizer_coverage = false 619 generate_linker_map = false 620 } 621 } 622 } else { 623 not_needed(invoker, "*") 624 not_needed([ "target_name" ]) 625 } 626} 627 628template("win_toolchains") { 629 # On Windows, cross-compile for x86 changes the `host_toolchain` 630 # into x86 too so as to avoid compiling things twice (see 631 # //build/config/BUILDCONFIG.gn). But the prebuilt stdlib does not 632 # exist for Windows x86 and it's exceedingly difficult to get it 633 # built from a single build_rust.py invocation. So we just don't follow 634 # along in the `msvc_rust_host_build_tools_toolchain` toolchains, and 635 # always use the host cpu type (which will be x64 in that case). Things 636 # built with these toolchains are never built for the target_cpu anyhow, 637 # so the optimization there does not benefit them. 638 # 639 # Thus, in msvc_rust_host_build_tools_toolchain: 640 # * Use `rust_host_toolchain_arch` instead of `toolchain_arch`. 641 # * Use `rust_host_win_toolchain_data` instead of `win_toolchain_data`. 642 643 assert(defined(invoker.toolchain_arch)) 644 toolchain_arch = invoker.toolchain_arch 645 rust_host_toolchain_arch = host_cpu 646 647 # The toolchain data for `msvc_toolchain()`. 648 if (toolchain_arch == "x86") { 649 win_toolchain_data = win_toolchain_data_x86 650 } else if (toolchain_arch == "x64") { 651 win_toolchain_data = win_toolchain_data_x64 652 } else if (toolchain_arch == "arm64") { 653 win_toolchain_data = win_toolchain_data_arm64 654 } else { 655 error("Unsupported toolchain_arch, add it to win_toolchain_data.gni") 656 } 657 658 # The toolchain data for `msvc_rust_host_build_tools_toolchain()`. 659 if (rust_host_toolchain_arch == "x86") { 660 rust_host_win_toolchain_data = win_toolchain_data_x86 661 } else if (rust_host_toolchain_arch == "x64") { 662 rust_host_win_toolchain_data = win_toolchain_data_x64 663 } else if (rust_host_toolchain_arch == "arm64") { 664 rust_host_win_toolchain_data = win_toolchain_data_arm64 665 } else { 666 error( 667 "Unsupported rust_host_toolchain_arch, add it to win_toolchain_data.gni") 668 } 669 670 # The toolchain using MSVC only makes sense when not doing cross builds. 671 # Chromium exclusively uses the win_clang_ toolchain below, but V8 and 672 # WebRTC still use this MSVC toolchain in some cases. 673 if (host_os == "win") { 674 if (defined(invoker.cl_toolchain_prefix)) { 675 cl_toolchain_prefix = invoker.cl_toolchain_prefix 676 } else { 677 cl_toolchain_prefix = "" 678 } 679 msvc_toolchain(cl_toolchain_prefix + target_name) { 680 environment = "environment." + toolchain_arch 681 cl = "\"${win_toolchain_data.vc_bin_dir}/cl.exe\"" 682 683 toolchain_args = { 684 if (defined(invoker.toolchain_args)) { 685 forward_variables_from(invoker.toolchain_args, "*") 686 } 687 is_clang = false 688 use_clang_coverage = false 689 current_os = "win" 690 current_cpu = toolchain_arch 691 } 692 } 693 msvc_rust_host_build_tools_toolchain(cl_toolchain_prefix + target_name) { 694 environment = "environment." + rust_host_toolchain_arch 695 cl = "\"${rust_host_win_toolchain_data.vc_bin_dir}/cl.exe\"" 696 697 toolchain_args = { 698 if (defined(invoker.toolchain_args)) { 699 forward_variables_from(invoker.toolchain_args, "*") 700 } 701 is_clang = false 702 use_clang_coverage = false 703 current_os = "win" 704 current_cpu = rust_host_toolchain_arch 705 } 706 } 707 } 708 709 if (defined(invoker.clang_toolchain_prefix)) { 710 clang_toolchain_prefix = invoker.clang_toolchain_prefix 711 } else { 712 clang_toolchain_prefix = "win_clang_" 713 } 714 715 _clang_lib_dir = 716 rebase_path("$clang_base_path/lib/clang/$clang_version/lib/windows", 717 root_build_dir) 718 if (host_os == "win") { 719 # And to match the other -libpath flags. 720 _clang_lib_dir = string_replace(_clang_lib_dir, "/", "\\") 721 } 722 723 msvc_toolchain(clang_toolchain_prefix + target_name) { 724 environment = "environment." + toolchain_arch 725 cl = "${_clang_bin_path}/clang-cl${_exe}" 726 727 sys_include_flags = "${win_toolchain_data.include_flags_imsvc}" 728 if (use_lld) { 729 sys_lib_flags = "-libpath:$_clang_lib_dir " + 730 "${win_toolchain_data.libpath_lldlink_flags}" 731 } 732 733 toolchain_args = { 734 if (defined(invoker.toolchain_args)) { 735 forward_variables_from(invoker.toolchain_args, "*") 736 } 737 is_clang = true 738 current_os = "win" 739 current_cpu = toolchain_arch 740 } 741 } 742 msvc_rust_host_build_tools_toolchain(clang_toolchain_prefix + target_name) { 743 environment = "environment." + rust_host_toolchain_arch 744 cl = "${_clang_bin_path}/clang-cl${_exe}" 745 746 sys_include_flags = "${rust_host_win_toolchain_data.include_flags_imsvc}" 747 if (use_lld) { 748 sys_lib_flags = "-libpath:$_clang_lib_dir " + 749 "${rust_host_win_toolchain_data.libpath_lldlink_flags}" 750 } 751 752 toolchain_args = { 753 if (defined(invoker.toolchain_args)) { 754 forward_variables_from(invoker.toolchain_args, "*") 755 } 756 is_clang = true 757 current_os = "win" 758 current_cpu = rust_host_toolchain_arch 759 } 760 } 761} 762