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