1# Copyright 2013 The Chromium Authors 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5# TODO(brettw) Use "gcc_toolchain.gni" like the Linux toolchains. This requires 6# some enhancements since the commands on Mac are slightly different than on 7# Linux. 8 9import("//build/config/apple/symbols.gni") 10import("//build/config/clang/clang.gni") 11import("//build/config/compiler/compiler.gni") 12import("//build/config/coverage/coverage.gni") 13import("//build/config/rust.gni") 14import("//build/toolchain/cc_wrapper.gni") 15import("//build/toolchain/rbe.gni") 16import("//build/toolchain/toolchain.gni") 17import("//build_overrides/build.gni") 18 19# TODO(crbug.com/1370527): This import is required to detect whether the 20# build is for the catalyst environment in order to disable the hermetic 21# swift compiler (as it does not include support for catalyst). Remove it 22# once the support is available. 23if (is_ios) { 24 import("//build/config/ios/config.gni") 25 import("//build/config/ios/ios_sdk.gni") 26} 27 28assert((target_os == "ios" && host_os == "mac") || host_os != "win") 29 30declare_args() { 31 # This controls whether whole module optimization is enabled when building 32 # Swift modules. If enabled, the compiler will compile the module as one 33 # unit, generating just one single object file. Otherwise, it will generate 34 # one object file per .swift file. If unspecified, will default to "true" 35 # for official builds, and "false" for all other builds. 36 swift_whole_module_optimization = -1 37 38 # If true, the intermediate build products of swift module compilation will 39 # be kept after the invocation of the swiftc compiler. Otherwise they will 40 # deleted between each invocation. 41 swift_keep_intermediate_files = false 42 43 # If unspecified, will use the toolchain downloaded via deps. 44 swift_toolchain_path = -1 45} 46 47# TODO(crbug.com/1370527): Remove this and replace with `build_with_chromium` 48# once the support for catalyst is available in the hermetic swift compiler. 49_can_use_hermetic_swift = 50 build_with_chromium && is_ios && target_environment != "catalyst" 51 52if (swift_toolchain_path == -1) { 53 # TODO(crbug.com/1451611) The custom swift toolchain not does currently work 54 # with Xcode 15 beta 1. 55 if (_can_use_hermetic_swift && !(is_ios && xcode_version_int >= 1500)) { 56 # Version of the hermetic compiler. Needs to be updated when a new version of 57 # the compiler is rolled to ensure that all outputs are regenerated. It must 58 # be kept in sync with the `version` of `third_party/swift-toolchain` in 59 # //DEPS. 60 swiftc_version = "swift-5.8-release" 61 62 # Use the hermetic swift toolchain. 63 swift_toolchain_path = "//third_party/swift-toolchain/" 64 } else { 65 swift_toolchain_path = "" 66 } 67} 68 69if (swift_whole_module_optimization == -1) { 70 swift_whole_module_optimization = is_official_build 71} 72 73# When implementing tools using Python scripts, a TOOL_VERSION=N env 74# variable is placed in front of the command. The N should be incremented 75# whenever the script is changed, so that the build system rebuilds all 76# edges that utilize the script. Ideally this should be changed to use 77# proper input-dirty checking, but that could be expensive. Instead, use a 78# script to get the tool scripts' modification time to use as the version. 79# This won't cause a re-generation of GN files when the tool script changes 80# but it will cause edges to be marked as dirty if the ninja files are 81# regenerated. See https://crbug.com/619083 for details. A proper fix 82# would be to have inputs to tools (https://crbug.com/621119). 83tool_versions = exec_script( 84 "get_tool_mtime.py", 85 rebase_path([ 86 "//build/toolchain/apple/filter_libtool.py", 87 "//build/toolchain/apple/linker_driver.py", 88 "//build/toolchain/ios/compile_xcassets.py", 89 "//build/toolchain/ios/const_extract_protocols.json", 90 "//build/toolchain/ios/swiftc.py", 91 ], 92 root_build_dir), 93 "trim scope") 94 95# Shared toolchain definition. Invocations should set current_os to set the 96# build args in this definition. This is titled "single_apple_toolchain" 97# because it makes exactly one toolchain. Callers will normally want to 98# invoke instead "apple_toolchain" which makes an additional toolchain for 99# Rust targets that are build-time artificts such as proc macros. 100template("single_apple_toolchain") { 101 toolchain(target_name) { 102 # When invoking this toolchain not as the default one, these args will be 103 # passed to the build. They are ignored when this is the default toolchain. 104 assert(defined(invoker.toolchain_args), 105 "Toolchains must declare toolchain_args") 106 toolchain_args = { 107 # Populate toolchain args from the invoker. 108 forward_variables_from(invoker.toolchain_args, "*") 109 110 # The host toolchain value computed by the default toolchain's setup 111 # needs to be passed through unchanged to all secondary toolchains to 112 # ensure that it's always the same, regardless of the values that may be 113 # set on those toolchains. 114 host_toolchain = host_toolchain 115 } 116 117 # When the invoker has explicitly overridden cc_wrapper in the 118 # toolchain args, use those values, otherwise default to the global one. 119 # This works because the only reasonable override that toolchains might 120 # supply for these values are to force-disable them. 121 if (defined(toolchain_args.use_remoteexec)) { 122 toolchain_uses_remoteexec = toolchain_args.use_remoteexec 123 } else { 124 toolchain_uses_remoteexec = use_remoteexec 125 } 126 if (defined(toolchain_args.cc_wrapper)) { 127 toolchain_cc_wrapper = toolchain_args.cc_wrapper 128 } else { 129 toolchain_cc_wrapper = cc_wrapper 130 } 131 assert(!(toolchain_cc_wrapper != "" && toolchain_uses_remoteexec), 132 "re-client and cc_wrapper can't be used together.") 133 134 if (defined(toolchain_args.use_lld)) { 135 toolchain_uses_lld = toolchain_args.use_lld 136 } else { 137 toolchain_uses_lld = use_lld 138 } 139 140 # The value of all global variables (such as `is_component_build`) is the 141 # one from the default toolchain when evaluating a secondary toolchain 142 # (see https://crbug.com/gn/286). This mean that the value may change when 143 # evaluating target/configs in the new toolchain if the variable default 144 # value depends on variable set in `toolchain_args`. 145 # 146 # For this reason, "ios" needs to override `is_component_build` as its 147 # default value depends on `current_os`. Use the overridden value if it 148 # is set in `toolchain_args`. 149 if (defined(toolchain_args.is_component_build)) { 150 toolchain_is_component_build = toolchain_args.is_component_build 151 } else { 152 toolchain_is_component_build = is_component_build 153 } 154 155 prefix = rebase_path("$clang_base_path/bin/", root_build_dir) 156 _cc = "${prefix}clang" 157 _cxx = "${prefix}clang++" 158 159 swiftmodule_switch = "-Wl,-add_ast_path," 160 161 # Compute the compiler prefix. 162 if (toolchain_uses_remoteexec) { 163 if (defined(toolchain_args.rbe_cc_cfg_file)) { 164 toolchain_rbe_cc_cfg_file = toolchain_args.rbe_cc_cfg_file 165 } else { 166 toolchain_rbe_cc_cfg_file = rbe_cc_cfg_file 167 } 168 169 # C/C++ (clang) rewrapper prefix to use when use_remoteexec is true. 170 compiler_prefix = "${rbe_bin_dir}/rewrapper -cfg=${toolchain_rbe_cc_cfg_file}${rbe_bug_326584510_missing_inputs} -exec_root=${rbe_exec_root} " 171 } else if (toolchain_cc_wrapper != "") { 172 compiler_prefix = toolchain_cc_wrapper + " " 173 } else { 174 compiler_prefix = "" 175 } 176 177 cc = compiler_prefix + _cc 178 cxx = compiler_prefix + _cxx 179 ld = _cxx 180 181 # Set the explicit search path for clang++ so it uses the right linker 182 # binary. 183 if (!toolchain_uses_lld) { 184 ld += " -B " + invoker.bin_path 185 } 186 187 if (defined(toolchain_args.coverage_instrumentation_input_file)) { 188 toolchain_coverage_instrumentation_input_file = 189 toolchain_args.coverage_instrumentation_input_file 190 } else { 191 toolchain_coverage_instrumentation_input_file = 192 coverage_instrumentation_input_file 193 } 194 _use_clang_coverage_wrapper = 195 toolchain_coverage_instrumentation_input_file != "" 196 if (_use_clang_coverage_wrapper) { 197 _coverage_wrapper = 198 rebase_path("//build/toolchain/clang_code_coverage_wrapper.py", 199 root_build_dir) + " --files-to-instrument=" + 200 rebase_path(toolchain_coverage_instrumentation_input_file, 201 root_build_dir) + " --target-os=" + target_os 202 cc = "$python_path $_coverage_wrapper ${cc}" 203 cxx = "$python_path $_coverage_wrapper ${cxx}" 204 } 205 206 linker_driver_env = "TOOL_VERSION=${tool_versions.linker_driver}" 207 linker_driver = 208 rebase_path("//build/toolchain/apple/linker_driver.py", root_build_dir) 209 linker_driver_args = "-Wcrl,driver,$ld" 210 211 # Specify an explicit path for the strip binary. 212 _strippath = invoker.bin_path + "strip" 213 _installnametoolpath = "${prefix}llvm-install-name-tool" 214 linker_driver_args += " -Wcrl,strippath,${_strippath} -Wcrl,installnametoolpath,${_installnametoolpath}" 215 _enable_dsyms = enable_dsyms 216 _save_unstripped_output = save_unstripped_output 217 218 # Make these apply to all tools below. 219 lib_switch = "-l" 220 lib_dir_switch = "-L" 221 222 # Object files go in this directory. Use label_name instead of 223 # target_output_name since labels will generally have no spaces and will be 224 # unique in the directory. 225 object_subdir = "{{target_out_dir}}/{{label_name}}" 226 227 # If dSYMs are enabled, this flag will be added to the link tools. 228 if (_enable_dsyms) { 229 dsym_switch = " -Wcrl,dsym,{{root_out_dir}} " 230 dsym_switch += "-Wcrl,dsymutilpath," + 231 rebase_path("//tools/clang/dsymutil/bin/dsymutil", 232 root_build_dir) + " " 233 234 dsym_output_dir = 235 "{{root_out_dir}}/{{target_output_name}}{{output_extension}}.dSYM" 236 dsym_output = [ 237 "$dsym_output_dir/Contents/Info.plist", 238 "$dsym_output_dir/Contents/Resources/DWARF/" + 239 "{{target_output_name}}{{output_extension}}", 240 ] 241 } else { 242 dsym_switch = "" 243 } 244 245 if (_save_unstripped_output) { 246 _unstripped_output = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}.unstripped" 247 } 248 249 if (toolchain_has_rust) { 250 if (!defined(rust_compiler_prefix)) { 251 rust_compiler_prefix = "" 252 } 253 rust_sysroot_relative = rebase_path(rust_sysroot, root_build_dir) 254 rustc_bin = "$rust_sysroot_relative/bin/rustc" 255 rustc = "$rust_compiler_prefix${rustc_bin}" 256 rustc_wrapper = 257 rebase_path("//build/rust/rustc_wrapper.py", root_build_dir) 258 259 tool("rust_staticlib") { 260 libname = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 261 rspfile = "$libname.rsp" 262 depfile = "$libname.d" 263 264 default_output_extension = ".a" 265 output_prefix = "lib" 266 267 # Static libraries go in the target out directory by default so we can 268 # generate different targets with the same name and not have them 269 # collide. 270 default_output_dir = "{{target_out_dir}}" 271 description = "RUST(STATICLIB) {{output}}" 272 outputs = [ libname ] 273 274 # TODO(danakj): When `!toolchain_uses_lld` do we need to specify a path 275 # to libtool like the "alink" rule? 276 277 rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}" 278 command = "\"$python_path\" \"$rustc_wrapper\" --rustc=$rustc --depfile=$depfile --rsp=$rspfile -- -Clinker=\"$_cxx\" $rustc_common_args --emit=dep-info=$depfile,link -o $libname LDFLAGS RUSTENV {{rustenv}}" 279 rust_sysroot = rust_sysroot_relative 280 } 281 282 tool("rust_rlib") { 283 # We must always prefix with `lib` even if the library already starts 284 # with that prefix or else our stdlib is unable to find libc.rlib (or 285 # actually liblibc.rlib). 286 rlibname = 287 "{{output_dir}}/lib{{target_output_name}}{{output_extension}}" 288 rspfile = "$rlibname.rsp" 289 depfile = "$rlibname.d" 290 291 default_output_extension = ".rlib" 292 293 # This is prefixed unconditionally in `rlibname`. 294 # output_prefix = "lib" 295 296 # Static libraries go in the target out directory by default so we can 297 # generate different targets with the same name and not have them 298 # collide. 299 default_output_dir = "{{target_out_dir}}" 300 description = "RUST {{output}}" 301 outputs = [ rlibname ] 302 303 rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}" 304 command = "\"$python_path\" \"$rustc_wrapper\" --rustc=$rustc --depfile=$depfile --rsp=$rspfile -- -Clinker=\"$_cxx\" $rustc_common_args {{rustdeps}} {{externs}} --emit=dep-info=$depfile,link -o $rlibname LDFLAGS RUSTENV {{rustenv}}" 305 rust_sysroot = rust_sysroot_relative 306 } 307 308 tool("rust_bin") { 309 exename = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 310 rspfile = "$exename.rsp" 311 depfile = "$exename.d" 312 pool = "//build/toolchain:link_pool($default_toolchain)" 313 314 # TODO(danakj): solink can generate TOC files for re-exporting library 315 # symbols, and we should do the same here. 316 317 default_output_dir = "{{root_out_dir}}" 318 description = "RUST(BIN) {{output}}" 319 outputs = [ exename ] 320 321 # TODO(danakj): Support dsym_switch like C++ targets. 322 # link_command += dsym_switch 323 # if (_enable_dsyms) { 324 # outputs += dsym_output 325 # } 326 # if (_save_unstripped_output) { 327 # outputs += [ _unstripped_output ] 328 # } 329 330 rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}" 331 command = "$linker_driver_env \"$python_path\" \"$rustc_wrapper\" --rustc=$rustc --depfile=$depfile --rsp=$rspfile -- -Clinker=\"$linker_driver\" $rustc_common_args --emit=dep-info=$depfile,link -o $exename LDFLAGS $linker_driver_args {{ldflags}} RUSTENV {{rustenv}}" 332 rust_sysroot = rust_sysroot_relative 333 } 334 335 tool("rust_cdylib") { 336 dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 337 rspfile = "$dllname.rsp" 338 depfile = "$dllname.d" 339 pool = "//build/toolchain:link_pool($default_toolchain)" 340 341 # TODO(danakj): solink can generate TOC files for re-exporting library 342 # symbols, and we should do the same here. 343 344 default_output_extension = ".dylib" 345 output_prefix = "lib" 346 default_output_dir = "{{root_out_dir}}" 347 description = "RUST(CDYLIB) {{output}}" 348 outputs = [ dllname ] 349 350 # TODO(danakj): Support dsym_switch like C++ targets. 351 # link_command += dsym_switch 352 # if (_enable_dsyms) { 353 # outputs += dsym_output 354 # } 355 # if (_save_unstripped_output) { 356 # outputs += [ _unstripped_output ] 357 # } 358 359 rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}" 360 command = "$linker_driver_env \"$python_path\" \"$rustc_wrapper\" --rustc=$rustc --depfile=$depfile --rsp=$rspfile -- -Clinker=\"$linker_driver\" $rustc_common_args --emit=dep-info=$depfile,link -o $dllname LDFLAGS $linker_driver_args {{ldflags}} RUSTENV {{rustenv}}" 361 rust_sysroot = rust_sysroot_relative 362 } 363 364 tool("rust_macro") { 365 dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 366 rspfile = "$dllname.rsp" 367 depfile = "$dllname.d" 368 pool = "//build/toolchain:link_pool($default_toolchain)" 369 370 # TODO(danakj): solink can generate TOC files for re-exporting library 371 # symbols, and we should do the same here. 372 373 default_output_extension = ".dylib" 374 output_prefix = "lib" 375 default_output_dir = "{{root_out_dir}}" 376 description = "RUST(MACRO) {{output}}" 377 outputs = [ dllname ] 378 379 # TODO(danakj): Support dsym_switch like C++ targets. 380 # link_command += dsym_switch 381 # if (_enable_dsyms) { 382 # outputs += dsym_output 383 # } 384 # if (_save_unstripped_output) { 385 # outputs += [ _unstripped_output ] 386 # } 387 388 rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}" 389 command = "\"$python_path\" \"$rustc_wrapper\" --rustc=$rustc --depfile=$depfile --rsp=$rspfile -- -Clinker=\"${_cxx}\" $rustc_common_args --emit=dep-info=$depfile,link -o $dllname LDFLAGS {{ldflags}} RUSTENV {{rustenv}}" 390 rust_sysroot = rust_sysroot_relative 391 } 392 } 393 394 tool("cc") { 395 depfile = "{{output}}.d" 396 precompiled_header_type = "gcc" 397 command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" 398 depsformat = "gcc" 399 description = "CC {{output}}" 400 outputs = [ "$object_subdir/{{source_name_part}}.o" ] 401 } 402 403 tool("cxx") { 404 depfile = "{{output}}.d" 405 precompiled_header_type = "gcc" 406 command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}" 407 depsformat = "gcc" 408 description = "CXX {{output}}" 409 outputs = [ "$object_subdir/{{source_name_part}}.o" ] 410 } 411 412 tool("asm") { 413 # For GCC we can just use the C compiler to compile assembly. 414 depfile = "{{output}}.d" 415 command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}" 416 depsformat = "gcc" 417 description = "ASM {{output}}" 418 outputs = [ "$object_subdir/{{source_name_part}}.o" ] 419 } 420 421 tool("objc") { 422 depfile = "{{output}}.d" 423 precompiled_header_type = "gcc" 424 command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_objc}} -c {{source}} -o {{output}}" 425 depsformat = "gcc" 426 description = "OBJC {{output}}" 427 outputs = [ "$object_subdir/{{source_name_part}}.o" ] 428 } 429 430 tool("objcxx") { 431 depfile = "{{output}}.d" 432 precompiled_header_type = "gcc" 433 command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_objcc}} -c {{source}} -o {{output}}" 434 depsformat = "gcc" 435 description = "OBJCXX {{output}}" 436 outputs = [ "$object_subdir/{{source_name_part}}.o" ] 437 } 438 439 tool("alink") { 440 rspfile = "{{output}}.rsp" 441 rspfile_content = "{{inputs}}" 442 443 if (!toolchain_uses_lld) { 444 script = rebase_path("//build/toolchain/apple/filter_libtool.py", 445 root_build_dir) 446 447 # Specify explicit path for libtool. 448 libtool = invoker.bin_path + "libtool" 449 command = "rm -f {{output}} && TOOL_VERSION=${tool_versions.filter_libtool} $python_path $script $libtool -static -D {{arflags}} -o {{output}} @$rspfile" 450 description = "LIBTOOL-STATIC {{output}}" 451 } else { 452 ar = "${prefix}llvm-ar" 453 command = "\"$ar\" {{arflags}} -r -c -s -D {{output}} @$rspfile" 454 455 # Remove the output file first so that ar doesn't try to modify the 456 # existing file. 457 command = "rm -f {{output}} && $command" 458 description = "AR {{output}}" 459 } 460 outputs = [ "{{output_dir}}/{{target_output_name}}{{output_extension}}" ] 461 default_output_dir = "{{target_out_dir}}" 462 default_output_extension = ".a" 463 output_prefix = "lib" 464 } 465 466 tool("solink") { 467 # E.g. "./libfoo.dylib": 468 dylib = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 469 rspfile = dylib + ".rsp" 470 pool = "//build/toolchain:link_pool($default_toolchain)" 471 472 # These variables are not built into GN but are helpers that implement 473 # (1) linking to produce a .dylib, (2) extracting the symbols from that 474 # file to a temporary file, (3) if the temporary file has differences from 475 # the existing .TOC file, overwrite it, otherwise, don't change it. 476 # 477 # As a special case, if the library reexports symbols from other dynamic 478 # libraries, we always update the .TOC and skip the temporary file and 479 # diffing steps, since that library always needs to be re-linked. 480 tocname = dylib + ".TOC" 481 temporary_tocname = dylib + ".tmp" 482 483 # Use explicit paths to binaries. The binaries present on the default 484 # search path in /usr/bin are thin wrappers around xcrun, which requires a 485 # full CommandLineTools or Xcode install, and still may not choose the 486 # appropriate binary if there are multiple installs. 487 if (host_os == "mac") { 488 nm = invoker.bin_path + "nm" 489 otool = invoker.bin_path + "otool" 490 } else { 491 nm = "${prefix}llvm-nm" 492 otool = "${prefix}llvm-otool" 493 } 494 495 does_reexport_command = "[ ! -e \"$dylib\" -o ! -e \"$tocname\" ] || $otool -l \"$dylib\" | grep -q LC_REEXPORT_DYLIB" 496 497 link_command = 498 "$linker_driver_env $linker_driver $linker_driver_args -shared " 499 if (toolchain_is_component_build) { 500 link_command += " -Wl,-install_name,@rpath/\"{{target_output_name}}{{output_extension}}\" " 501 } 502 link_command += dsym_switch 503 link_command += "{{ldflags}} -o \"$dylib\" \"@$rspfile\" {{rlibs}}" 504 505 replace_command = "if ! cmp -s \"$temporary_tocname\" \"$tocname\"; then mv \"$temporary_tocname\" \"$tocname\"" 506 extract_toc_command = "{ $otool -l \"$dylib\" | grep LC_ID_DYLIB -A 5; $nm -gPp \"$dylib\" | cut -f1-2 -d' ' | grep -v U\$\$; true; }" 507 508 command = "if $does_reexport_command ; then $link_command && $extract_toc_command > \"$tocname\"; else $link_command && $extract_toc_command > \"$temporary_tocname\" && $replace_command ; fi; fi" 509 510 rspfile_content = 511 "{{inputs}} {{frameworks}} {{swiftmodules}} {{solibs}} {{libs}}" 512 513 description = "SOLINK {{output}}" 514 515 # Use this for {{output_extension}} expansions unless a target manually 516 # overrides it (in which case {{output_extension}} will be what the target 517 # specifies). 518 default_output_dir = "{{root_out_dir}}" 519 default_output_extension = ".dylib" 520 521 output_prefix = "lib" 522 523 # Since the above commands only updates the .TOC file when it changes, ask 524 # Ninja to check if the timestamp actually changed to know if downstream 525 # dependencies should be recompiled. 526 restat = true 527 528 # Tell GN about the output files. It will link to the dylib but use the 529 # tocname for dependency management. 530 outputs = [ 531 dylib, 532 tocname, 533 ] 534 link_output = dylib 535 depend_output = tocname 536 537 if (_enable_dsyms) { 538 outputs += dsym_output 539 } 540 if (_save_unstripped_output) { 541 outputs += [ _unstripped_output ] 542 } 543 } 544 545 tool("solink_module") { 546 # E.g. "./libfoo.so": 547 sofile = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 548 rspfile = sofile + ".rsp" 549 pool = "//build/toolchain:link_pool($default_toolchain)" 550 551 link_command = "$linker_driver_env $linker_driver $linker_driver_args -bundle {{ldflags}} -o \"$sofile\" \"@$rspfile\" {{rlibs}}" 552 link_command += dsym_switch 553 command = link_command 554 555 rspfile_content = 556 "{{inputs}} {{frameworks}} {{swiftmodules}} {{solibs}} {{libs}}" 557 558 description = "SOLINK_MODULE {{output}}" 559 560 # Use this for {{output_extension}} expansions unless a target manually 561 # overrides it (in which case {{output_extension}} will be what the target 562 # specifies). 563 default_output_dir = "{{root_out_dir}}" 564 default_output_extension = ".so" 565 566 outputs = [ sofile ] 567 568 if (_enable_dsyms) { 569 outputs += dsym_output 570 } 571 if (_save_unstripped_output) { 572 outputs += [ _unstripped_output ] 573 } 574 } 575 576 tool("link") { 577 outfile = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 578 rspfile = "$outfile.rsp" 579 pool = "//build/toolchain:link_pool($default_toolchain)" 580 581 command = "$linker_driver_env $linker_driver $linker_driver_args $dsym_switch {{ldflags}} -o \"$outfile\" \"@$rspfile\" {{rlibs}}" 582 description = "LINK $outfile" 583 rspfile_content = 584 "{{inputs}} {{frameworks}} {{swiftmodules}} {{solibs}} {{libs}}" 585 outputs = [ outfile ] 586 587 if (_enable_dsyms) { 588 outputs += dsym_output 589 } 590 if (_save_unstripped_output) { 591 outputs += [ _unstripped_output ] 592 } 593 594 default_output_dir = "{{root_out_dir}}" 595 } 596 597 # These two are really entirely generic, but have to be repeated in 598 # each toolchain because GN doesn't allow a template to be used here. 599 # See //build/toolchain/toolchain.gni for details. 600 tool("stamp") { 601 command = stamp_command 602 description = stamp_description 603 } 604 tool("copy") { 605 command = copy_command 606 description = copy_description 607 } 608 609 tool("copy_bundle_data") { 610 # copy_command use hardlink if possible but this does not work with 611 # directories. Also when running EG2 tests from Xcode, Xcode tries to 612 # copy some files into the application bundle which fails if source 613 # and destination are hardlinked together. 614 # 615 # Instead use clonefile to copy the files which is as efficient as 616 # hardlink but ensure the file have distinct metadata (thus avoid the 617 # error with ditto, see https://crbug.com/1042182). 618 if (host_os == "mac") { 619 command = "rm -rf {{output}} && /bin/cp -Rc {{source}} {{output}}" 620 } else { 621 command = "rm -rf {{output}} && /bin/cp -Rld {{source}} {{output}}" 622 } 623 description = "COPY_BUNDLE_DATA {{source}} {{output}}" 624 pool = "//build/toolchain/apple:bundle_pool($default_toolchain)" 625 } 626 627 # Swift is only used on iOS, not macOS. We want to minimize the number 628 # of Xcode-based tools used by the macOS toolchain, so we intentionally 629 # disallow future uses of Swift on macOS. https://crbug.com/965663. 630 if (toolchain_args.current_os == "ios") { 631 tool("swift") { 632 _tool = rebase_path("//build/toolchain/ios/swiftc.py", root_build_dir) 633 634 depfile = "{{target_out_dir}}/{{module_name}}.d" 635 depsformat = "gcc" 636 637 _header_path = "{{target_gen_dir}}/{{target_output_name}}.h" 638 _output_dir = "{{target_out_dir}}/{{label_name}}" 639 640 outputs = [ 641 _header_path, 642 "$_output_dir/{{module_name}}-OutputFileMap.json", 643 "$_output_dir/{{module_name}}.SwiftFileList", 644 "$_output_dir/{{module_name}}.abi.json", 645 "$_output_dir/{{module_name}}.d", 646 "$_output_dir/{{module_name}}.dia", 647 "$_output_dir/{{module_name}}.swiftdoc", 648 "$_output_dir/{{module_name}}.swiftmodule", 649 "$_output_dir/{{module_name}}.swiftsourceinfo", 650 ] 651 652 partial_outputs = [ "$_output_dir/{{source_name_part}}.o" ] 653 654 # The list of outputs and partial_outputs change whether the whole 655 # module optimization is enabled or not. 656 if (swift_whole_module_optimization) { 657 outputs += [ 658 "$_output_dir/{{module_name}}.swiftconstvalues", 659 "$_output_dir/{{module_name}}.swiftdeps", 660 ] 661 } else { 662 outputs += [ "$_output_dir/{{module_name}}.priors" ] 663 partial_outputs += [ 664 "$_output_dir/{{source_name_part}}.d", 665 "$_output_dir/{{source_name_part}}.dia", 666 "$_output_dir/{{source_name_part}}.swiftdeps", 667 "$_output_dir/{{source_name_part}}.swiftconstvalues", 668 ] 669 } 670 671 # If configured to keep the intermediate build files, pass the flag 672 # to the script and inform gn of the stamp file only (as the other 673 # files have names that cannot be predicted without invoking swiftc). 674 if (swift_keep_intermediate_files) { 675 _derived_data_dir = "$_output_dir/DerivedData" 676 outputs += [ "$_derived_data_dir/{{module_name}}.stamp" ] 677 } 678 679 # Additional flags passed to the wrapper script but that are only 680 # set conditionally. 681 _extra_flags = "" 682 683 # Environment variables passed to the wrapper script. Considered 684 # part of the command-line by ninja (and thus cause the build to 685 # be considered dirty if they change) without having to be parsed 686 # by the script. 687 _env_vars = "TOOL_VERSION=${tool_versions.swiftc} " + 688 "JSON_VERSION=${tool_versions.const_extract_protocols}" 689 690 # Include the version of the compiler on the command-line. This causes 691 # `ninja` to consider all the compilation output to be dirty when the 692 # version changes. 693 if (defined(swiftc_version)) { 694 _env_vars += " SWIFTC_VERSION=$swiftc_version" 695 } 696 697 # Include the version of Xcode on the command-line (if specified via 698 # toolchain_args). This causes `ninja` to consider all the compilation 699 # outputs to be dirty when the version change. 700 # 701 # This is required because sometimes module dependency changes between 702 # different version of Xcode (e.g. when moving from Xcode 14 beta 6 to 703 # Xcode 14 RC). If the swiftmodule are not rebuilt when the version 704 # changes, they may encode dependency on now non-existing frameworks 705 # causing linker failures ultimately. 706 if (defined(toolchain_args.xcode_build)) { 707 _env_vars += " XCODE_VERSION=${toolchain_args.xcode_build}" 708 } 709 710 if (invoker.sdk_developer_dir != "") { 711 _env_vars += " DEVELOPER_DIR=${toolchain_args.sdk_developer_dir}" 712 } 713 714 if (swift_toolchain_path != "") { 715 _extra_flags += " --swift-toolchain-path " + 716 rebase_path(swift_toolchain_path, root_build_dir) 717 } 718 719 if (swift_whole_module_optimization) { 720 _extra_flags += " --whole-module-optimization" 721 } 722 723 if (swift_keep_intermediate_files) { 724 _extra_flags += " --derived-data-dir $_derived_data_dir" 725 } 726 727 # The Swift compiler assumes that the generated header will be used by 728 # Objective-C code compiled with module support enabled (-fmodules). 729 # 730 # As Chromium code is compiled without support for modules (i.e. the 731 # code is compiled without `-fmodules`), the dependent modules are not 732 # imported from the generated header, which causes compilation failure 733 # if the client code does not first import the required modules (see 734 # https://crbug.com/1316061 for details). 735 # 736 # Secondly, the Swift compiler uses absolute path when importing other 737 # modules' generated headers or Objective-C bridging headers. This 738 # causes issues with the distributed compiler (i.e. reclient or siso) 739 # as they want all paths to be relative to the source directory. 740 # 741 # Instruct swiftc.py to rewrite the generated header use relative 742 # import and to use the old #import syntax for system frameworks. 743 _extra_flags += " --fix-generated-header" 744 745 _src_dir = rebase_path("//", root_build_dir) 746 _gen_dir = rebase_path(root_gen_dir, root_build_dir) 747 _const_gather_protocols_file = 748 rebase_path("//build/toolchain/ios/const_extract_protocols.json", 749 root_build_dir) 750 751 command = 752 "$_env_vars $python_path $_tool --module-name {{module_name}} " + 753 "--header-path $_header_path --target-out-dir $_output_dir " + 754 "--const-gather-protocols-file $_const_gather_protocols_file " + 755 "--depfile-path $depfile --src-dir $_src_dir --gen-dir $_gen_dir " + 756 "--bridge-header {{bridge_header}} {{include_dirs}} " + 757 "{{module_dirs}} {{swiftflags}} {{inputs}}$_extra_flags" 758 759 description = "SWIFT $_output_dir/{{module_name}}.swiftmodule" 760 } 761 } 762 763 # xcassets are only used on iOS, not macOS. We want to minimize the number 764 # of Xcode-based tools used by the macOS toolchain, so we intentionally 765 # disallow future uses of xcassets on macOS. https://crbug.com/965663. 766 if (toolchain_args.current_os == "ios") { 767 tool("compile_xcassets") { 768 _tool = rebase_path("//build/toolchain/ios/compile_xcassets.py", 769 root_build_dir) 770 771 _env_vars = "TOOL_VERSION=${tool_versions.compile_xcassets}" 772 if (invoker.sdk_developer_dir != "") { 773 _env_vars += " DEVELOPER_DIR=${toolchain_args.sdk_developer_dir}" 774 } 775 776 command = 777 "$_env_vars $python_path $_tool " + 778 "-p '${toolchain_args.current_os}' " + 779 "-e '${invoker.target_environment}' " + 780 "-t '${invoker.deployment_target}' " + 781 "-T '{{bundle_product_type}}' " + 782 "-P '{{bundle_partial_info_plist}}' " + "-o {{output}} {{inputs}}" 783 784 description = "COMPILE_XCASSETS {{output}}" 785 pool = "//build/toolchain/apple:bundle_pool($default_toolchain)" 786 } 787 } 788 789 tool("action") { 790 pool = "//build/toolchain:action_pool($default_toolchain)" 791 } 792 } 793} 794 795# Makes an Apple toolchain for the target, and an equivalent toolchain with the 796# prebuilt Rust stdlib for building proc macros (and other for-build-use 797# artifacts). 798template("apple_toolchain") { 799 single_apple_toolchain(target_name) { 800 assert(defined(invoker.toolchain_args), 801 "Toolchains must declare toolchain_args") 802 forward_variables_from(invoker, 803 "*", 804 [ 805 "visibility", 806 "test_only", 807 ]) 808 809 # No need to forward visibility and test_only as they apply to targets not 810 # toolchains, but presubmit checks require that we explicitly exclude them 811 } 812 813 if (enable_rust && current_toolchain == default_toolchain) { 814 # Make an additional toolchain which is used for making tools that are run 815 # on the host machine as part of the build process (such as proc macros 816 # and Cargo build scripts). This toolchain uses the prebuilt stdlib that 817 # comes with the compiler, so it doesn't have to wait for the stdlib to be 818 # built before building other stuff. And this ensures its proc macro 819 # outputs have the right ABI to be loaded by the compiler, and it can be 820 # used to compile build scripts that are part of the stdlib that is built 821 # for the default toolchain. 822 single_apple_toolchain("${target_name}_for_rust_host_build_tools") { 823 assert(defined(invoker.toolchain_args), 824 "Toolchains must declare toolchain_args") 825 forward_variables_from(invoker, 826 "*", 827 [ 828 "toolchain_args", 829 "visibility", 830 "test_only", 831 ]) 832 toolchain_args = { 833 # Populate toolchain args from the invoker. 834 forward_variables_from(invoker.toolchain_args, "*") 835 toolchain_for_rust_host_build_tools = true 836 837 # The host build tools are static release builds to make the Chromium 838 # build faster. They do not need PGO etc, so no official builds. 839 is_debug = false 840 is_component_build = false 841 is_official_build = false 842 use_clang_coverage = false 843 use_sanitizer_coverage = false 844 generate_linker_map = false 845 use_thin_lto = false 846 } 847 } 848 } 849} 850