xref: /aosp_15_r20/external/pigweed/pw_build/BUILD.gn (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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
15import("//build_overrides/pigweed.gni")
16
17import("$dir_pw_build/cc_blob_library.gni")
18import("$dir_pw_build/python.gni")
19import("$dir_pw_build/relative_source_file_names.gni")
20import("$dir_pw_docgen/docs.gni")
21import("$dir_pw_toolchain/generate_toolchain.gni")
22import("$dir_pw_toolchain/traits.gni")
23import("$dir_pw_unit_test/test.gni")
24import("target_types.gni")
25
26# IMPORTANT: The compilation flags in this file must be kept in sync with
27#            the CMake flags pw_build/CMakeLists.txt.
28
29# TODO: b/301262374 - Provide a better way to detect the compiler type.
30is_clang = defined(pw_toolchain_SCOPE.cc) &&
31           get_path_info(pw_toolchain_SCOPE.cc, "file") == "clang"
32
33config("colorize_output") {
34  if (pw_build_COLORIZE_OUTPUT) {
35    cflags = [
36      # Colorize output. Ninja's Clang invocation disables color by default.
37      "-fdiagnostics-color",
38    ]
39    ldflags = cflags
40  }
41}
42
43config("debugging") {
44  # Enable debug symbol generation. This has no effect on final code size.
45  cflags = [ "-g" ]
46  rustflags = [
47    "-Cdebuginfo=2",
48    "-Clink-arg=-g",
49  ]
50}
51
52config("extra_debugging") {
53  # Include things like macro expansion in debug info.
54  cflags = [ "-g3" ]
55  rustflags = [
56    "-Cdebuginfo=2",
57    "-Clink-arg=-g3",
58  ]
59}
60
61# Optimization levels
62config("optimize_debugging") {
63  cflags = [ "-Og" ]
64  ldflags = cflags
65  rustflags = [ "-Clink-arg=-Og" ]
66}
67
68config("optimize_speed") {
69  cflags = [ "-O2" ]
70  ldflags = cflags
71  rustflags = [
72    "-Copt-level=2",
73    "-Clink-arg=-O2",
74  ]
75}
76
77config("optimize_more_speed") {
78  cflags = [ "-O3" ]
79  ldflags = cflags
80  rustflags = [
81    "-Copt-level=3",
82    "-Clink-arg=-O3",
83  ]
84}
85
86config("optimize_size") {
87  cflags = [ "-Os" ]
88  ldflags = cflags
89  rustflags = [
90    "-Copt-level=s",
91    "-Clink-arg=-Os",
92  ]
93}
94
95config("enable_clang_fixed_point_types") {
96  if (is_clang) {
97    cflags = [ "-ffixed-point" ]
98  }
99}
100
101config("enable_clang_mlinliner") {
102  cflags = [
103    # Enable ML inliner.
104    "-mllvm",
105    "-enable-ml-inliner=release",
106  ]
107}
108
109config("enable_clang_gvn_sink_hoist") {
110  cflags = [
111    # Enable GVN sink/hoist.
112    "-mllvm",
113    "-enable-gvn-sink=1",
114    "-mllvm",
115    "-enable-gvn-hoist=1",
116  ]
117}
118
119config("optimize_size_clang") {
120  cflags = [ "-Oz" ]
121  ldflags = [
122    # Identical Code Folding optimization
123    "-Wl,--icf=all",
124
125    # LLD does not recognize `Oz` which is a compiler front-end flag.
126    "-Wl,-O2",
127  ]
128  ldflags += cflags
129  rustflags = []
130  foreach(f, ldflags) {
131    rustflags += [ "-Clink-arg=$f" ]
132  }
133}
134
135# Standard compiler flags to reduce output binary size.
136config("reduced_size") {
137  cflags = [
138    "-fno-common",
139    "-fno-exceptions",
140    "-ffunction-sections",
141    "-fdata-sections",
142    "-fomit-frame-pointer",
143  ]
144  cflags_cc = [ "-fno-rtti" ]
145
146  if (current_os == "mac" || current_os == "ios") {
147    # Delete unreferenced sections. Helpful with -ffunction-sections.
148    ldflags = [ "-Wl,-dead_strip" ]
149    rustflags = [ "-Clink-arg=-Wl,-dead_strip" ]
150  } else {
151    # Delete unreferenced sections. Helpful with -ffunction-sections.
152    ldflags = [ "-Wl,--gc-sections" ]
153    rustflags = [ "-Clink-arg=-Wl,--gc-sections" ]
154  }
155}
156
157config("rust_edition_2015") {
158  rustflags = [ "--edition=2015" ]
159}
160
161config("rust_edition_2018") {
162  rustflags = [ "--edition=2018" ]
163}
164
165config("rust_edition_2021") {
166  rustflags = [ "--edition=2021" ]
167}
168
169config("strict_warnings") {
170  cflags = [
171    "-Wall",
172    "-Wextra",
173    "-Wimplicit-fallthrough",
174    "-Wcast-qual",
175    "-Wundef",
176    "-Wpointer-arith",
177
178    # Make all warnings errors, except for the exemptions below.
179    "-Werror",
180    "-Wno-error=cpp",  # preprocessor #warning statement
181    "-Wno-error=deprecated-declarations",  # [[deprecated]] attribute
182  ]
183  cflags_cc = [ "-Wnon-virtual-dtor" ]
184}
185
186# Thread safety warnings are only supported by Clang.
187config("clang_thread_safety_warnings") {
188  cflags = [ "-Wthread-safety" ]
189  defines = [ "_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS=1" ]
190}
191
192# This config contains warnings that we don't necessarily recommend projects
193# enable, but are enabled for upstream Pigweed for maximum project
194# compatibility.
195config("extra_strict_warnings") {
196  cflags = [
197    "-Wshadow",
198    "-Wredundant-decls",
199  ]
200  cflags_c = [ "-Wstrict-prototypes" ]
201}
202
203# This config contains warnings that are enabled for upstream Pigweed.
204# This config MUST NOT be used downstream to allow for warnings to be
205# added in the future without breaking downstream.
206config("internal_strict_warnings") {
207  configs = [
208    ":internal_strict_warnings_core",
209    ":shadow_all",
210  ]
211}
212
213# Core flags from ":internal_strict_warnings" that are enabled throughout
214# Pigweed. These are split out so ":shadow_all" can be disabled where needed.
215config("internal_strict_warnings_core") {
216  cflags = [ "-Wswitch-enum" ]
217
218  if (is_clang) {
219    cflags += [ "-Wextra-semi" ]
220  } else {
221    # TODO: b/306734552 - On GCC, this only works as a C++ flag.
222    cflags_cc = [ "-Wextra-semi" ]
223  }
224
225  # TODO: b/243069432 - Enable pedantic warnings on Windows when they pass.
226  if (host_os != "win") {
227    configs = [ ":pedantic_warnings" ]
228  }
229}
230
231# Keep "-Wshadow-all" separate so it can be disabled individually.
232config("shadow_all") {
233  if (is_clang) {
234    cflags = [ "-Wshadow-all" ]
235  }
236}
237
238config("pedantic_warnings") {
239  cflags = [
240    # Enable -Wpedantic, but disable a few warnings.
241    "-Wpedantic",
242
243    # Allow designated initializers, which were added in C++20 but widely
244    # supported prior and permitted by the Google style guide.
245    "-Wno-c++20-designator",
246
247    # Allow empty ... arguments in macros, which are permitted in C++20 but
248    # widely supported prior.
249    "-Wno-gnu-zero-variadic-macro-arguments",
250  ]
251
252  if (pw_toolchain_CXX_STANDARD < pw_toolchain_STANDARD.CXX17) {
253    # Allow C++17 attributes in C++14, since Pigweed targets C++17 or newer.
254    cflags += [ "-Wno-c++17-attribute-extensions" ]
255  }
256
257  # TODO: b/333712899 - Enable C23 extension warnings.
258  cflags += [ "-Wno-c23-extensions" ]
259
260  # TODO: b/335021928 - Enable C++ 20 extension warnings.
261  cflags += [ "-Wno-c++20-extensions" ]
262
263  # TODO: b/335328444 - Enable C++ 20 extension warnings.
264  cflags += [ "-Wno-deprecated-pragma" ]
265
266  cflags += [
267    # TODO: b/356904203 - Unblock Clang roll. Missing template argument
268    # warning introduced by Clang produces warnings in third party code.
269    # Remove this warning suppression after addressing the root cause.
270    "-Wno-missing-template-arg-list-after-template-kw",
271
272    # TODO: b/356689444 - Remove no-unknown-warning-option after Clang roll.
273    "-Wno-unknown-warning-option",
274  ]
275}
276
277# Numeric conversion warnings.
278#
279# Originally Pigweed didn't enable this, but we ultimately decided to turn it
280# on since it caused issues with downstream project that enable this warning.
281#
282# b/259746255 tracks converting everything to build with this warning.
283config("conversion_warnings") {
284  # TODO: b/260629756 - Remove Windows restriction once fixed for Windows + GCC.
285  if (host_os != "win") {
286    cflags = [ "-Wconversion" ]
287  }
288}
289
290config("cpp14") {
291  cflags_cc = [ "-std=c++14" ]
292}
293
294config("cpp17") {
295  cflags_cc = [
296    "-std=c++17",
297
298    # Allow uses of the register keyword, which may appear in C headers.
299    "-Wno-register",
300  ]
301}
302
303config("cpp20") {
304  cflags_cc = [
305    "-std=c++20",
306    "-Wno-register",
307  ]
308}
309
310# Selects the C++ standard to used based on the pw_toolchain_CXX_STANDARD
311# toolchain trait.
312config("toolchain_cpp_standard") {
313  if (pw_toolchain_CXX_STANDARD == pw_toolchain_STANDARD.CXX14) {
314    configs = [ ":cpp14" ]
315  } else if (pw_toolchain_CXX_STANDARD == pw_toolchain_STANDARD.CXX17) {
316    configs = [ ":cpp17" ]
317  } else if (pw_toolchain_CXX_STANDARD == pw_toolchain_STANDARD.CXX20) {
318    configs = [ ":cpp20" ]
319  } else {
320    assert(false,
321           "Unexpected pw_toolchain_CXX_STANDARD value: " +
322               pw_toolchain_CXX_STANDARD)
323  }
324}
325
326# Removes system-dependent prefixes from macros like __FILE__ and debug symbols.
327#
328# All compilation is relative to root_build_dir. The root_build_dir path is
329# arbitrary, so it must be removed to make builds reproducible. This config
330# remaps paths as if compilation occurred from the repository root instead of
331# root_build_dir. Paths that include root_build_dir are updated to standardize
332# on out/ as the build directory.
333#
334# If an ELF is built from a directory other than "out/", debuggers will be able
335# to locate in-tree sources, but may have issues finding generated sources in
336# the output directory. This can be worked around in a few ways:
337#
338#   - Use GDB's `set substitute-path <from> <to>` option to remap paths.
339#   - Rebuild from out/.
340#   - Symlink out/ to the build directory.
341#   - Temporarily disable these transformations.
342#
343# If an ELF is built from "out/", debuggers will be able to locate all sources,
344# including generated sources, when run from the repo root.
345config("relative_paths") {
346  # Apply a series of file-prefix-map transformations. Only the first matching
347  # option applies.
348  #
349  # GCC applies these in reverse order due to building iterating through a
350  # recursively constructed linked list:
351  # inclusive-language: disable
352  # https://github.com/gcc-mirror/gcc/blob/master/gcc/file-prefix-map.cc#L41.
353  # inclusive-language: enable
354  #
355  # Clang currently does not have a set forwards or backwards application order
356  # due to storing them in a std::map (that reorders lexicogrpahically by key):
357  # https://github.com/llvm/llvm-project/blob/main/clang/include/clang/Basic/CodeGenOptions.h#L209.
358  #
359  # TODO: b/278906020 - Tracks merging in an upstream change to LLVM to that will
360  # enforce clang applying these transformations in order. Until then, there
361  # will be issues with the debug and coverage information while using build
362  # directories that are more than a single directory from the root project
363  # directory. This is due to "=out/" always being applied first due to the
364  # left-hand side of the = being "", which is always ordered first in the
365  # std::map.
366  _transformations = [
367    # Remap absolute prefixes for files in the output directory to out/.
368    rebase_path(root_build_dir) + "/=out/",
369
370    # Remove the path to the out directory so the ELF is relative to the root.
371    rebase_path(root_build_dir) + "=",
372
373    # Remove any absolute paths to the repo root.
374    rebase_path("//") + "=",
375
376    # Remove the relative path from the build directory to the root, which is
377    # the prefix of in-tree sources.
378    rebase_path("//", root_build_dir) + "=",
379
380    # Prepend out/ to any unmatched files, which are in the output directory.
381    "=out/",
382
383    # Repeat the replacements in reverse order since GCC applies them backwards.
384    rebase_path("//", root_build_dir) + "=",
385    rebase_path("//") + "=",
386    rebase_path(root_build_dir) + "=",
387    rebase_path(root_build_dir) + "/=out/",
388  ]
389
390  cflags = []
391
392  foreach(transform, _transformations) {
393    cflags += [ "-ffile-prefix-map=" + transform ]
394  }
395
396  # Write the transformations to a well known path so that other utilities
397  # that need to present file names that match the compiler's __FILE__
398  # macro can apply the same transformation.
399  write_file(pw_build_RELATIVE_PATH_TRANSFORM_JSON, _transformations, "json")
400}
401
402config("link_with_lld") {
403  ldflags = [ "-fuse-ld=lld" ]
404}
405
406# This group is linked into all pw_executable, pw_static_library, and
407# pw_shared_library targets. This makes it possible to ensure symbols are
408# defined without a dependency on them.
409#
410# pw_build_LINK_DEPS should only be used when necessary. For example,
411# pw_assert relies on pw_build_LINK_DEPS to avoid circular dependencies
412# in GN. In almost all other cases, build targets should explicitly depend on
413# the other targets they use.
414#
415# pw_build_TOOLCHAIN_LINK_DEPS is used to define dependencies introduced by
416# the various toolchains created under pw_toolchain module in GN. For example,
417# LLVM compiler-rt builtin libraries, or the arm-none-eabi newlib interface
418# stubs.
419group("link_deps") {
420  deps = pw_build_LINK_DEPS + pw_build_TOOLCHAIN_LINK_DEPS
421}
422
423# This empty target is used as the default value for module configurations.
424# Projects may set pw_build_DEFAULT_MODULE_CONFIG to a different GN target that
425# overrides modules' configuration options via macro definitions or a header
426# forcibly included with `-include`.
427group("empty") {
428}
429
430config("default_config") {
431  include_dirs = [ "public" ]
432}
433
434# Linker script utility PW_MUST_PLACE
435pw_source_set("must_place") {
436  public_configs = [ ":default_config" ]
437  public = [ "public/pw_build/must_place.ld.h" ]
438}
439
440pw_source_set("linker_symbol") {
441  public_configs = [ ":default_config" ]
442  public = [ "public/pw_build/linker_symbol.h" ]
443  public_deps = [ "$dir_pw_third_party/fuchsia:stdcompat" ]
444}
445
446pw_doc_group("docs") {
447  sources = [
448    "bazel.rst",
449    "cmake.rst",
450    "docs.rst",
451    "gn.rst",
452    "linker_scripts.rst",
453    "project_builder.rst",
454    "python.rst",
455  ]
456}
457
458config("module_config_test_config") {
459  visibility = [ ":*" ]
460  defines = [ "PW_THREAD_FREERTOS_CONFIG_JOINING_ENABLED=1" ]
461}
462
463# Pigweed upstream does not use the default toolchain, but other projects may
464# use it. To support using pw_build from the default toolchain without fully
465# configuring the Pigweed build, only instantiate the pw_build tests for a
466# non-default toolchain.
467if (current_toolchain != default_toolchain) {
468  pw_test("cc_blob_library_test") {
469    sources = [ "cc_blob_library_test.cc" ]
470    deps = [ ":test_blob" ]
471  }
472
473  pw_test("linker_symbol_test") {
474    sources = [ "linker_symbol_test.cc" ]
475    enable_if = current_os == "linux"
476    deps = [ ":linker_symbol" ]
477    inputs = [ "linker_symbol_test.ld" ]
478    ldflags = [
479      "-T",
480      rebase_path("linker_symbol_test.ld", root_build_dir),
481    ]
482  }
483
484  pw_test("module_config_test") {
485    public_configs = [ ":module_config_test_config" ]
486    sources = [ "module_config_test.cc" ]
487    deps = [ "$dir_pw_thread_freertos:config" ]
488  }
489
490  pw_cc_blob_library("test_blob") {
491    out_header = "pw_build/test_blob.h"
492    namespace = "test::ns"
493    blobs = [
494      {
495        file_path = "test_blob_0123.bin"
496        symbol_name = "kFirstBlob0123"
497        alignas = 512
498      },
499      {
500        file_path = "test_blob_0123.bin"
501        symbol_name = "kSecondBlob0123"
502      },
503    ]
504    visibility = [ ":*" ]
505  }
506
507  # file_prefix_map_test verifies that the -ffile-prefix-map option is applied
508  # correctly.
509
510  # File paths should be relative to the root of the GN build.
511  _test_header = rebase_path("pw_build_private/file_prefix_map_test.h", "//")
512  _path_test_define = [ "PW_BUILD_EXPECTED_HEADER_PATH=\"$_test_header\"" ]
513
514  pw_test("file_prefix_map_test") {
515    _source_path = rebase_path("file_prefix_map_test.cc", "//")
516
517    sources = [ "file_prefix_map_test.cc" ]
518
519    defines = _path_test_define +
520              [ "PW_BUILD_EXPECTED_SOURCE_PATH=\"$_source_path\"" ]
521
522    deps = [ ":file_prefix_map_generated_file" ]
523  }
524
525  # Generated file paths should be relative to the build directory.
526  copy("generate_file_prefix_map_test_source") {
527    sources = [ "file_prefix_map_test.cc" ]
528    outputs = [ get_label_info(":file_prefix_map_test", "target_gen_dir") +
529                "/file_prefix_map_test_generated.cc" ]
530    visibility = [ ":*" ]
531  }
532
533  pw_source_set("file_prefix_map_generated_file") {
534    public = [ "pw_build_private/file_prefix_map_test.h" ]
535    sources = get_target_outputs(":generate_file_prefix_map_test_source")
536    deps = [ ":generate_file_prefix_map_test_source" ]
537
538    _source_path = rebase_path(sources[0], root_build_dir)
539
540    # The source file is prefixed with out/ since it's generated.
541    defines = _path_test_define +
542              [ "PW_BUILD_EXPECTED_SOURCE_PATH=\"out/$_source_path\"" ]
543    include_dirs = [ "." ]  # Allow accessing file_prefix_map_test.h
544    visibility = [ ":*" ]
545  }
546
547  pw_source_set("empty_main") {
548    sources = [ "empty_main.cc" ]
549    visibility = [ ":*" ]
550  }
551
552  pw_test_group("tests") {
553    tests = [
554      ":cc_blob_library_test",
555      ":file_prefix_map_test",
556      ":linker_symbol_test",
557    ]
558  }
559}
560