1 # Copyright 2020 The Pigweed Authors
3 # Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 # use this file except in compliance with the License. You may obtain a copy of
7 # https://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 # License for the specific language governing permissions and limitations under
15 import("//build_overrides/pigweed.gni")
17 import("$dir_pw_toolchain/universal_tools.gni")
20 # Scope defining the current toolchain. Contains all of the arguments required
21 # by the generate_toolchain template.
22 pw_toolchain_SCOPE = {
25 # Prefix for compilation commands (e.g. the path to a Goma or CCache compiler
26 # launcher). Example for ccache:
27 # gn gen out --args='pw_command_launcher="ccache"'
28 pw_command_launcher = ""
31 # Creates a toolchain target.
34 # ar: (required) String indicating the archive tool to use.
35 # cc: (required) String indicating the C compiler to use.
36 # cxx: (required) String indicating the C++ compiler to use.
37 # is_host_toolchain: (optional) Boolean indicating if the outputs are meant
39 # final_binary_extension: (optional) The extension to apply to final linked
41 # link_whole_archive: (optional) Boolean indicating if the linker should load
42 # all object files when resolving symbols.
43 # link_group: (optional) Boolean indicating if the linker should use
44 # a group to resolve circular dependencies between artifacts.
45 # defaults: (required) A scope setting defaults to apply to GN
46 # targets in this toolchain, as described in pw_vars_default.gni
48 # The defaults scope should contain values for builtin GN arguments:
49 # current_cpu: The CPU of the toolchain.
50 # Well known values include "arm", "arm64", "x64", "x86", and "mips".
51 # current_os: The OS of the toolchain. Defaults to "".
52 # Well known values include "win", "mac", "linux", "android", and "ios".
54 template("generate_toolchain") {
55 assert(defined(invoker.defaults), "toolchain is missing 'defaults'")
57 # In multi-toolchain builds from the top level, we run into issues where
58 # toolchains defined with this template are re-generated each time. To avoid
59 # collisions, the actual toolchain is only generated for the default (dummy)
60 # toolchain, and an unused target is created otherwise.
61 if (current_toolchain == default_toolchain) {
62 invoker_toolchain_args = invoker.defaults
64 # These values should always be set as they influence toolchain
65 # behavior, but allow them to be unset as a transitional measure.
66 if (!defined(invoker_toolchain_args.current_cpu)) {
67 invoker_toolchain_args.current_cpu = ""
69 if (!defined(invoker_toolchain_args.current_os)) {
70 invoker_toolchain_args.current_os = ""
73 # Determine OS of toolchain, which is the builtin argument "current_os".
74 toolchain_os = invoker_toolchain_args.current_os
76 toolchain(target_name) {
77 assert(defined(invoker.cc), "toolchain is missing 'cc'")
79 if (pw_command_launcher != "") {
80 command_launcher = pw_command_launcher
82 depfile = "{{output}}.d"
83 command = string_join(" ",
86 "-MMD -MF $depfile", # Write out dependencies.
95 description = "as {{output}}"
97 # Use {{source_file_part}}, which includes the extension, instead of
98 # {{source_name_part}} so that object files created from <file_name>.c
99 # and <file_name>.cc sources are unique.
100 "{{source_out_dir}}/{{target_output_name}}.{{source_file_part}}.o",
105 if (pw_command_launcher != "") {
106 command_launcher = pw_command_launcher
108 depfile = "{{output}}.d"
109 command = string_join(" ",
112 "-MMD -MF $depfile", # Write out dependencies.
114 "{{cflags_c}}", # Must come after {{cflags}}.
121 description = "cc {{output}}"
123 "{{source_out_dir}}/{{target_output_name}}.{{source_file_part}}.o",
127 assert(defined(invoker.cxx), "toolchain is missing 'cxx'")
129 if (pw_command_launcher != "") {
130 command_launcher = pw_command_launcher
132 depfile = "{{output}}.d"
133 command = string_join(" ",
136 "-MMD -MF $depfile", # Write out dependencies.
138 "{{cflags_cc}}", # Must come after {{cflags}}.
145 description = "c++ {{output}}"
147 "{{source_out_dir}}/{{target_output_name}}.{{source_file_part}}.o",
152 if (pw_command_launcher != "") {
153 command_launcher = pw_command_launcher
155 depfile = "{{output}}.d"
160 "-MMD -MF $depfile", # Write out dependencies.
162 "{{cflags_objc}}", # Must come after {{cflags}}.
165 "{{framework_dirs}}",
170 description = "objc {{output}}"
172 "{{source_out_dir}}/{{target_output_name}}.{{source_file_part}}.o",
177 if (pw_command_launcher != "") {
178 command_launcher = pw_command_launcher
180 depfile = "{{output}}.d"
185 "-MMD -MF $depfile", # Write out dependencies.
187 "{{cflags_objcc}}", # Must come after {{cflags}}.
190 "{{framework_dirs}}",
195 description = "objc++ {{output}}"
197 "{{source_out_dir}}/{{target_output_name}}.{{source_file_part}}.o",
201 assert(defined(invoker.ar), "toolchain is missing 'ar'")
203 if (host_os == "win") {
204 rspfile = "{{output}}.rsp"
205 rspfile_content = "{{inputs}}"
206 rm_command = "del /F /Q \"{{output}}\" 2> NUL"
207 command = "cmd /c \"($rm_command) & ${invoker.ar} rcs {{output}} @$rspfile\""
210 "rm -f {{output}} && ${invoker.ar} rcs {{output}} {{inputs}}"
213 description = "ar {{target_output_name}}{{output_extension}}"
215 [ "{{output_dir}}/{{target_output_name}}{{output_extension}}" ]
216 default_output_extension = ".a"
217 default_output_dir = "{{target_out_dir}}/lib"
221 lib_dir_switch = "-L"
224 "{{output_dir}}/{{target_output_name}}{{output_extension}}"
225 _link_mapfile = "{{output_dir}}/{{target_output_name}}.map"
231 if (toolchain_os == "mac" || toolchain_os == "ios") {
233 # Output a map file that shows symbols and their location.
234 "-Wl,-map,$_link_mapfile",
236 # Delete unreferenced sections. Helpful with -ffunction-sections.
241 # Output a map file that shows symbols and their location.
242 "-Wl,-Map,$_link_mapfile",
244 # Delete unreferenced sections. Helpful with -ffunction-sections.
249 _link_group = defined(invoker.link_group) && invoker.link_group
251 _link_flags += [ "-Wl,--start-group" ]
253 _link_flags += [ "{{inputs}}" ]
254 _link_flags += [ "{{frameworks}}" ]
256 if (defined(invoker.link_whole_archive) && invoker.link_whole_archive) {
257 # Load all object files from all libraries to resolve symbols.
258 # Short of living in the ideal world where all dependency graphs
259 # among static libs are acyclic and all developers diligently
260 # express such graphs in terms that GN understands, this is the
262 # Make sure you use this with --gc-sections, otherwise the
263 # resulting binary will contain every symbol defined in every
264 # input file and every static library. That could be quite a lot.
266 "-Wl,--whole-archive",
268 "-Wl,--no-whole-archive",
271 _link_flags += [ "{{libs}}" ]
275 _link_flags += [ "-Wl,--end-group" ]
277 _link_flags += [ "-o $_link_outfile" ]
279 _link_command = string_join(" ", _link_flags)
282 command = _link_command
283 description = "ld $_link_outfile"
284 outputs = [ _link_outfile ]
285 default_output_dir = "{{target_out_dir}}/bin"
287 if (defined(invoker.final_binary_extension)) {
288 default_output_extension = invoker.final_binary_extension
289 } else if (toolchain_os == "win") {
290 default_output_extension = ".exe"
292 default_output_extension = ""
297 command = _link_command + " -shared"
298 description = "ld -shared $_link_outfile"
299 outputs = [ _link_outfile ]
300 default_output_dir = "{{target_out_dir}}/lib"
301 default_output_extension = ".so"
305 # GN-ism: GN gets mad if you directly forward the contents of
306 # pw_universal_stamp.
307 _stamp = pw_universal_stamp
308 forward_variables_from(_stamp, "*")
312 # GN-ism: GN gets mad if you directly forward the contents of
314 _copy = pw_universal_copy
315 forward_variables_from(_copy, "*")
318 # Build arguments to be overridden when compiling cross-toolchain:
320 # pw_toolchain_defaults: A scope setting defaults to apply to GN targets
321 # in this toolchain. It is analogous to $pw_target_defaults in
322 # $dir_pigweed/pw_vars_default.gni.
324 # pw_toolchain_SCOPE: A copy of the invoker scope that defines the
325 # toolchain. Used for generating derivative toolchains.
328 pw_toolchain_SCOPE = {
330 pw_toolchain_SCOPE = {
331 forward_variables_from(invoker, "*")
333 forward_variables_from(invoker_toolchain_args, "*")
337 not_needed(invoker, "*")
343 # Creates a series of toolchain targets with common compiler options.
346 # toolchains: List of scopes defining each of the desired toolchains.
347 # The scope must contain a "name" variable; other variables are forwarded to
348 # $generate_toolchain.
349 template("generate_toolchains") {
350 not_needed([ "target_name" ])
351 assert(defined(invoker.toolchains),
352 "generate_toolchains must be called with a list of toolchains")
354 # Create a target for each of the desired toolchains, appending its own cflags
355 # and ldflags to the common ones.
356 foreach(_toolchain, invoker.toolchains) {
357 generate_toolchain(_toolchain.name) {
358 forward_variables_from(_toolchain, "*", [ "name" ])