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