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} -c {{source}} -o {{output}}" 357 depsformat = "gcc" 358 description = "CXX {{output}}" 359 outputs = [ "$object_subdir/{{source_name_part}}.o" ] 360 } 361 362 tool("asm") { 363 # For GCC we can just use the C compiler to compile assembly. 364 depfile = "{{output}}.d" 365 command = "$asm $md -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{asmflags}}${extra_asmflags} -c {{source}} -o {{output}}" 366 depsformat = "gcc" 367 description = "ASM {{output}}" 368 outputs = [ "$object_subdir/{{source_name_part}}.o" ] 369 } 370 371 tool("alink") { 372 if (current_os == "aix") { 373 # AIX does not support either -D (deterministic output) or response 374 # files. 375 command = "$ar -X64 {{arflags}} -r -c -s {{output}} {{inputs}}" 376 } else { 377 rspfile = "{{output}}.rsp" 378 rspfile_content = "{{inputs}}" 379 command = "\"$ar\" {{arflags}} -r -c -D {{output}} @\"$rspfile\"" 380 } 381 382 # Remove the output file first so that ar doesn't try to modify the 383 # existing file. 384 if (host_os == "win") { 385 tool_wrapper_path = 386 rebase_path("//build/toolchain/win/tool_wrapper.py", root_build_dir) 387 command = "cmd /s /c \"\"$python_path\" $tool_wrapper_path delete-file {{output}} && $command\"" 388 } else { 389 command = "rm -f {{output}} && $command" 390 } 391 392 # Almost all targets build with //build/config/compiler:thin_archive which 393 # adds -T -S to arflags. 394 description = "AR {{output}}" 395 outputs = [ "{{output_dir}}/{{target_output_name}}{{output_extension}}" ] 396 397 # Static libraries go in the target out directory by default so we can 398 # generate different targets with the same name and not have them collide. 399 default_output_dir = "{{target_out_dir}}" 400 default_output_extension = ".a" 401 output_prefix = "lib" 402 } 403 404 tool("solink") { 405 soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so". 406 sofile = "{{output_dir}}/$soname" # Possibly including toolchain dir. 407 rspfile = sofile + ".rsp" 408 409 pool = "//build/toolchain:link_pool($default_toolchain)" 410 411 if (defined(invoker.strip)) { 412 unstripped_sofile = "{{root_out_dir}}/lib.unstripped/$soname" 413 } else { 414 unstripped_sofile = sofile 415 } 416 417 # These variables are not built into GN but are helpers that 418 # implement (1) linking to produce a .so, (2) extracting the symbols 419 # from that file (3) if the extracted list differs from the existing 420 # .TOC file, overwrite it, otherwise, don't change it. 421 tocfile = sofile + ".TOC" 422 423 soname_flag = "" 424 if (current_os != "aix") { 425 # -soname flag is not available on aix ld 426 soname_flag = "-Wl,-soname=\"$soname\"" 427 } 428 link_command = "$ld -shared $soname_flag {{ldflags}}${extra_ldflags} -o \"$unstripped_sofile\" @\"$rspfile\" {{rlibs}}" 429 430 # Generate a map file to be used for binary size analysis. 431 # Map file adds ~10% to the link time on a z620. 432 # With target_os="android", libchrome.so.map.gz is ~20MB. 433 map_switch = "" 434 if (enable_linker_map) { 435 map_file = "$unstripped_sofile.map.gz" 436 map_switch = " --map-file \"$map_file\"" 437 } 438 439 assert(defined(readelf), "to solink you must have a readelf") 440 assert(defined(nm), "to solink you must have an nm") 441 strip_switch = "" 442 if (defined(invoker.strip)) { 443 strip_switch = "--strip=${invoker.strip} " 444 } 445 446 # This needs a Python script to avoid using a complex shell command 447 # requiring sh control structures, pipelines, and POSIX utilities. 448 # The host might not have a POSIX shell and utilities (e.g. Windows). 449 solink_wrapper = 450 rebase_path("//build/toolchain/gcc_solink_wrapper.py", root_build_dir) 451 solink_extra_flags = "" 452 if (current_os == "aix") { 453 # to be intercepted by solink_wrapper, so that we exit immediately 454 # after linking the shared object, without generating the TOC file 455 # (skipped on Aix) 456 solink_extra_flags = "--partitioned-library" 457 } 458 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" 459 460 if (target_cpu == "mipsel" && is_component_build && is_android) { 461 rspfile_content = "-Wl,--start-group -Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}} -Wl,--end-group" 462 } else if (current_os == "aix") { 463 # --whole-archive, --no-whole-archive flags are not available on the aix 464 # ld. 465 rspfile_content = "{{inputs}} {{solibs}} {{libs}}" 466 } else { 467 rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}}" 468 } 469 470 description = "SOLINK $sofile" 471 472 # Use this for {{output_extension}} expansions unless a target manually 473 # overrides it (in which case {{output_extension}} will be what the target 474 # specifies). 475 default_output_extension = default_shlib_extension 476 477 default_output_dir = "{{root_out_dir}}${default_shlib_subdir}" 478 479 output_prefix = "lib" 480 481 # Since the above commands only updates the .TOC file when it changes, ask 482 # Ninja to check if the timestamp actually changed to know if downstream 483 # dependencies should be recompiled. 484 restat = true 485 486 # Tell GN about the output files. It will link to the sofile but use the 487 # tocfile for dependency management. 488 outputs = [ 489 sofile, 490 tocfile, 491 ] 492 if (sofile != unstripped_sofile) { 493 outputs += [ unstripped_sofile ] 494 if (defined(invoker.use_unstripped_as_runtime_outputs) && 495 invoker.use_unstripped_as_runtime_outputs) { 496 runtime_outputs = [ unstripped_sofile ] 497 } 498 } 499 500 # Clank build will generate DWP files when Fission is used. 501 # Other builds generate DWP files outside of the gn link targets, if at 502 # all. 503 if (defined(invoker.dwp)) { 504 outputs += [ unstripped_sofile + ".dwp" ] 505 if (defined(invoker.use_unstripped_as_runtime_outputs) && 506 invoker.use_unstripped_as_runtime_outputs) { 507 runtime_outputs += [ unstripped_sofile + ".dwp" ] 508 } 509 } 510 if (defined(map_file)) { 511 outputs += [ map_file ] 512 } 513 link_output = sofile 514 depend_output = tocfile 515 } 516 517 tool("solink_module") { 518 soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so". 519 sofile = "{{output_dir}}/$soname" 520 rspfile = sofile + ".rsp" 521 522 pool = "//build/toolchain:link_pool($default_toolchain)" 523 524 if (defined(invoker.strip)) { 525 unstripped_sofile = "{{root_out_dir}}/lib.unstripped/$soname" 526 } else { 527 unstripped_sofile = sofile 528 } 529 530 soname_flag = "" 531 whole_archive_flag = "" 532 no_whole_archive_flag = "" 533 if (current_os != "aix") { 534 # -soname, --whole-archive, --no-whole-archive flags are not available 535 # on aix ld 536 soname_flag = "-Wl,-soname=\"$soname\"" 537 whole_archive_flag = "-Wl,--whole-archive" 538 no_whole_archive_flag = "-Wl,--no-whole-archive" 539 } 540 command = "$ld -shared {{ldflags}}${extra_ldflags} -o \"$unstripped_sofile\" $soname_flag @\"$rspfile\"" 541 542 if (defined(invoker.strip)) { 543 strip_command = "${invoker.strip} -o \"$sofile\" \"$unstripped_sofile\"" 544 command += " && " + strip_command 545 } 546 rspfile_content = "$whole_archive_flag {{inputs}} {{solibs}} $no_whole_archive_flag {{libs}} {{rlibs}}" 547 548 description = "SOLINK_MODULE $sofile" 549 550 # Use this for {{output_extension}} expansions unless a target manually 551 # overrides it (in which case {{output_extension}} will be what the target 552 # specifies). 553 if (defined(invoker.loadable_module_extension)) { 554 default_output_extension = invoker.loadable_module_extension 555 } else { 556 default_output_extension = default_shlib_extension 557 } 558 559 default_output_dir = "{{root_out_dir}}${default_shlib_subdir}" 560 561 output_prefix = "lib" 562 563 outputs = [ sofile ] 564 if (sofile != unstripped_sofile) { 565 outputs += [ unstripped_sofile ] 566 if (defined(invoker.use_unstripped_as_runtime_outputs) && 567 invoker.use_unstripped_as_runtime_outputs) { 568 runtime_outputs = [ unstripped_sofile ] 569 } 570 } 571 } 572 573 tool("link") { 574 exename = "{{target_output_name}}{{output_extension}}" 575 outfile = "{{output_dir}}/$exename" 576 rspfile = "$outfile.rsp" 577 unstripped_outfile = outfile 578 579 pool = "//build/toolchain:link_pool($default_toolchain)" 580 581 # Use this for {{output_extension}} expansions unless a target manually 582 # overrides it (in which case {{output_extension}} will be what the target 583 # specifies). 584 default_output_extension = default_executable_extension 585 586 default_output_dir = "{{root_out_dir}}" 587 588 if (defined(invoker.strip)) { 589 unstripped_outfile = "{{root_out_dir}}/exe.unstripped/$exename" 590 } 591 592 start_group_flag = "" 593 end_group_flag = "" 594 if (current_os != "aix") { 595 # the "--start-group .. --end-group" feature isn't available on the aix 596 # ld. 597 start_group_flag = "-Wl,--start-group" 598 end_group_flag = "-Wl,--end-group " 599 } 600 601 # We need to specify link groups, at least, for single pass linkers. I.e. 602 # Rust libraries are alpha-sorted instead of by dependencies so they fail 603 # to link if not properly ordered or grouped. 604 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" 605 606 # Generate a map file to be used for binary size analysis. 607 # Map file adds ~10% to the link time on a z620. 608 # With target_os="android", libchrome.so.map.gz is ~20MB. 609 map_switch = "" 610 if (enable_linker_map) { 611 map_file = "$unstripped_outfile.map.gz" 612 map_switch = " --map-file \"$map_file\"" 613 } 614 615 strip_switch = "" 616 if (defined(invoker.strip)) { 617 strip_switch = " --strip=\"${invoker.strip}\" --unstripped-file=\"$unstripped_outfile\"" 618 } 619 620 link_wrapper = 621 rebase_path("//build/toolchain/gcc_link_wrapper.py", root_build_dir) 622 command = "\"$python_path\" \"$link_wrapper\" --output=\"$outfile\"$strip_switch$map_switch$dwp_switch -- $link_command" 623 624 description = "LINK $outfile" 625 626 rspfile_content = "{{inputs}}" 627 outputs = [ outfile ] 628 if (outfile != unstripped_outfile) { 629 outputs += [ unstripped_outfile ] 630 if (defined(invoker.use_unstripped_as_runtime_outputs) && 631 invoker.use_unstripped_as_runtime_outputs) { 632 runtime_outputs = [ unstripped_outfile ] 633 } 634 } 635 636 # Clank build will generate DWP files when Fission is used. 637 # Other builds generate DWP files outside of the gn link targets, if at 638 # all. 639 if (defined(invoker.dwp)) { 640 outputs += [ unstripped_outfile + ".dwp" ] 641 if (defined(invoker.use_unstripped_as_runtime_outputs) && 642 invoker.use_unstripped_as_runtime_outputs) { 643 runtime_outputs += [ unstripped_outfile + ".dwp" ] 644 } 645 } 646 if (defined(invoker.link_outputs)) { 647 outputs += invoker.link_outputs 648 } 649 if (defined(map_file)) { 650 outputs += [ map_file ] 651 } 652 } 653 654 # These two are really entirely generic, but have to be repeated in 655 # each toolchain because GN doesn't allow a template to be used here. 656 # See //build/toolchain/toolchain.gni for details. 657 tool("stamp") { 658 command = stamp_command 659 description = stamp_description 660 } 661 tool("copy") { 662 command = copy_command 663 description = copy_description 664 } 665 666 tool("action") { 667 pool = "//build/toolchain:action_pool($default_toolchain)" 668 } 669 670 if (toolchain_has_rust) { 671 if (!defined(rust_compiler_prefix)) { 672 rust_compiler_prefix = "" 673 } 674 rust_sysroot_relative = rebase_path(rust_sysroot, root_build_dir) 675 rustc_bin = "$rust_sysroot_relative/bin/rustc" 676 rustc = "$rust_compiler_prefix${rustc_bin}" 677 rustc_wrapper = 678 rebase_path("//build/rust/rustc_wrapper.py", root_build_dir) 679 680 # RSP manipulation due to https://bugs.chromium.org/p/gn/issues/detail?id=249 681 tool("rust_staticlib") { 682 libname = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 683 rspfile = "$libname.rsp" 684 depfile = "$libname.d" 685 686 default_output_extension = ".a" 687 output_prefix = "lib" 688 689 # Static libraries go in the target out directory by default so we can 690 # generate different targets with the same name and not have them 691 # collide. 692 default_output_dir = "{{target_out_dir}}" 693 description = "RUST(STATICLIB) {{output}}" 694 outputs = [ libname ] 695 696 rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}" 697 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}}" 698 rust_sysroot = rust_sysroot_relative 699 } 700 701 tool("rust_rlib") { 702 # We must always prefix with `lib` even if the library already starts 703 # with that prefix or else our stdlib is unable to find libc.rlib (or 704 # actually liblibc.rlib). 705 rlibname = 706 "{{output_dir}}/lib{{target_output_name}}{{output_extension}}" 707 rspfile = "$rlibname.rsp" 708 depfile = "$rlibname.d" 709 710 default_output_extension = ".rlib" 711 712 # This is prefixed unconditionally in `rlibname`. 713 # output_prefix = "lib" 714 # Static libraries go in the target out directory by default so we can 715 # generate different targets with the same name and not have them 716 # collide. 717 default_output_dir = "{{target_out_dir}}" 718 description = "RUST {{output}}" 719 outputs = [ rlibname ] 720 721 rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}" 722 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}}" 723 rust_sysroot = rust_sysroot_relative 724 } 725 726 tool("rust_bin") { 727 exename = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 728 depfile = "$exename.d" 729 rspfile = "$exename.rsp" 730 pool = "//build/toolchain:link_pool($default_toolchain)" 731 732 default_output_extension = default_executable_extension 733 default_output_dir = "{{root_out_dir}}" 734 description = "RUST(BIN) {{output}}" 735 outputs = [ exename ] 736 737 rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}" 738 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}}" 739 rust_sysroot = rust_sysroot_relative 740 } 741 742 tool("rust_cdylib") { 743 dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 744 depfile = "$dllname.d" 745 rspfile = "$dllname.rsp" 746 pool = "//build/toolchain:link_pool($default_toolchain)" 747 748 default_output_extension = default_shlib_extension 749 output_prefix = "lib" 750 default_output_dir = "{{root_out_dir}}${default_shlib_subdir}" 751 description = "RUST(CDYLIB) {{output}}" 752 outputs = [ dllname ] 753 754 rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}" 755 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}}" 756 rust_sysroot = rust_sysroot_relative 757 } 758 759 tool("rust_macro") { 760 dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 761 depfile = "$dllname.d" 762 rspfile = "$dllname.rsp" 763 pool = "//build/toolchain:link_pool($default_toolchain)" 764 765 default_output_extension = default_shlib_extension 766 output_prefix = "lib" 767 default_output_dir = "{{root_out_dir}}${default_shlib_subdir}" 768 description = "RUST(MACRO) {{output}}" 769 outputs = [ dllname ] 770 771 rspfile_content = "{{rustdeps}} {{externs}} SOURCES {{sources}}" 772 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}}" 773 rust_sysroot = rust_sysroot_relative 774 } 775 } 776 777 forward_variables_from(invoker, 778 [ 779 "deps", 780 "propagates_configs", 781 ]) 782 } 783} 784 785# Make an additional toolchain which is used for making tools that are run 786# on the host machine as part of the build process (such as proc macros 787# and Cargo build scripts). This toolchain uses the prebuilt stdlib that 788# comes with the compiler, so it doesn't have to wait for the stdlib to be 789# built before building other stuff. And this ensures its proc macro 790# outputs have the right ABI to be loaded by the compiler, and it can be 791# used to compile build scripts that are part of the stdlib that is built 792# for the default toolchain. 793template("gcc_rust_host_build_tools_toolchain") { 794 single_gcc_toolchain(target_name) { 795 assert(defined(invoker.toolchain_args), 796 "Toolchains must declare toolchain_args") 797 forward_variables_from(invoker, 798 "*", 799 TESTONLY_AND_VISIBILITY + [ "toolchain_args" ]) 800 toolchain_args = { 801 # Populate toolchain args from the invoker. 802 forward_variables_from(invoker.toolchain_args, "*") 803 toolchain_for_rust_host_build_tools = true 804 805 # The host build tools are static release builds to make the Chromium 806 # build faster. 807 is_debug = false 808 is_component_build = false 809 is_official_build = false 810 use_clang_coverage = false 811 use_sanitizer_coverage = false 812 generate_linker_map = false 813 use_thin_lto = false 814 } 815 816 # When cross-compiling we don't want to use the target platform's file 817 # extensions. 818 shlib_extension = host_shlib_extension 819 } 820} 821 822# If PartitionAlloc is part of the build (even as a transitive dependency), then 823# it replaces the system allocator. If this toolchain is used, that will be 824# overridden and the system allocator will be used regardless. This is important 825# in some third-party binaries outside of Chrome. 826template("gcc_system_allocator_toolchain") { 827 single_gcc_toolchain(target_name) { 828 assert(defined(invoker.toolchain_args), 829 "Toolchains must declare toolchain_args") 830 forward_variables_from(invoker, 831 "*", 832 TESTONLY_AND_VISIBILITY + [ "toolchain_args" ]) 833 toolchain_args = { 834 # Populate toolchain args from the invoker. 835 forward_variables_from(invoker.toolchain_args, "*") 836 toolchain_allows_use_partition_alloc_as_malloc = false 837 838 # Disable component build so that we can copy the exes to the 839 # root_build_dir and support the default_toolchain redirection on Windows. 840 # See also the comment in //build/symlink.gni. 841 is_component_build = false 842 843 # Only one toolchain can be configured with MSAN support with our current 844 # GN setup, or they all try to make the instrumented libraries and 845 # collide. 846 is_msan = false 847 } 848 } 849} 850 851# Makes a GCC toolchain for the target, and an equivalent toolchain with the 852# prebuilt Rust stdlib for building proc macros (and other for-build-use 853# artifacts). 854template("gcc_toolchain") { 855 single_gcc_toolchain(target_name) { 856 assert(defined(invoker.toolchain_args), 857 "Toolchains must declare toolchain_args") 858 forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY) 859 860 # No need to forward visibility and test_only as they apply to targets not 861 # toolchains, but presubmit checks require that we explicitly exclude them 862 } 863 864 gcc_rust_host_build_tools_toolchain( 865 "${target_name}_for_rust_host_build_tools") { 866 assert(defined(invoker.toolchain_args), 867 "Toolchains must declare toolchain_args") 868 forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY) 869 } 870 871 gcc_system_allocator_toolchain("${target_name}_host_with_system_allocator") { 872 assert(defined(invoker.toolchain_args), 873 "Toolchains must declare toolchain_args") 874 forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY) 875 } 876 gcc_system_allocator_toolchain("${target_name}_with_system_allocator") { 877 assert(defined(invoker.toolchain_args), 878 "Toolchains must declare toolchain_args") 879 forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY) 880 } 881} 882 883# This is a shorthand for gcc_toolchain instances based on the Chromium-built 884# version of Clang. Only the toolchain_cpu and toolchain_os variables need to 885# be specified by the invoker, and optionally toolprefix if it's a 886# cross-compile case. Note that for a cross-compile case this toolchain 887# requires a config to pass the appropriate -target option, or else it will 888# actually just be doing a native compile. 889template("clang_toolchain") { 890 gcc_toolchain(target_name) { 891 _path = "$clang_base_path/bin" 892 _is_path_absolute = get_path_info(_path, "abspath") == _path 893 894 # Preserve absolute paths for tools like distcc. 895 if (_is_path_absolute && filter_include([ _path ], [ "//*" ]) == []) { 896 prefix = _path 897 } else { 898 prefix = rebase_path(_path, root_build_dir) 899 } 900 901 cc = "${prefix}/clang" 902 cxx = "${prefix}/clang++" 903 ld = cxx 904 readelf = "${prefix}/llvm-readelf" 905 ar = "${prefix}/llvm-ar" 906 nm = "${prefix}/llvm-nm" 907 908 forward_variables_from(invoker, "*", [ "toolchain_args" ]) 909 910 toolchain_args = { 911 if (defined(invoker.toolchain_args)) { 912 forward_variables_from(invoker.toolchain_args, "*") 913 } 914 is_clang = true 915 } 916 } 917} 918