1import("//llvm/utils/gn/build/buildflags.gni") 2import("//llvm/utils/gn/build/mac_sdk.gni") 3import("//llvm/utils/gn/build/sysroot.gni") 4import("//llvm/utils/gn/build/toolchain/compiler.gni") 5import("//llvm/utils/gn/build/toolchain/target_flags.gni") 6 7declare_args() { 8 # Whether to build everything with test coverage information. 9 # After building with this, run tests and then run 10 # llvm/utils/prepare-code-coverage-artifact.py \ 11 # --compilation-dir=out/gn \ 12 # .../llvm-profdata .../llvm-cov out/gn/profiles/ report/ \ 13 # out/gn/bin/llvm-undname ... 14 # to generate a HTML report for the binaries passed in the last line. 15 llvm_build_instrumented_coverage = false 16 17 # Whether to build everything with instrumentation for PGO 18 # After building with this: 19 # 1. Remove old profile data with `rm *.profraw` 20 # 2. Run the built instrumented binaries. 21 # This will produce *.profraw files in the current working directory. 22 # 3. Run `llvm-profdata merge *.profraw -o llvm.profdata` to merge them. 23 # 4. Then build again, with this set to false, and with 24 # `llvm_pgo_use = "//llvm.profdata"` set to use the created profile. 25 llvm_pgo_instrument = false 26 27 # If non-empty, path to merged profiling data used for optimization 28 # See documentation for llvm_pgo_instrument for how to create profile data. 29 llvm_pgo_use = "" 30 31 # If set, puts relative paths in debug info. 32 # Makes the build output independent of the build directory, but makes 33 # most debuggers harder to use. See "Getting to local determinism" and 34 # "Getting debuggers to work well with locally deterministic builds" in 35 # http://blog.llvm.org/2019/11/deterministic-builds-with-clang-and-lld.html 36 # for more information. 37 use_relative_paths_in_debug_info = false 38 39 # The version of host gcc. Ignored if is_clang is true. 40 gcc_version = 9 41} 42 43assert(!llvm_build_instrumented_coverage || is_clang, 44 "llvm_build_instrumented_coverage requires clang as host compiler") 45assert(!llvm_pgo_instrument || is_clang, 46 "llvm_pgo_instrument requires clang as host compiler") 47assert(llvm_pgo_use == "" || is_clang, 48 "llvm_pgo_use requires clang as host compiler") 49assert(!llvm_pgo_instrument || llvm_pgo_use == "", 50 "set at most one of llvm_pgo_instrument and llvm_pgo_use") 51 52config("compiler_defaults") { 53 defines = [] 54 55 if (!llvm_enable_assertions) { 56 defines += [ "NDEBUG" ] 57 } 58 59 if (llvm_enable_expensive_checks) { 60 defines += [ "EXPENSIVE_CHECKS" ] 61 } 62 63 asmflags = target_flags 64 cflags = target_flags + target_cflags 65 cflags_cc = [] 66 ldflags = target_flags + target_ldflags 67 68 # Mostly for compiler-rt, see compiler-rt/cmake/config-ix.cmake 69 if (current_os == "ios") { 70 asmflags += [ "-miphoneos-version-min=8.0" ] 71 cflags += [ "-miphoneos-version-min=8.0" ] 72 ldflags += [ "-miphoneos-version-min=8.0" ] 73 } 74 if (current_os == "mac") { 75 asmflags += [ "-mmacos-version-min=$mac_deployment_target" ] 76 cflags += [ "-mmacos-version-min=$mac_deployment_target" ] 77 ldflags += [ "-mmacos-version-min=$mac_deployment_target" ] 78 } 79 80 assert(symbol_level == 0 || symbol_level == 1 || symbol_level == 2, 81 "Unexpected symbol_level") 82 if (current_os != "win") { 83 if (symbol_level == 2) { 84 cflags += [ "-g" ] 85 86 # For full debug-info -g builds, --gdb-index makes links ~15% slower, and 87 # gdb symbol reading time 1500% faster (lld links in 4.4 instead of 3.9s, 88 # and gdb loads and runs it in 2s instead of in 30s). It's likely that 89 # people doing symbol_level=2 want to run a debugger (since 90 # symbol_level=2 isn't the default). So this seems like the right 91 # tradeoff. 92 if (current_os != "mac" && use_lld) { 93 cflags += [ "-ggnu-pubnames" ] # PR34820 94 ldflags += [ "-Wl,--gdb-index" ] 95 96 # Use debug fission. In this mode, detailed debug information is 97 # written to a .dwo file next to each .o file instead of into the .o 98 # file directly. The linker then only links the .o files, which contain 99 # a pointer to each .dwo file. The debugger then reads debug info out 100 # of all the .dwo files instead of from the binary. 101 # 102 # (The dwp tool can link all the debug info together into a single 103 # "debug info binary", but that's not done as part of the build.) 104 # 105 # This requires `-Wl,--gdb-index` (above) to work well. 106 # 107 # With lld, this reduces link time: 108 # - in release + symbol_level=2 builds: From 2.3s to 1.3s 109 # - in debug builds: From 5.2s to 4.6s 110 # 111 # Time needed for gdb startup and setting a breakpoint is comparable, 112 # the time from from `r` to hititng a breakpoint on main goes from 4s 113 # to 2s. 114 # 115 # (macOS's linker always keeps debug info out of its output executables 116 # and debuggers there also know to load debug info from the .o files. 117 # macOS also has a debug info linker like dwp, it's called dsymutil. 118 # This happens by default, so there's no need to pass a flag there.) 119 cflags += [ "-gsplit-dwarf" ] 120 ldflags += [ "-gsplit-dwarf" ] # Needed for ThinLTO builds. 121 } 122 } else if (symbol_level == 1) { 123 cflags += [ "-g1" ] 124 # For linetable-only -g1 builds, --gdb-index makes links ~8% slower, but 125 # links are 4x faster than -g builds so it's a fairly small absolute cost. 126 # On the other hand, gdb startup is well below 1s with and without the 127 # index, and people using -g1 likely don't use a debugger. So don't use 128 # the flag here. 129 # Linetables always go in the .o file, even with -gsplit-dwarf, so there's 130 # no point in passing -gsplit-dwarf here. 131 } 132 if (is_optimized) { 133 cflags += [ "-O3" ] 134 } 135 cflags += [ "-fdiagnostics-color" ] 136 if (use_lld) { 137 ldflags += [ "-Wl,--color-diagnostics" ] 138 } 139 cflags_cc += [ 140 "-std=c++17", 141 "-fvisibility-inlines-hidden", 142 ] 143 } else { 144 if (symbol_level != 0) { 145 cflags += [ 146 "/Zi", 147 "/FS", 148 ] 149 if (symbol_level == 1 && is_clang) { 150 cflags += [ "-gline-tables-only" ] 151 } 152 ldflags += [ "/DEBUG" ] 153 154 # Speed up links with ghash on windows. 155 if (use_lld && is_clang) { 156 cflags += [ "-gcodeview-ghash" ] 157 ldflags += [ "/DEBUG:GHASH" ] 158 } 159 } 160 if (is_optimized) { 161 cflags += [ 162 "/O2", 163 "/Gw", 164 "/Zc:inline", 165 ] 166 ldflags += [ 167 "/OPT:REF", 168 "/OPT:ICF", 169 ] 170 } 171 defines += [ 172 "_CRT_SECURE_NO_DEPRECATE", 173 "_CRT_SECURE_NO_WARNINGS", 174 "_CRT_NONSTDC_NO_DEPRECATE", 175 "_CRT_NONSTDC_NO_WARNINGS", 176 "_SCL_SECURE_NO_DEPRECATE", 177 "_SCL_SECURE_NO_WARNINGS", 178 179 "_HAS_EXCEPTIONS=0", 180 "_UNICODE", 181 "UNICODE", 182 ] 183 cflags += [ "/EHs-c-" ] 184 cflags_cc += [ "/std:c++17" ] 185 186 if (!is_clang) { 187 # expand __VA_ARGS__ in "OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__)" 188 cflags += [ "/Zc:preprocessor" ] 189 190 # cl.exe doesn't set __cplusplus correctly by default. 191 # clang-cl gets it right by default, so don't needlessly add the flag there. 192 cflags_cc += [ "/Zc:__cplusplus" ] 193 } 194 195 # The MSVC default value (1 MB) is not enough for parsing recursive C++ 196 # templates in Clang. 197 ldflags += [ "/STACK:10000000" ] 198 } 199 200 # Warning setup. 201 if (current_os == "win" && !is_clang) { 202 cflags += [ 203 # Suppress ''modifier' : used more than once' (__forceinline and inline). 204 "-wd4141", 205 206 # Suppress 'conversion from 'type1' to 'type2', possible loss of data'. 207 "-wd4244", 208 209 # Suppress 'conversion from 'size_t' to 'type', possible loss of data'. 210 "-wd4267", 211 212 # Suppress 'no matching operator delete found'. 213 "-wd4291", 214 215 # Suppress 'noexcept used with no exception handling mode specified'. 216 "-wd4577", 217 218 # Suppress 'destructor was implicitly defined as deleted'. 219 "-wd4624", 220 221 # Suppress 'unsafe mix of type <type> and type <type> in operation'. 222 "-wd4805", 223 ] 224 } else { 225 if (current_os == "win") { 226 cflags += [ "/W4" ] 227 } else { 228 cflags += [ 229 "-Wall", 230 "-Wextra", 231 ] 232 } 233 cflags += [ "-Wno-unused-parameter" ] 234 if (is_clang) { 235 cflags += [ 236 "-Wdelete-non-virtual-dtor", 237 "-Wstring-conversion", 238 ] 239 } else { 240 cflags += [ 241 # GCC's -Wcomment complains about // comments ending with '\' if the 242 # next line is also a // comment. 243 "-Wno-comment", 244 245 # Disable gcc's potentially uninitialized use analysis as it presents 246 # lots of false positives. 247 "-Wno-maybe-uninitialized", 248 ] 249 cflags_cc += [ 250 # The LLVM libraries have no stable C++ API, so -Wnoexcept-type is not 251 # useful. 252 "-Wno-noexcept-type", 253 ] 254 if (gcc_version >= 8) { 255 cflags_cc += [ 256 # Disable -Wclass-memaccess, a C++-only warning from GCC 8 that fires 257 # on LLVM's ADT classes. 258 "-Wno-class-memaccess", 259 ] 260 } 261 if (gcc_version >= 9) { 262 cflags_cc += [ 263 # Disable -Wredundant-move on GCC>=9. GCC wants to remove std::move 264 # in code like "A foo(ConvertibleToA a) { return std::move(a); }", 265 # but this code does not compile (or uses the copy constructor 266 # instead) on clang<=3.8. Clang also has a -Wredundant-move, but it 267 # only fires when the types match exactly, so we can keep it here. 268 "-Wno-redundant-move", 269 ] 270 } 271 } 272 } 273 274 # On Windows, the linker is not invoked through the compiler driver. 275 if (use_lld && current_os != "win") { 276 ldflags += [ "-fuse-ld=lld" ] 277 } 278 279 if (llvm_build_instrumented_coverage) { 280 cflags += [ 281 "-fcoverage-mapping", 282 283 # For build determinism. Using this requires passing --compilation-dir to 284 # llvm/utils/prepare-code-coverage-artifact.py. 285 "-fcoverage-compilation-dir=.", 286 287 # Using an absolute path here is lame, but it's used at test execution 288 # time to generate the profiles, and lit doesn't specify a fixed folder 289 # for test execution -- so this is the only way to get all profiles into 290 # a single folder like llvm/utils/prepare-code-coverage-artifact.py 291 # expects. 292 "-fprofile-instr-generate=" + 293 rebase_path("$root_build_dir/profiles/%4m.profraw"), 294 ] 295 if (current_os != "win") { 296 ldflags += [ "-fprofile-instr-generate" ] 297 } 298 } 299 if (llvm_pgo_instrument) { 300 cflags += [ "-fprofile-generate" ] 301 if (current_os != "win") { 302 ldflags += [ "-fprofile-generate" ] 303 } 304 } 305 if (llvm_pgo_use != "") { 306 cflags += [ 307 "-fprofile-use=" + rebase_path(llvm_pgo_use, root_build_dir), 308 309 # There are always quite a few diags like 310 # warning: foo.cpp: Function control flow change detected 311 # (hash mismatch) [-Wbackend-plugin] 312 # in a PGO build. Since they're not unexpected, silence them. 313 "-Wno-backend-plugin", 314 ] 315 } 316 317 # Deterministic build setup, see 318 # http://blog.llvm.org/2019/11/deterministic-builds-with-clang-and-lld.html 319 if (current_os == "win") { 320 ldflags += [ "/pdbaltpath:%_PDB%" ] 321 } 322 if (is_clang) { 323 cflags += [ 324 "-no-canonical-prefixes", 325 "-Werror=date-time", 326 ] 327 if (current_os == "win") { 328 cflags += [ "-fmsc-version=1926" ] 329 if (use_lld) { 330 cflags += [ "/Brepro" ] 331 ldflags += [ "/Brepro" ] 332 } 333 } 334 if (use_relative_paths_in_debug_info) { 335 cflags += [ "-fdebug-compilation-dir=." ] 336 } 337 } 338 if (sysroot != "") { 339 if (current_os == "win") { 340 assert(is_clang, "sysroot only works with clang-cl as host compiler") 341 cflags += [ "/winsysroot" + rebase_path(sysroot, root_build_dir) ] 342 if (use_lld) { 343 ldflags += [ "/winsysroot:" + rebase_path(sysroot, root_build_dir) ] 344 345 # FIXME: Remove once PR54409 is fixed. 346 if (current_cpu == "x64") { 347 ldflags += [ "/machine:x64" ] 348 } else if (current_cpu == "x86") { 349 ldflags += [ "/machine:x86" ] 350 } 351 } 352 } else if (current_os != "ios" && current_os != "mac" && 353 current_os != "android") { 354 cflags += [ "--sysroot=" + rebase_path(sysroot, root_build_dir) ] 355 } 356 } 357 if ((current_os == "ios" || current_os == "mac") && 358 (clang_base_path != "" || sysroot != "")) { 359 if (current_os == "ios" && current_cpu == "arm64") { 360 sdk_path = ios_sdk_path 361 } else if (current_os == "ios" && current_cpu == "x64") { 362 sdk_path = iossim_sdk_path 363 } else if (current_os == "mac") { 364 sdk_path = mac_sdk_path 365 } 366 cflags += [ 367 "-isysroot", 368 rebase_path(sdk_path, root_build_dir), 369 ] 370 ldflags += [ 371 "-isysroot", 372 rebase_path(sdk_path, root_build_dir), 373 ] 374 } 375 if (sysroot != "" && current_os != "win" && is_clang) { 376 cflags += [ "-Wpoison-system-directories" ] 377 } 378 379 if (use_ubsan) { 380 assert(is_clang && (current_os == "ios" || current_os == "linux" || 381 current_os == "mac"), 382 "ubsan only supported on iOS/Clang, Linux/Clang, or macOS/Clang") 383 cflags += [ 384 "-fsanitize=undefined", 385 "-fno-sanitize=vptr,function", 386 "-fno-sanitize-recover=all", 387 ] 388 ldflags += [ "-fsanitize=undefined" ] 389 } 390 391 if (use_asan) { 392 assert(is_clang && (current_os == "ios" || current_os == "linux" || 393 current_os == "mac"), 394 "asan only supported on iOS/Clang, Linux/Clang, or macOS/Clang") 395 cflags += [ "-fsanitize=address" ] 396 ldflags += [ "-fsanitize=address" ] 397 } 398 399 if (use_tsan) { 400 assert(is_clang && current_os == "linux", 401 "tsan only supported on Linux/Clang") 402 cflags += [ "-fsanitize=thread" ] 403 ldflags += [ "-fsanitize=thread" ] 404 } 405 406 if (use_thinlto) { 407 assert(is_clang, "ThinLTO only supported on Clang") 408 409 lto_opt_level = 2 410 411 cflags += [ "-flto=thin" ] 412 413 if (current_os == "win") { 414 ldflags += [ 415 "/opt:lldlto=" + lto_opt_level, 416 "/opt:lldltojobs=" + max_jobs_per_lto_link, 417 ] 418 } else { 419 ldflags += [ 420 "-flto=thin", 421 "-Wl,--thinlto-jobs=" + max_jobs_per_lto_link, 422 "-Wl,--lto-O" + lto_opt_level, 423 ] 424 } 425 } 426 427 cflags_objcc = cflags_cc 428} 429 430config("no_exceptions") { 431 cflags_cc = [] 432 if (current_os != "win") { 433 cflags_cc += [ "-fno-exceptions" ] 434 } 435 cflags_objcc = cflags_cc 436} 437 438config("no_rtti") { 439 if (current_os == "win") { 440 cflags_cc = [ "/GR-" ] 441 } else { 442 cflags_cc = [ "-fno-rtti" ] 443 } 444 cflags_objcc = cflags_cc 445} 446 447config("zdefs") { 448 # -Wl,-z,defs doesn't work with sanitizers. 449 # https://clang.llvm.org/docs/AddressSanitizer.html 450 if (current_os != "ios" && current_os != "mac" && current_os != "win" && 451 !(use_asan || use_tsan || use_ubsan)) { 452 ldflags = [ "-Wl,-z,defs" ] 453 } 454} 455 456# To make an archive that can be distributed, you need to remove this config and 457# set complete_static_lib. 458config("thin_archive") { 459 if (current_os != "ios" && current_os != "mac" && current_os != "win") { 460 arflags = [ "-T" ] 461 } 462} 463 464config("llvm_code") { 465 include_dirs = [ 466 "//llvm/include", 467 "$root_gen_dir/llvm/include", 468 ] 469 if (current_os != "win") { 470 cflags = [ "-fPIC" ] 471 } 472} 473 474config("lld_code") { 475 include_dirs = [ 476 "//lld/include", 477 "$root_gen_dir/lld/include", 478 ] 479} 480 481config("clang_code") { 482 if (current_os != "win") { 483 cflags = [ "-fno-strict-aliasing" ] 484 } 485 include_dirs = [ 486 "//clang/include", 487 "$root_gen_dir/clang/include", 488 ] 489} 490 491config("bolt_code") { 492 include_dirs = [ 493 "//bolt/include", 494 "$root_gen_dir/bolt/include", 495 ] 496} 497 498config("crt_code") { 499 include_dirs = [ "//compiler-rt/lib" ] 500 cflags = [ 501 "-fno-builtin", 502 "-gline-tables-only", 503 ] 504 if (current_os != "win") { 505 cflags += [ 506 "-fPIC", 507 "-funwind-tables", 508 "-fvisibility=hidden", 509 ] 510 } else { 511 cflags += [ 512 # Disable thread safe initialization for static locals. ASan shouldn't need it. 513 # Thread safe initialization assumes that the CRT has already been initialized, but ASan initializes before the CRT. 514 "/Zc:threadSafeInit-", 515 ] 516 } 517 if (is_clang) { 518 cflags += [ 519 "-Werror=thread-safety", 520 "-Werror=thread-safety-reference", 521 "-Werror=thread-safety-beta", 522 ] 523 } 524} 525 526config("lldb_code") { 527 if (current_os != "win") { 528 cflags = [ "-fno-strict-aliasing" ] 529 } 530 include_dirs = [ 531 "//lldb/include", 532 "$root_gen_dir/lldb/include", 533 ] 534} 535 536config("warn_covered_switch_default") { 537 if (is_clang) { 538 cflags = [ "-Wcovered-switch-default" ] 539 } 540} 541