• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# Copyright (c) 2013 The Chromium Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7import("//build/config/clang/clang.gni")
8import("//build/config/compiler/compiler.gni")
9import("//build/config/sanitizers/sanitizers.gni")
10import("//build/config/v8_target_cpu.gni")
11import("//build/toolchain/cc_wrapper.gni")
12import("//build/toolchain/clang_static_analyzer.gni")
13import("//build/toolchain/toolchain.gni")
14
15if (is_nacl) {
16  # To keep NaCl variables out of builds that don't include NaCl, all
17  # variables defined in nacl/config.gni referenced here should be protected by
18  # is_nacl conditions.
19  import("//build/config/nacl/config.gni")
20}
21
22declare_args() {
23  # Enables allowlist generation for IDR_ grit defines seen by the compiler.
24  # Currently works only on ohos and enabled by default for release builds.
25  # Requires debug info, so disabled for symbol_level=0 & strip_debug_info=true.
26  enable_resource_allowlist_generation =
27      is_ohos && !is_debug &&
28      # Always enable for official builds, but enable for release builds by
29      # default only when other args allow.
30      (is_official_build ||
31       (!strip_debug_info && symbol_level > 0 && !is_component_build))
32}
33
34declare_args() {
35  share_ccache = ""
36}
37
38# When the arg is set via args.gn, it applies to all toolchains. In order to not
39# hit the assert in grit_rule.gni, explicitly disable for host toolchains.
40if (is_linux && target_os == "ohos") {
41  enable_resource_allowlist_generation = false
42}
43
44# Path to the Clang static analysis wrapper script.
45# REVIEWERS: can you suggest a better location for this?
46# GN is really picky about dead stores of variables except at the global scope.
47analyzer_wrapper =
48    rebase_path("//build/toolchain/clang_static_analyzer_wrapper.py",
49                root_build_dir) + " --mode=clang"
50
51# This template defines a toolchain for something that works like gcc
52# (including clang).
53#
54# It requires the following variables specifying the executables to run:
55#  - ar
56#  - cc
57#  - cxx
58#  - ld
59#
60# Optional parameters that control the tools:
61#
62#  - extra_cflags
63#      Extra flags to be appended when compiling C files (but not C++ files).
64#  - extra_cppflags
65#      Extra flags to be appended when compiling both C and C++ files. "CPP"
66#      stands for "C PreProcessor" in this context, although it can be
67#      used for non-preprocessor flags as well. Not to be confused with
68#      "CXX" (which follows).
69#  - extra_cxxflags
70#      Extra flags to be appended when compiling C++ files (but not C files).
71#  - extra_asmflags
72#      Extra flags to be appended when compiling assembly.
73#  - extra_ldflags
74#      Extra flags to be appended when linking
75#
76#  - libs_section_prefix
77#  - libs_section_postfix
78#      The contents of these strings, if specified, will be placed around
79#      the libs section of the linker line. It allows one to inject libraries
80#      at the beginning and end for all targets in a toolchain.
81#  - solink_libs_section_prefix
82#  - solink_libs_section_postfix
83#      Same as libs_section_{pre,post}fix except used for solink instead of link.
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/.
113template("gcc_toolchain") {
114  toolchain(target_name) {
115    assert(defined(invoker.ar), "gcc_toolchain() must specify a \"ar\" value")
116    assert(defined(invoker.cc), "gcc_toolchain() must specify a \"cc\" value")
117    assert(defined(invoker.cxx), "gcc_toolchain() must specify a \"cxx\" value")
118    assert(defined(invoker.ld), "gcc_toolchain() must specify a \"ld\" value")
119
120    # This define changes when the toolchain changes, forcing a rebuild.
121    # Nothing should ever use this define.
122    if (defined(invoker.rebuild_define)) {
123      rebuild_string = "-D" + invoker.rebuild_define + " "
124    } else {
125      rebuild_string = ""
126    }
127
128    # GN's syntax can't handle more than one scope dereference at once, like
129    # "invoker.toolchain_args.foo", so make a temporary to hold the toolchain
130    # args so we can do "invoker_toolchain_args.foo".
131    assert(defined(invoker.toolchain_args),
132           "Toolchains must specify toolchain_args")
133    invoker_toolchain_args = invoker.toolchain_args
134    assert(defined(invoker_toolchain_args.current_cpu),
135           "toolchain_args must specify a current_cpu")
136    assert(defined(invoker_toolchain_args.current_os),
137           "toolchain_args must specify a current_os")
138
139    # When invoking this toolchain not as the default one, these args will be
140    # passed to the build. They are ignored when this is the default toolchain.
141    toolchain_args = {
142      # Populate toolchain args from the invoker.
143      forward_variables_from(invoker_toolchain_args, "*")
144
145      # The host toolchain value computed by the default toolchain's setup
146      # needs to be passed through unchanged to all secondary toolchains to
147      # ensure that it's always the same, regardless of the values that may be
148      # set on those toolchains.
149      host_toolchain = host_toolchain
150
151      if (!defined(invoker_toolchain_args.v8_current_cpu)) {
152        v8_current_cpu = invoker_toolchain_args.current_cpu
153      }
154    }
155
156    if (defined(toolchain_args.cc_wrapper)) {
157      toolchain_cc_wrapper = toolchain_args.cc_wrapper
158    } else {
159      toolchain_cc_wrapper = cc_wrapper
160    }
161
162    if (is_clang && use_clang_static_analyzer &&
163        (!defined(invoker.is_clang_analysis_supported) ||
164         invoker.is_clang_analysis_supported)) {
165      compiler_prefix = "${analyzer_wrapper} "
166      asm = invoker.cc
167    } else {
168      if (share_ccache != "") {
169        compiler_prefix = "CCACHE_DIR=" + share_ccache +
170                          " CCACHE_NOHASHDIR=1 ${toolchain_cc_wrapper} "
171      } else {
172        compiler_prefix = "${toolchain_cc_wrapper} "
173      }
174    }
175
176    cc = compiler_prefix + invoker.cc
177    cxx = compiler_prefix + invoker.cxx
178    ar = invoker.ar
179    ld = invoker.ld
180    if (!defined(asm)) {
181      asm = cc
182    }
183    if (defined(invoker.readelf)) {
184      readelf = invoker.readelf
185    } else {
186      readelf = "readelf"
187    }
188    if (defined(invoker.nm)) {
189      nm = invoker.nm
190    } else {
191      nm = "nm"
192    }
193
194    if (defined(invoker.shlib_extension)) {
195      default_shlib_extension = invoker.shlib_extension
196    } else {
197      default_shlib_extension = shlib_extension
198    }
199
200    if (defined(invoker.executable_extension)) {
201      default_executable_extension = invoker.executable_extension
202    } else {
203      default_executable_extension = ""
204    }
205
206    # Bring these into our scope for string interpolation with default values.
207    if (defined(invoker.libs_section_prefix)) {
208      libs_section_prefix = invoker.libs_section_prefix
209    } else {
210      libs_section_prefix = ""
211    }
212
213    if (defined(invoker.libs_section_postfix)) {
214      libs_section_postfix = invoker.libs_section_postfix
215    } else {
216      libs_section_postfix = ""
217    }
218
219    if (defined(invoker.solink_libs_section_prefix)) {
220      solink_libs_section_prefix = invoker.solink_libs_section_prefix
221    } else {
222      solink_libs_section_prefix = ""
223    }
224
225    if (defined(invoker.solink_libs_section_postfix)) {
226      solink_libs_section_postfix = invoker.solink_libs_section_postfix
227    } else {
228      solink_libs_section_postfix = ""
229    }
230
231    if (defined(invoker.extra_cflags) && invoker.extra_cflags != "") {
232      extra_cflags = " " + invoker.extra_cflags
233    } else {
234      extra_cflags = ""
235    }
236
237    if (defined(invoker.extra_cppflags) && invoker.extra_cppflags != "") {
238      extra_cppflags = " " + invoker.extra_cppflags
239    } else {
240      extra_cppflags = ""
241    }
242
243    if (defined(invoker.extra_cxxflags) && invoker.extra_cxxflags != "") {
244      extra_cxxflags = " " + invoker.extra_cxxflags
245    } else {
246      extra_cxxflags = ""
247    }
248
249    if (defined(invoker.extra_asmflags) && invoker.extra_asmflags != "") {
250      extra_asmflags = " " + invoker.extra_asmflags
251    } else {
252      extra_asmflags = ""
253    }
254
255    if (defined(invoker.extra_ldflags) && invoker.extra_ldflags != "") {
256      extra_ldflags = " " + invoker.extra_ldflags
257    } else {
258      extra_ldflags = ""
259    }
260
261    enable_linker_map = defined(invoker.enable_linker_map) &&
262                        invoker.enable_linker_map && generate_linker_map
263
264    # These library switches can apply to all tools below.
265    lib_switch = "-l"
266    lib_dir_switch = "-L"
267
268    # Object files go in this directory.
269    object_subdir = "{{source_out_dir}}/{{label_name}}"
270
271    tool("cc") {
272      depfile = "{{output}}.d"
273      command = "$cc -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{cflags}} {{cflags_c}}${extra_cppflags}${extra_cflags} -c {{source}} -o {{output}}"
274      depsformat = "gcc"
275      description = "CC {{output}}"
276      outputs = [ "$object_subdir/{{source_name_part}}.o" ]
277    }
278
279    tool("cxx") {
280      depfile = "{{output}}.d"
281      command = "$cxx -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}}${extra_cppflags}${extra_cxxflags} -c {{source}} -o {{output}}"
282      depsformat = "gcc"
283      description = "CXX {{output}}"
284      outputs = [ "$object_subdir/{{source_name_part}}.o" ]
285    }
286
287    tool("asm") {
288      # For GCC we can just use the C compiler to compile assembly.
289      depfile = "{{output}}.d"
290      command = "$asm -MMD -MF $depfile ${rebuild_string}{{defines}} {{include_dirs}} {{asmflags}}${extra_asmflags} -c {{source}} -o {{output}}"
291      depsformat = "gcc"
292      description = "ASM {{output}}"
293      outputs = [ "$object_subdir/{{source_name_part}}.o" ]
294    }
295
296    tool("alink") {
297      if (current_os == "aix") {
298        # AIX does not support either -D (deterministic output) or response
299        # files.
300        command = "$ar -X64 {{arflags}} -r -c -s {{output}} {{inputs}}"
301      } else {
302        rspfile = "{{output}}.rsp"
303        rspfile_content = "{{inputs}}"
304        command = "\"$ar\" {{arflags}} -r -c -s -D {{output}} @\"$rspfile\""
305      }
306
307      # Remove the output file first so that ar doesn't try to modify the
308      # existing file.
309      if (host_os == "win") {
310        tool_wrapper_path =
311            rebase_path("//build/toolchain/win/tool_wrapper.py", root_build_dir)
312        command = "cmd /c $python_path $tool_wrapper_path delete-file {{output}} && $command"
313      } else {
314        command = "rm -f {{output}} && $command"
315      }
316
317      # Almost all targets build with //build/config/compiler:thin_archive which
318      # adds -T to arflags.
319      description = "AR {{output}}"
320      outputs = [ "{{output_dir}}/{{target_output_name}}{{output_extension}}" ]
321
322      # Shared libraries go in the target out directory by default so we can
323      # generate different targets with the same name and not have them collide.
324      default_output_dir = "{{target_out_dir}}"
325      default_output_extension = ".a"
326      output_prefix = "lib"
327    }
328
329    tool("solink") {
330      soname = "{{target_output_name}}{{output_extension}}"  # e.g. "libfoo.so".
331      sofile = "{{output_dir}}/$soname"  # Possibly including toolchain dir.
332      rspfile = sofile + ".rsp"
333      pool = "//build/toolchain:link_pool($default_toolchain)"
334
335      is_mingw_link = false
336      if (invoker_toolchain_args.current_os == "mingw") {
337        is_mingw_link = true
338        libname = "{{target_output_name}}.lib"
339        libfile = "{{output_dir}}/$libname"
340      }
341
342      if (defined(invoker.strip)) {
343        unstripped_sofile = "{{root_out_dir}}/lib.unstripped/$sofile"
344      } else {
345        unstripped_sofile = sofile
346      }
347
348      link_command = "$ld -shared {{ldflags}}${extra_ldflags} -o \"$unstripped_sofile\" @\"$rspfile\""
349      if (!is_mingw_link) {
350        link_command = "$link_command -Wl,-soname=\"$soname\""
351      } else {
352        link_command = "$link_command -Wl,--out-implib,{{root_out_dir}}/lib.unstripped/$libfile"
353      }
354
355      # Generate a map file to be used for binary size analysis.
356      # Map file adds ~10% to the link time on a z620.
357      map_switch = ""
358      if (enable_linker_map && is_official_build) {
359        map_file = "$unstripped_sofile.map.gz"
360        map_switch = " --map-file \"$map_file\""
361      }
362
363      assert(defined(readelf), "to solink you must have a readelf")
364      assert(defined(nm), "to solink you must have an nm")
365      strip_switch = ""
366      if (defined(invoker.strip)) {
367        strip_switch = "--strip=${invoker.strip} "
368      }
369
370      # This needs a Python script to avoid using a complex shell command
371      # requiring sh control structures, pipelines, and POSIX utilities.
372      # The host might not have a POSIX shell and utilities (e.g. Windows).
373      solink_wrapper =
374          rebase_path("//build/toolchain/gcc_solink_wrapper.py", root_build_dir)
375      command = "$python_path \"$solink_wrapper\" --readelf=\"$readelf\" --nm=\"$nm\" $strip_switch --sofile=\"$unstripped_sofile\" $map_switch --output=\"$sofile\""
376      if (is_mingw_link) {
377        command = "$command --libfile=\"$libfile\""
378      }
379      if (full_mini_debug && !is_debug) {
380        command = "$command --mini-debug"
381      }
382      command = "$command -- $link_command"
383
384      rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive $solink_libs_section_prefix {{libs}} $solink_libs_section_postfix"
385
386      description = "SOLINK $sofile"
387
388      # Use this for {{output_extension}} expansions unless a target manually
389      # overrides it (in which case {{output_extension}} will be what the target
390      # specifies).
391      default_output_extension = default_shlib_extension
392
393      default_output_dir = "{{root_out_dir}}"
394
395      output_prefix = "lib"
396
397      # Since the above commands only updates the .TOC file when it changes, ask
398      # Ninja to check if the timestamp actually changed to know if downstream
399      # dependencies should be recompiled.
400      restat = true
401
402      # Tell GN about the output files. It will link to the sofile
403      outputs = [ sofile ]
404      if (sofile != unstripped_sofile) {
405        outputs += [ unstripped_sofile ]
406        if (defined(invoker.use_unstripped_as_runtime_outputs) &&
407            invoker.use_unstripped_as_runtime_outputs) {
408          runtime_outputs = [ unstripped_sofile ]
409        }
410      }
411      if (defined(map_file)) {
412        outputs += [ map_file ]
413      }
414
415      if (is_mingw_link) {
416        outputs += [ libfile ]
417        link_output = libfile
418        depend_output = libfile
419      } else {
420        link_output = sofile
421        depend_output = sofile
422      }
423    }
424
425    tool("solink_module") {
426      soname = "{{target_output_name}}{{output_extension}}"  # e.g. "libfoo.so".
427      sofile = "{{output_dir}}/$soname"
428      rspfile = sofile + ".rsp"
429      pool = "//build/toolchain:link_pool($default_toolchain)"
430
431      if (defined(invoker.strip)) {
432        unstripped_sofile = "{{root_out_dir}}/lib.unstripped/$sofile"
433      } else {
434        unstripped_sofile = sofile
435      }
436
437      command = "$ld -shared {{ldflags}}${extra_ldflags} -o \"$unstripped_sofile\" -Wl,-soname=\"$soname\" @\"$rspfile\""
438
439      if (defined(invoker.strip)) {
440        strip_command = "${invoker.strip} -o \"$sofile\" \"$unstripped_sofile\""
441        command += " && " + strip_command
442      }
443      rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive $solink_libs_section_prefix {{libs}} $solink_libs_section_postfix"
444
445      description = "SOLINK_MODULE $sofile"
446
447      # Use this for {{output_extension}} expansions unless a target manually
448      # overrides it (in which case {{output_extension}} will be what the target
449      # specifies).
450      if (defined(invoker.loadable_module_extension)) {
451        default_output_extension = invoker.loadable_module_extension
452      } else {
453        default_output_extension = default_shlib_extension
454      }
455
456      default_output_dir = "{{root_out_dir}}"
457
458      output_prefix = "lib"
459
460      outputs = [ sofile ]
461      if (sofile != unstripped_sofile) {
462        outputs += [ unstripped_sofile ]
463        if (defined(invoker.use_unstripped_as_runtime_outputs) &&
464            invoker.use_unstripped_as_runtime_outputs) {
465          runtime_outputs = [ unstripped_sofile ]
466        }
467      }
468    }
469
470    tool("link") {
471      exename = "{{target_output_name}}{{output_extension}}"
472      outfile = "{{output_dir}}/$exename"
473      rspfile = "$outfile.rsp"
474      unstripped_outfile = outfile
475      pool = "//build/toolchain:link_pool($default_toolchain)"
476
477      # Use this for {{output_extension}} expansions unless a target manually
478      # overrides it (in which case {{output_extension}} will be what the target
479      # specifies).
480      default_output_extension = default_executable_extension
481
482      default_output_dir = "{{root_out_dir}}"
483
484      if (defined(invoker.strip)) {
485        unstripped_outfile = "{{root_out_dir}}/exe.unstripped/$outfile"
486      }
487
488      # Generate a map file to be used for binary size analysis.
489      # Map file adds ~10% to the link time on a z620.
490      map_switch = ""
491      if (enable_linker_map && is_official_build) {
492        map_file = "$unstripped_outfile.map.gz"
493        map_switch = " --map-file \"$map_file\""
494      }
495
496      start_group_flag = ""
497      end_group_flag = ""
498      if (current_os != "aix") {
499        # the "--start-group .. --end-group" feature isn't available on the aix ld.
500        start_group_flag = "-Wl,--start-group"
501        end_group_flag = "-Wl,--end-group "
502      }
503      _clang_rt_dso_full_path = ""
504      if (is_asan && invoker_toolchain_args.current_os == "ohos") {
505        if (invoker_toolchain_args.current_cpu == "arm64") {
506          _clang_rt_dso_full_path = rebase_path(
507                  "$clang_base_path/lib/clang/$clang_version/lib/aarch64-linux-ohos/libclang_rt.asan.so",
508                  root_build_dir)
509        } else {
510          _clang_rt_dso_full_path = rebase_path(
511                  "$clang_base_path/lib/clang/$clang_version/lib/arm-linux-ohos/libclang_rt.asan.so",
512                  root_build_dir)
513        }
514      }
515      link_command = "$ld {{ldflags}}${extra_ldflags} -o \"$unstripped_outfile\" $libs_section_prefix $start_group_flag $_clang_rt_dso_full_path @\"$rspfile\" {{solibs}} {{libs}} $end_group_flag $libs_section_postfix"
516
517      strip_switch = ""
518
519      if (defined(invoker.strip)) {
520        strip_switch = " --strip=\"${invoker.strip}\" --unstripped-file=\"$unstripped_outfile\""
521      }
522      if (is_asan && invoker_toolchain_args.current_os == "ohos") {
523        strip_switch =
524            "$strip_switch --clang_rt_dso_path=\"$_clang_rt_dso_full_path\""
525      }
526
527      link_wrapper =
528          rebase_path("//build/toolchain/gcc_link_wrapper.py", root_build_dir)
529      command = "$python_path \"$link_wrapper\" --output=\"$outfile\"$strip_switch$map_switch "
530      if (full_mini_debug && !is_debug) {
531        command = "$command --mini-debug"
532      }
533      command = "$command -- $link_command"
534      description = "LINK $outfile"
535      rspfile_content = "{{inputs}}"
536      outputs = [ outfile ]
537      if (outfile != unstripped_outfile) {
538        outputs += [ unstripped_outfile ]
539        if (defined(invoker.use_unstripped_as_runtime_outputs) &&
540            invoker.use_unstripped_as_runtime_outputs) {
541          runtime_outputs = [ unstripped_outfile ]
542        }
543      }
544      if (defined(invoker.link_outputs)) {
545        outputs += invoker.link_outputs
546      }
547      if (defined(map_file)) {
548        outputs += [ map_file ]
549      }
550    }
551
552    # These two are really entirely generic, but have to be repeated in
553    # each toolchain because GN doesn't allow a template to be used here.
554    # See //build/toolchain/toolchain.gni for details.
555    tool("stamp") {
556      command = stamp_command
557      description = stamp_description
558    }
559    tool("copy") {
560      command = copy_command
561      description = copy_description
562    }
563
564    tool("action") {
565      pool = "//build/toolchain:action_pool($default_toolchain)"
566    }
567
568    forward_variables_from(invoker, [ "deps" ])
569  }
570}
571
572# This is a shorthand for gcc_toolchain instances based on the Chromium-built
573# version of Clang. Only the toolchain_cpu and toolchain_os variables need to
574# be specified by the invoker, and optionally toolprefix if it's a
575# cross-compile case. Note that for a cross-compile case this toolchain
576# requires a config to pass the appropriate -target option, or else it will
577# actually just be doing a native compile. The invoker can optionally override
578# use_gold too.
579template("clang_toolchain") {
580  if (defined(invoker.toolprefix)) {
581    toolprefix = invoker.toolprefix
582  } else {
583    toolprefix = ""
584  }
585
586  gcc_toolchain(target_name) {
587    prefix = rebase_path("$clang_base_path/bin", root_build_dir)
588    cc = "$prefix/clang"
589    cxx = "$prefix/clang++"
590    ld = cxx
591    readelf = "${toolprefix}readelf"
592    ar = "${prefix}/llvm-ar"
593    nm = "${toolprefix}nm"
594
595    forward_variables_from(invoker,
596                           [
597                             "strip",
598                             "is_clang_analysis_supported",
599                             "enable_linker_map",
600                             "use_unstripped_as_runtime_outputs",
601                           ])
602
603    toolchain_args = {
604      if (defined(invoker.toolchain_args)) {
605        forward_variables_from(invoker.toolchain_args, "*")
606      }
607      is_clang = true
608    }
609
610    if (defined(invoker.shlib_extension) && invoker.shlib_extension != "") {
611      shlib_extension = invoker.shlib_extension
612    }
613  }
614}
615