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