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