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