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