Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / pigweed / repo / pw_toolchain / generate_toolchain.gni
1 # Copyright 2020 The Pigweed Authors
2 #
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
5 # the License at
6 #
7 #     https://www.apache.org/licenses/LICENSE-2.0
8 #
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
13 # the License.
14
15 import("//build_overrides/pigweed.gni")
16
17 import("$dir_pw_toolchain/universal_tools.gni")
18
19 declare_args() {
20   # Scope defining the current toolchain. Contains all of the arguments required
21   # by the generate_toolchain template.
22   pw_toolchain_SCOPE = {
23   }
24
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 = ""
29 }
30
31 # Creates a toolchain target.
32 #
33 # Args:
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
38 #     for the $host_os.
39 #   final_binary_extension: (optional) The extension to apply to final linked
40 #     binaries.
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
47 #
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".
53 #
54 template("generate_toolchain") {
55   assert(defined(invoker.defaults), "toolchain is missing 'defaults'")
56
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
63
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 = ""
68     }
69     if (!defined(invoker_toolchain_args.current_os)) {
70       invoker_toolchain_args.current_os = ""
71     }
72
73     # Determine OS of toolchain, which is the builtin argument "current_os".
74     toolchain_os = invoker_toolchain_args.current_os
75
76     toolchain(target_name) {
77       assert(defined(invoker.cc), "toolchain is missing 'cc'")
78       tool("asm") {
79         if (pw_command_launcher != "") {
80           command_launcher = pw_command_launcher
81         }
82         depfile = "{{output}}.d"
83         command = string_join(" ",
84                               [
85                                 invoker.cc,
86                                 "-MMD -MF $depfile",  # Write out dependencies.
87                                 "{{asmflags}}",
88                                 "{{cflags}}",
89                                 "{{defines}}",
90                                 "{{include_dirs}}",
91                                 "-c {{source}}",
92                                 "-o {{output}}",
93                               ])
94         depsformat = "gcc"
95         description = "as {{output}}"
96         outputs = [
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",
101         ]
102       }
103
104       tool("cc") {
105         if (pw_command_launcher != "") {
106           command_launcher = pw_command_launcher
107         }
108         depfile = "{{output}}.d"
109         command = string_join(" ",
110                               [
111                                 invoker.cc,
112                                 "-MMD -MF $depfile",  # Write out dependencies.
113                                 "{{cflags}}",
114                                 "{{cflags_c}}",  # Must come after {{cflags}}.
115                                 "{{defines}}",
116                                 "{{include_dirs}}",
117                                 "-c {{source}}",
118                                 "-o {{output}}",
119                               ])
120         depsformat = "gcc"
121         description = "cc {{output}}"
122         outputs = [
123           "{{source_out_dir}}/{{target_output_name}}.{{source_file_part}}.o",
124         ]
125       }
126
127       assert(defined(invoker.cxx), "toolchain is missing 'cxx'")
128       tool("cxx") {
129         if (pw_command_launcher != "") {
130           command_launcher = pw_command_launcher
131         }
132         depfile = "{{output}}.d"
133         command = string_join(" ",
134                               [
135                                 invoker.cxx,
136                                 "-MMD -MF $depfile",  # Write out dependencies.
137                                 "{{cflags}}",
138                                 "{{cflags_cc}}",  # Must come after {{cflags}}.
139                                 "{{defines}}",
140                                 "{{include_dirs}}",
141                                 "-c {{source}}",
142                                 "-o {{output}}",
143                               ])
144         depsformat = "gcc"
145         description = "c++ {{output}}"
146         outputs = [
147           "{{source_out_dir}}/{{target_output_name}}.{{source_file_part}}.o",
148         ]
149       }
150
151       tool("objc") {
152         if (pw_command_launcher != "") {
153           command_launcher = pw_command_launcher
154         }
155         depfile = "{{output}}.d"
156         command =
157             string_join(" ",
158                         [
159                           invoker.cc,
160                           "-MMD -MF $depfile",  # Write out dependencies.
161                           "{{cflags}}",
162                           "{{cflags_objc}}",  # Must come after {{cflags}}.
163                           "{{defines}}",
164                           "{{include_dirs}}",
165                           "{{framework_dirs}}",
166                           "-c {{source}}",
167                           "-o {{output}}",
168                         ])
169         depsformat = "gcc"
170         description = "objc {{output}}"
171         outputs = [
172           "{{source_out_dir}}/{{target_output_name}}.{{source_file_part}}.o",
173         ]
174       }
175
176       tool("objcxx") {
177         if (pw_command_launcher != "") {
178           command_launcher = pw_command_launcher
179         }
180         depfile = "{{output}}.d"
181         command =
182             string_join(" ",
183                         [
184                           invoker.cxx,
185                           "-MMD -MF $depfile",  # Write out dependencies.
186                           "{{cflags}}",
187                           "{{cflags_objcc}}",  # Must come after {{cflags}}.
188                           "{{defines}}",
189                           "{{include_dirs}}",
190                           "{{framework_dirs}}",
191                           "-c {{source}}",
192                           "-o {{output}}",
193                         ])
194         depsformat = "gcc"
195         description = "objc++ {{output}}"
196         outputs = [
197           "{{source_out_dir}}/{{target_output_name}}.{{source_file_part}}.o",
198         ]
199       }
200
201       assert(defined(invoker.ar), "toolchain is missing 'ar'")
202       tool("alink") {
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\""
208         } else {
209           command =
210               "rm -f {{output}} && ${invoker.ar} rcs {{output}} {{inputs}}"
211         }
212
213         description = "ar {{target_output_name}}{{output_extension}}"
214         outputs =
215             [ "{{output_dir}}/{{target_output_name}}{{output_extension}}" ]
216         default_output_extension = ".a"
217         default_output_dir = "{{target_out_dir}}/lib"
218       }
219
220       lib_switch = "-l"
221       lib_dir_switch = "-L"
222
223       _link_outfile =
224           "{{output_dir}}/{{target_output_name}}{{output_extension}}"
225       _link_mapfile = "{{output_dir}}/{{target_output_name}}.map"
226       _link_flags = [
227         invoker.cxx,
228         "{{ldflags}}",
229       ]
230
231       if (toolchain_os == "mac" || toolchain_os == "ios") {
232         _link_flags += [
233           # Output a map file that shows symbols and their location.
234           "-Wl,-map,$_link_mapfile",
235
236           # Delete unreferenced sections. Helpful with -ffunction-sections.
237           "-Wl,-dead_strip",
238         ]
239       } else {
240         _link_flags += [
241           # Output a map file that shows symbols and their location.
242           "-Wl,-Map,$_link_mapfile",
243
244           # Delete unreferenced sections. Helpful with -ffunction-sections.
245           "-Wl,--gc-sections",
246         ]
247       }
248
249       _link_group = defined(invoker.link_group) && invoker.link_group
250       if (_link_group) {
251         _link_flags += [ "-Wl,--start-group" ]
252       }
253       _link_flags += [ "{{inputs}}" ]
254       _link_flags += [ "{{frameworks}}" ]
255
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
261         # safest option.
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.
265         _link_flags += [
266           "-Wl,--whole-archive",
267           "{{libs}}",
268           "-Wl,--no-whole-archive",
269         ]
270       } else {
271         _link_flags += [ "{{libs}}" ]
272       }
273
274       if (_link_group) {
275         _link_flags += [ "-Wl,--end-group" ]
276       }
277       _link_flags += [ "-o $_link_outfile" ]
278
279       _link_command = string_join(" ", _link_flags)
280
281       tool("link") {
282         command = _link_command
283         description = "ld $_link_outfile"
284         outputs = [ _link_outfile ]
285         default_output_dir = "{{target_out_dir}}/bin"
286
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"
291         } else {
292           default_output_extension = ""
293         }
294       }
295
296       tool("solink") {
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"
302       }
303
304       tool("stamp") {
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, "*")
309       }
310
311       tool("copy") {
312         # GN-ism: GN gets mad if you directly forward the contents of
313         # pw_universal_copy.
314         _copy = pw_universal_copy
315         forward_variables_from(_copy, "*")
316       }
317
318       # Build arguments to be overridden when compiling cross-toolchain:
319       #
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.
323       #
324       #   pw_toolchain_SCOPE: A copy of the invoker scope that defines the
325       #     toolchain. Used for generating derivative toolchains.
326       #
327       toolchain_args = {
328         pw_toolchain_SCOPE = {
329         }
330         pw_toolchain_SCOPE = {
331           forward_variables_from(invoker, "*")
332         }
333         forward_variables_from(invoker_toolchain_args, "*")
334       }
335     }
336   } else {
337     not_needed(invoker, "*")
338     group(target_name) {
339     }
340   }
341 }
342
343 # Creates a series of toolchain targets with common compiler options.
344 #
345 # Args:
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")
353
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" ])
359     }
360   }
361 }