• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) 2013 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5# This value will be inherited in the toolchain below.
6concurrent_links = exec_script("get_concurrent_links.py", [], "value")
7
8# This template defines a toolchain for something that works like gcc
9# (including clang).
10#
11# It requires the following variables specifying the executables to run:
12#  - cc
13#  - cxx
14#  - ar
15#  - ld
16# and the following which is used in the toolchain_args
17#  - toolchain_cpu_arch  (What "cpu_arch" should be set to when invoking a
18#                         build using this toolchain.)
19#  - toolchain_os  (What "os" should be set to when invoking a build using this
20#                   toolchain.)
21#
22# Optional parameters:
23#  - libs_section_prefix
24#  - libs_section_postfix
25#      The contents of these strings, if specified, will be placed around
26#      the libs section of the linker line. It allows one to inject libraries
27#      at the beginning and end for all targets in a toolchain.
28#  - solink_libs_section_prefix
29#  - solink_libs_section_postfix
30#      Same as libs_section_{pre,post}fix except used for solink instead of link.
31#  - post_solink
32#      The content of this string, if specified, will be appended to the solink
33#      command.
34#  - deps
35#      Just forwarded to the toolchain definition.
36#  - is_clang
37template("gcc_toolchain") {
38  toolchain(target_name) {
39    assert(defined(invoker.cc), "gcc_toolchain() must specify a \"cc\" value")
40    assert(defined(invoker.cxx), "gcc_toolchain() must specify a \"cxx\" value")
41    assert(defined(invoker.ar), "gcc_toolchain() must specify a \"ar\" value")
42    assert(defined(invoker.ld), "gcc_toolchain() must specify a \"ld\" value")
43    assert(defined(invoker.toolchain_cpu_arch),
44           "gcc_toolchain() must specify a \"toolchain_cpu_arch\"")
45    assert(defined(invoker.toolchain_os),
46           "gcc_toolchain() must specify a \"toolchain_os\"")
47
48    # We can't do string interpolation ($ in strings) on things with dots in
49    # them. To allow us to use $cc below, for example, we create copies of
50    # these values in our scope.
51    cc = invoker.cc
52    cxx = invoker.cxx
53    ar = invoker.ar
54    ld = invoker.ld
55
56    # Bring these into our scope for string interpolation with default values.
57    if (defined(invoker.libs_section_prefix)) {
58      libs_section_prefix = invoker.libs_section_prefix
59    } else {
60      libs_section_prefix = ""
61    }
62
63    if (defined(invoker.libs_section_postfix)) {
64      libs_section_postfix = invoker.libs_section_postfix
65    } else {
66      libs_section_postfix = ""
67    }
68
69    if (defined(invoker.solink_libs_section_prefix)) {
70      solink_libs_section_prefix = invoker.solink_libs_section_prefix
71    } else {
72      solink_libs_section_prefix = ""
73    }
74
75    if (defined(invoker.solink_libs_section_postfix)) {
76      solink_libs_section_postfix = invoker.solink_libs_section_postfix
77    } else {
78      solink_libs_section_postfix = ""
79    }
80
81    # These library switches can apply to all tools below.
82    lib_switch = "-l"
83    lib_dir_switch = "-L"
84
85    tool("cc") {
86      depfile = "{{output}}.d"
87      command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
88      depsformat = "gcc"
89      description = "CC {{output}}"
90      outputs = [
91        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
92      ]
93    }
94
95    tool("cxx") {
96      depfile = "{{output}}.d"
97      command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}"
98      depsformat = "gcc"
99      description = "CXX {{output}}"
100      outputs = [
101        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
102      ]
103    }
104
105    tool("asm") {
106      # For GCC we can just use the C compiler to compile assembly.
107      depfile = "{{output}}.d"
108      command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}"
109      depsformat = "gcc"
110      description = "ASM {{output}}"
111      outputs = [
112        "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o",
113      ]
114    }
115
116    tool("alink") {
117      rspfile = "{{output}}.rsp"
118      command = "rm -f {{output}} && $ar rcs {{output}} @$rspfile"
119      description = "AR {{output}}"
120      rspfile_content = "{{inputs}}"
121      outputs = [
122        "{{target_out_dir}}/{{target_output_name}}{{output_extension}}"
123      ]
124      default_output_extension = ".a"
125      output_prefix = "lib"
126    }
127
128    tool("solink") {
129      soname = "{{target_output_name}}{{output_extension}}"  # e.g. "libfoo.so".
130      sofile = "{{root_out_dir}}/$soname"  # Possibly including toolchain dir.
131      rspfile = sofile + ".rsp"
132
133      # These variables are not built into GN but are helpers that implement
134      # (1) linking to produce a .so, (2) extracting the symbols from that file
135      # to a temporary file, (3) if the temporary file has differences from the
136      # existing .TOC file, overwrite it, otherwise, don't change it.
137      tocfile = sofile + ".TOC"
138      temporary_tocname = sofile + ".tmp"
139      link_command = "$ld -shared {{ldflags}} -o $sofile -Wl,-soname=$soname @$rspfile"
140      toc_command = "{ readelf -d $sofile | grep SONAME ; nm -gD -f p $soname | cut -f1-2 -d' '; } > $temporary_tocname"
141      replace_command = "if ! cmp -s $temporary_tocname $tocfile; then mv $temporary_tocname $tocfile; fi"
142
143      command = "$link_command && $toc_command && $replace_command"
144      if (defined(invoker.postsolink)) {
145        command += " && " + invoker.postsolink
146      }
147      rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive $solink_libs_section_prefix {{libs}} $solink_libs_section_postfix"
148
149      description = "SOLINK $sofile"
150
151      # Use this for {{output_extension}} expansions unless a target manually
152      # overrides it (in which case {{output_extension}} will be what the target
153      # specifies).
154      default_output_extension = ".so"
155
156      output_prefix = "lib"
157
158      # Since the above commands only updates the .TOC file when it changes, ask
159      # Ninja to check if the timestamp actually changed to know if downstream
160      # dependencies should be recompiled.
161      restat = true
162
163      # Tell GN about the output files. It will link to the sofile but use the
164      # tocfile for dependency management.
165      outputs = [
166        sofile,
167        tocfile,
168      ]
169      if (defined(invoker.solink_outputs)) {
170        outputs += invoker.solink_outputs
171      }
172      link_output = sofile
173      depend_output = tocfile
174    }
175
176    tool("link") {
177      outfile = "{{root_out_dir}}/{{target_output_name}}{{output_extension}}"
178      rspfile = "$outfile.rsp"
179      command = "$ld {{ldflags}} -o $outfile -Wl,--start-group @$rspfile {{solibs}} -Wl,--end-group $libs_section_prefix {{libs}} $libs_section_postfix"
180      if (defined(invoker.postlink)) {
181        command += " && " + invoker.postlink
182      }
183      description = "LINK $outfile"
184      rspfile_content = "{{inputs}}"
185      outputs = [ outfile ]
186      if (defined(invoker.link_outputs)) {
187        outputs += invoker.link_outputs
188      }
189    }
190
191    tool("stamp") {
192      command = "touch {{output}}"
193      description = "STAMP {{output}}"
194    }
195
196    tool("copy") {
197      command = "ln -f {{source}} {{output}} 2>/dev/null || (rm -rf {{output}} && cp -af {{source}} {{output}})"
198      description = "COPY {{source}} {{output}}"
199    }
200
201    # When invoking this toolchain not as the default one, these args will be
202    # passed to the build. They are ignored when this is the default toolchain.
203    toolchain_args() {
204      cpu_arch = invoker.toolchain_cpu_arch
205      os = invoker.toolchain_os
206      if (defined(invoker.is_clang)) {
207        is_clang = invoker.is_clang
208      }
209    }
210
211    if (defined(invoker.deps)) {
212      deps = invoker.deps
213    }
214  }
215}
216