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