xref: /llvm-project/llvm/utils/gn/build/BUILD.gn (revision 18952bdcd6f987620e6396261c2bb444e428e07e)
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