xref: /aosp_15_r20/external/angle/build/toolchain/gcc_toolchain.gni (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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