clang_cc_toolchain_config.bzl 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275
  1. # Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. # Exceptions. See /LICENSE for license information.
  3. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. """A Starlark cc_toolchain configuration rule"""
  5. load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
  6. load(
  7. "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl",
  8. "action_config",
  9. "feature",
  10. "feature_set",
  11. "flag_group",
  12. "flag_set",
  13. "tool",
  14. "tool_path",
  15. "variable_with_value",
  16. "with_feature_set",
  17. )
  18. load("@rules_cc//cc:defs.bzl", "cc_toolchain")
  19. load("@rules_cc//cc/common:cc_common.bzl", "cc_common")
  20. load(
  21. ":clang_detected_variables.bzl",
  22. "clang_bindir",
  23. "clang_include_dirs_list",
  24. "clang_resource_dir",
  25. "clang_version",
  26. "clang_version_for_cache",
  27. "llvm_bindir",
  28. "sysroot_dir",
  29. )
  30. all_c_compile_actions = [
  31. ACTION_NAMES.c_compile,
  32. ACTION_NAMES.assemble,
  33. ACTION_NAMES.preprocess_assemble,
  34. ]
  35. all_cpp_compile_actions = [
  36. ACTION_NAMES.cpp_compile,
  37. ACTION_NAMES.linkstamp_compile,
  38. ACTION_NAMES.cpp_header_parsing,
  39. ACTION_NAMES.cpp_module_compile,
  40. ACTION_NAMES.cpp_module_codegen,
  41. ]
  42. all_compile_actions = all_c_compile_actions + all_cpp_compile_actions
  43. preprocessor_compile_actions = [
  44. ACTION_NAMES.c_compile,
  45. ACTION_NAMES.cpp_compile,
  46. ACTION_NAMES.linkstamp_compile,
  47. ACTION_NAMES.preprocess_assemble,
  48. ACTION_NAMES.cpp_header_parsing,
  49. ACTION_NAMES.cpp_module_compile,
  50. ]
  51. codegen_compile_actions = [
  52. ACTION_NAMES.c_compile,
  53. ACTION_NAMES.cpp_compile,
  54. ACTION_NAMES.linkstamp_compile,
  55. ACTION_NAMES.assemble,
  56. ACTION_NAMES.preprocess_assemble,
  57. ACTION_NAMES.cpp_module_codegen,
  58. ]
  59. all_link_actions = [
  60. ACTION_NAMES.cpp_link_executable,
  61. ACTION_NAMES.cpp_link_dynamic_library,
  62. ACTION_NAMES.cpp_link_nodeps_dynamic_library,
  63. ]
  64. def _impl(ctx):
  65. tool_paths = [
  66. tool_path(name = "ar", path = llvm_bindir + "/llvm-ar"),
  67. tool_path(name = "ld", path = clang_bindir + "/ld.lld"),
  68. tool_path(name = "cpp", path = clang_bindir + "/clang-cpp"),
  69. tool_path(name = "gcc", path = clang_bindir + "/clang++"),
  70. tool_path(name = "dwp", path = llvm_bindir + "/llvm-dwp"),
  71. tool_path(name = "gcov", path = llvm_bindir + "/llvm-cov"),
  72. tool_path(name = "nm", path = llvm_bindir + "/llvm-nm"),
  73. tool_path(name = "objcopy", path = llvm_bindir + "/llvm-objcopy"),
  74. tool_path(name = "objdump", path = llvm_bindir + "/llvm-objdump"),
  75. tool_path(name = "strip", path = llvm_bindir + "/llvm-strip"),
  76. ]
  77. action_configs = [
  78. action_config(action_name = name, enabled = True, tools = [tool(path = clang_bindir + "/clang")])
  79. for name in all_c_compile_actions
  80. ] + [
  81. action_config(action_name = name, enabled = True, tools = [tool(path = clang_bindir + "/clang++")])
  82. for name in all_cpp_compile_actions
  83. ] + [
  84. action_config(action_name = name, enabled = True, tools = [tool(path = clang_bindir + "/clang++")])
  85. for name in all_link_actions
  86. ] + [
  87. action_config(action_name = name, enabled = True, tools = [tool(path = llvm_bindir + "/llvm-ar")])
  88. for name in [ACTION_NAMES.cpp_link_static_library]
  89. ] + [
  90. action_config(action_name = name, enabled = True, tools = [tool(path = llvm_bindir + "/llvm-strip")])
  91. for name in [ACTION_NAMES.strip]
  92. ]
  93. std_compile_flags = ["-std=c++20"]
  94. # libc++ is only used on non-Windows platforms.
  95. if ctx.attr.target_os != "windows":
  96. std_compile_flags.append("-stdlib=libc++")
  97. # TODO: Regression that warns on anonymous unions; remove depending on fix.
  98. # Sets the flag for unknown clang versions, which are assumed to be at head.
  99. # https://github.com/llvm/llvm-project/issues/70384
  100. if not clang_version or clang_version == 18:
  101. missing_field_init_flags = ["-Wno-missing-field-initializers"]
  102. elif clang_version > 18:
  103. missing_field_init_flags = ["-Wno-missing-designated-field-initializers"]
  104. else:
  105. missing_field_init_flags = []
  106. default_flags_feature = feature(
  107. name = "default_flags",
  108. enabled = True,
  109. flag_sets = [
  110. flag_set(
  111. actions = all_compile_actions + all_link_actions,
  112. flag_groups = ([
  113. flag_group(
  114. flags = [
  115. "-no-canonical-prefixes",
  116. "-fcolor-diagnostics",
  117. ],
  118. ),
  119. ]),
  120. ),
  121. flag_set(
  122. actions = all_compile_actions,
  123. flag_groups = ([
  124. flag_group(
  125. flags = [
  126. "-Werror",
  127. "-Wall",
  128. "-Wextra",
  129. "-Wthread-safety",
  130. "-Wself-assign",
  131. "-Wimplicit-fallthrough",
  132. "-Wctad-maybe-unsupported",
  133. "-Wextra-semi",
  134. "-Wmissing-prototypes",
  135. "-Wzero-as-null-pointer-constant",
  136. "-Wdelete-non-virtual-dtor",
  137. # Don't warn on external code as we can't
  138. # necessarily patch it easily. Note that these have
  139. # to be initial directories in the `#include` line.
  140. "--system-header-prefix=absl/",
  141. "--system-header-prefix=benchmark/",
  142. "--system-header-prefix=boost/",
  143. "--system-header-prefix=clang-tools-extra/",
  144. "--system-header-prefix=clang/",
  145. "--system-header-prefix=gmock/",
  146. "--system-header-prefix=gtest/",
  147. "--system-header-prefix=libfuzzer/",
  148. "--system-header-prefix=llvm/",
  149. "--system-header-prefix=re2/",
  150. "--system-header-prefix=tools/cpp/",
  151. "--system-header-prefix=tree_sitter/",
  152. # Compile actions shouldn't link anything.
  153. "-c",
  154. ] + missing_field_init_flags,
  155. ),
  156. flag_group(
  157. expand_if_available = "output_assembly_file",
  158. flags = ["-S"],
  159. ),
  160. flag_group(
  161. expand_if_available = "output_preprocess_file",
  162. flags = ["-E"],
  163. ),
  164. flag_group(
  165. flags = ["-MD", "-MF", "%{dependency_file}"],
  166. expand_if_available = "dependency_file",
  167. ),
  168. flag_group(
  169. flags = ["-frandom-seed=%{output_file}"],
  170. expand_if_available = "output_file",
  171. ),
  172. ]),
  173. ),
  174. flag_set(
  175. actions = all_cpp_compile_actions + all_link_actions,
  176. flag_groups = ([
  177. flag_group(
  178. flags = std_compile_flags,
  179. ),
  180. ]),
  181. ),
  182. flag_set(
  183. actions = codegen_compile_actions,
  184. flag_groups = ([
  185. flag_group(
  186. flags = [
  187. "-ffunction-sections",
  188. "-fdata-sections",
  189. ],
  190. ),
  191. ]),
  192. ),
  193. flag_set(
  194. actions = codegen_compile_actions,
  195. flag_groups = [
  196. flag_group(flags = ["-fPIC"], expand_if_available = "pic"),
  197. ],
  198. ),
  199. flag_set(
  200. actions = preprocessor_compile_actions,
  201. flag_groups = [
  202. flag_group(
  203. flags = [
  204. # Disable a warning and override builtin macros to
  205. # ensure a hermetic build.
  206. "-Wno-builtin-macro-redefined",
  207. "-D__DATE__=\"redacted\"",
  208. "-D__TIMESTAMP__=\"redacted\"",
  209. "-D__TIME__=\"redacted\"",
  210. # Pass the clang version as a define so that bazel
  211. # caching is more likely to notice version changes.
  212. "-DCLANG_VERSION_FOR_CACHE=\"%s\"" % clang_version_for_cache,
  213. ],
  214. ),
  215. flag_group(
  216. flags = ["-D%{preprocessor_defines}"],
  217. iterate_over = "preprocessor_defines",
  218. ),
  219. flag_group(
  220. flags = ["-include", "%{includes}"],
  221. iterate_over = "includes",
  222. expand_if_available = "includes",
  223. ),
  224. flag_group(
  225. flags = ["-iquote", "%{quote_include_paths}"],
  226. iterate_over = "quote_include_paths",
  227. ),
  228. flag_group(
  229. flags = ["-I%{include_paths}"],
  230. iterate_over = "include_paths",
  231. ),
  232. flag_group(
  233. flags = ["-isystem", "%{system_include_paths}"],
  234. iterate_over = "system_include_paths",
  235. ),
  236. ],
  237. ),
  238. flag_set(
  239. actions = [
  240. ACTION_NAMES.cpp_link_dynamic_library,
  241. ACTION_NAMES.cpp_link_nodeps_dynamic_library,
  242. ],
  243. flag_groups = [flag_group(flags = ["-shared"])],
  244. ),
  245. flag_set(
  246. actions = all_link_actions,
  247. flag_groups = [
  248. flag_group(
  249. flags = ["-Wl,-S"],
  250. expand_if_available = "strip_debug_symbols",
  251. ),
  252. flag_group(
  253. flags = ["-L%{library_search_directories}"],
  254. iterate_over = "library_search_directories",
  255. expand_if_available = "library_search_directories",
  256. ),
  257. flag_group(
  258. iterate_over = "runtime_library_search_directories",
  259. flags = [
  260. "-Wl,-rpath,$ORIGIN/%{runtime_library_search_directories}",
  261. ],
  262. expand_if_available =
  263. "runtime_library_search_directories",
  264. ),
  265. ],
  266. ),
  267. ],
  268. )
  269. # Handle different levels of optimization with individual features so that
  270. # they can be ordered and the defaults can override the minimal settings if
  271. # both are enabled.
  272. minimal_optimization_flags = feature(
  273. name = "minimal_optimization_flags",
  274. flag_sets = [
  275. flag_set(
  276. actions = codegen_compile_actions,
  277. flag_groups = [flag_group(flags = [
  278. "-O1",
  279. ])],
  280. ),
  281. ],
  282. )
  283. default_optimization_flags = feature(
  284. name = "default_optimization_flags",
  285. enabled = True,
  286. requires = [feature_set(["opt"])],
  287. flag_sets = [
  288. flag_set(
  289. actions = all_compile_actions,
  290. flag_groups = [flag_group(flags = [
  291. "-DNDEBUG",
  292. ])],
  293. ),
  294. flag_set(
  295. actions = codegen_compile_actions,
  296. flag_groups = [flag_group(flags = [
  297. "-O3",
  298. ])],
  299. ),
  300. ],
  301. )
  302. x86_64_cpu_flags = feature(
  303. name = "x86_64_cpu_flags",
  304. enabled = True,
  305. flag_sets = [
  306. flag_set(
  307. actions = all_compile_actions,
  308. flag_groups = [flag_group(flags = [
  309. "-march=x86-64-v2",
  310. ])],
  311. ),
  312. ],
  313. )
  314. aarch64_cpu_flags = feature(
  315. name = "aarch64_cpu_flags",
  316. enabled = True,
  317. flag_sets = [
  318. flag_set(
  319. actions = all_compile_actions,
  320. flag_groups = [flag_group(flags = [
  321. "-march=armv8.2-a",
  322. ])],
  323. ),
  324. ],
  325. )
  326. # Handle different levels and forms of debug info emission with individual
  327. # features so that they can be ordered and the defaults can override the
  328. # minimal settings if both are enabled.
  329. minimal_debug_info_flags = feature(
  330. name = "minimal_debug_info_flags",
  331. implies = ["debug_info_compression_flags"],
  332. flag_sets = [
  333. flag_set(
  334. actions = codegen_compile_actions,
  335. flag_groups = [
  336. flag_group(
  337. flags = ["-gmlt"],
  338. ),
  339. ],
  340. ),
  341. ],
  342. )
  343. debug_info_flags = feature(
  344. name = "debug_info_flags",
  345. implies = ["debug_info_compression_flags"],
  346. flag_sets = [
  347. flag_set(
  348. actions = codegen_compile_actions,
  349. flag_groups = ([
  350. flag_group(
  351. flags = ["-g"],
  352. ),
  353. flag_group(
  354. flags = ["-gsplit-dwarf"],
  355. expand_if_available = "per_object_debug_info_file",
  356. ),
  357. ]),
  358. ),
  359. ],
  360. )
  361. debug_info_compression_flags = feature(
  362. name = "debug_info_compression_flags",
  363. flag_sets = [
  364. flag_set(
  365. actions = codegen_compile_actions + all_link_actions,
  366. flag_groups = ([
  367. flag_group(
  368. flags = ["-gz"],
  369. ),
  370. ]),
  371. ),
  372. ],
  373. )
  374. # Define a set of mutually exclusive debugger flags.
  375. debugger_flags = feature(name = "debugger_flags")
  376. lldb_flags = feature(
  377. # Use a convenient name for users to select if needed.
  378. name = "lldb_flags",
  379. # Default enable LLDB-optimized flags whenever debugging.
  380. enabled = True,
  381. requires = [feature_set(features = ["debug_info_flags"])],
  382. provides = ["debugger_flags"],
  383. flag_sets = [
  384. flag_set(
  385. actions = codegen_compile_actions,
  386. flag_groups = ([
  387. flag_group(
  388. flags = [
  389. "-glldb",
  390. "-gpubnames",
  391. "-gsimple-template-names",
  392. ],
  393. ),
  394. ]),
  395. ),
  396. ],
  397. )
  398. gdb_flags = feature(
  399. # Use a convenient name for users to select if needed.
  400. name = "gdb_flags",
  401. requires = [feature_set(features = ["debug_info_flags"])],
  402. provides = ["debugger_flags"],
  403. flag_sets = [
  404. flag_set(
  405. actions = codegen_compile_actions,
  406. flag_groups = ([
  407. flag_group(
  408. flags = ["-ggdb"],
  409. ),
  410. flag_group(
  411. flags = ["-ggnu-pubnames"],
  412. ),
  413. ]),
  414. ),
  415. flag_set(
  416. actions = all_link_actions,
  417. flag_groups = [
  418. flag_group(
  419. flags = ["-Wl,--gdb-index"],
  420. ),
  421. ],
  422. ),
  423. ],
  424. )
  425. # An enabled feature that requires the `dbg` compilation mode. This is used
  426. # to toggle on more general features to use by default, while allowing those
  427. # general features to be explicitly enabled where needed.
  428. enable_in_dbg = feature(
  429. name = "enable_in_dbg",
  430. enabled = True,
  431. requires = [feature_set(["dbg"])],
  432. implies = [
  433. "debug_info_flags",
  434. ],
  435. )
  436. # This feature can be enabled in conjunction with any optimizations to
  437. # ensure accurate call stacks and backtraces for profilers or errors.
  438. preserve_call_stacks = feature(
  439. name = "preserve_call_stacks",
  440. flag_sets = [flag_set(
  441. actions = codegen_compile_actions,
  442. flag_groups = [flag_group(flags = [
  443. # Ensure good backtraces by preserving frame pointers and
  444. # disabling tail call elimination.
  445. "-fno-omit-frame-pointer",
  446. "-mno-omit-leaf-frame-pointer",
  447. "-fno-optimize-sibling-calls",
  448. ])],
  449. )],
  450. )
  451. sysroot_feature = feature(
  452. name = "sysroot",
  453. enabled = True,
  454. flag_sets = [
  455. flag_set(
  456. actions = all_compile_actions + all_link_actions,
  457. flag_groups = [
  458. flag_group(
  459. flags = ["--sysroot=%{sysroot}"],
  460. expand_if_available = "sysroot",
  461. ),
  462. ],
  463. ),
  464. ],
  465. )
  466. use_module_maps = feature(
  467. name = "use_module_maps",
  468. requires = [feature_set(features = ["module_maps"])],
  469. flag_sets = [
  470. flag_set(
  471. actions = [
  472. ACTION_NAMES.c_compile,
  473. ACTION_NAMES.cpp_compile,
  474. ACTION_NAMES.cpp_header_parsing,
  475. ACTION_NAMES.cpp_module_compile,
  476. ],
  477. flag_groups = [
  478. # These flag groups are separate so they do not expand to
  479. # the cross product of the variables.
  480. flag_group(flags = ["-fmodule-name=%{module_name}"]),
  481. flag_group(
  482. flags = ["-fmodule-map-file=%{module_map_file}"],
  483. ),
  484. ],
  485. ),
  486. ],
  487. )
  488. # Tell bazel we support module maps in general, so they will be generated
  489. # for all c/c++ rules.
  490. # Note: not all C++ rules support module maps; thus, do not imply this
  491. # feature from other features - instead, require it.
  492. module_maps = feature(
  493. name = "module_maps",
  494. enabled = True,
  495. implies = [
  496. # "module_map_home_cwd",
  497. # "module_map_without_extern_module",
  498. # "generate_submodules",
  499. ],
  500. )
  501. layering_check = feature(
  502. name = "layering_check",
  503. implies = ["use_module_maps"],
  504. flag_sets = [
  505. flag_set(
  506. actions = [
  507. ACTION_NAMES.c_compile,
  508. ACTION_NAMES.cpp_compile,
  509. ACTION_NAMES.cpp_header_parsing,
  510. ACTION_NAMES.cpp_module_compile,
  511. ],
  512. flag_groups = [
  513. flag_group(flags = [
  514. "-fmodules-strict-decluse",
  515. "-Wprivate-header",
  516. ]),
  517. flag_group(
  518. iterate_over = "dependent_module_map_files",
  519. flags = [
  520. "-fmodule-map-file=%{dependent_module_map_files}",
  521. ],
  522. ),
  523. ],
  524. ),
  525. ],
  526. )
  527. sanitizer_common_flags = feature(
  528. name = "sanitizer_common_flags",
  529. implies = ["minimal_debug_info_flags", "preserve_call_stacks"],
  530. )
  531. # Separated from the feature above so it can only be included on platforms
  532. # where it is supported. There is no negative flag in Clang so we can't just
  533. # override it later.
  534. sanitizer_static_lib_flags = feature(
  535. name = "sanitizer_static_lib_flags",
  536. enabled = True,
  537. requires = [feature_set(["sanitizer_common_flags"])],
  538. flag_sets = [flag_set(
  539. actions = all_link_actions,
  540. flag_groups = [flag_group(flags = [
  541. "-static-libsan",
  542. ])],
  543. )],
  544. )
  545. asan = feature(
  546. name = "asan",
  547. implies = ["sanitizer_common_flags"],
  548. flag_sets = [flag_set(
  549. actions = all_compile_actions + all_link_actions,
  550. flag_groups = [flag_group(flags = [
  551. "-fsanitize=address,undefined,nullability",
  552. "-fsanitize-address-use-after-scope",
  553. # Outlining is almost always the right tradeoff for our
  554. # sanitizer usage where we're more pressured on generated code
  555. # size than runtime performance.
  556. "-fsanitize-address-outline-instrumentation",
  557. # We don't need the recovery behavior of UBSan as we expect
  558. # builds to be clean. Not recovering is a bit cheaper.
  559. "-fno-sanitize-recover=undefined,nullability",
  560. # Don't embed the full path name for files. This limits the size
  561. # and combined with line numbers is unlikely to result in many
  562. # ambiguities.
  563. "-fsanitize-undefined-strip-path-components=-1",
  564. # Needed due to clang AST issues, such as in
  565. # clang/AST/Redeclarable.h line 199.
  566. "-fno-sanitize=vptr",
  567. ])],
  568. )],
  569. )
  570. # A feature that further reduces the generated code size of our the ASan
  571. # feature, but at the cost of lower quality diagnostics. This is enabled
  572. # along with ASan in our fastbuild configuration, but can be disabled
  573. # explicitly to get better error messages.
  574. asan_min_size = feature(
  575. name = "asan_min_size",
  576. requires = [feature_set(["asan"])],
  577. flag_sets = [flag_set(
  578. actions = all_compile_actions + all_link_actions,
  579. flag_groups = [flag_group(flags = [
  580. # Force two UBSan checks that have especially large code size
  581. # cost to use the minimal branch to a trapping instruction model
  582. # instead of the full diagnostic.
  583. "-fsanitize-trap=alignment,null",
  584. ])],
  585. )],
  586. )
  587. # Likely due to being unable to use the static-linked and up-to-date
  588. # sanitizer runtimes, we have to disable a number of sanitizers on macOS.
  589. macos_asan_workarounds = feature(
  590. name = "macos_sanitizer_workarounds",
  591. enabled = True,
  592. requires = [feature_set(["asan"])],
  593. flag_sets = [flag_set(
  594. actions = all_compile_actions + all_link_actions,
  595. flag_groups = [flag_group(flags = [
  596. "-fno-sanitize=function",
  597. ])],
  598. )],
  599. )
  600. # An enabled feature that requires the `fastbuild` compilation. This is used
  601. # to toggle general features on by default, while allowing them to be
  602. # directly enabled and disabled more generally as desired.
  603. enable_in_fastbuild = feature(
  604. name = "enable_in_fastbuild",
  605. enabled = True,
  606. requires = [feature_set(["fastbuild"])],
  607. implies = [
  608. "asan",
  609. "asan_min_size",
  610. "minimal_optimization_flags",
  611. "minimal_debug_info_flags",
  612. ],
  613. )
  614. fuzzer = feature(
  615. name = "fuzzer",
  616. flag_sets = [flag_set(
  617. actions = all_compile_actions + all_link_actions,
  618. flag_groups = [flag_group(flags = [
  619. "-fsanitize=fuzzer-no-link",
  620. ])],
  621. )],
  622. )
  623. if clang_version and clang_version <= 16:
  624. libcpp_debug_flags = ["-D_LIBCPP_ENABLE_ASSERTIONS=1"]
  625. libcpp_release_flags = ["-D_LIBCPP_ENABLE_ASSERTIONS=0"]
  626. elif clang_version and clang_version <= 17:
  627. # Clang 17 deprecates LIBCPP_ENABLE_ASSERTIONS in favor of
  628. # HARDENED_MODE and DEBUG_MODE.
  629. libcpp_debug_flags = ["-D_LIBCPP_ENABLE_HARDENED_MODE=1"]
  630. libcpp_release_flags = ["-D_LIBCPP_ENABLE_HARDENED_MODE=1"]
  631. else:
  632. # Clang 18 changes HARDENED_MODE to use 4 values:
  633. # https://releases.llvm.org/18.1.0/projects/libcxx/docs/Hardening.html#hardening-modes
  634. libcpp_debug_flags = [
  635. "-D_LIBCPP_ENABLE_HARDENED_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE",
  636. ]
  637. libcpp_release_flags = [
  638. "-D_LIBCPP_ENABLE_HARDENED_MODE=_LIBCPP_HARDENING_MODE_FAST",
  639. ]
  640. linux_flags_feature = feature(
  641. name = "linux_flags",
  642. enabled = True,
  643. flag_sets = [
  644. flag_set(
  645. actions = all_link_actions,
  646. flag_groups = ([
  647. flag_group(
  648. flags = [
  649. "-fuse-ld=lld",
  650. "-stdlib=libc++",
  651. "-unwindlib=libunwind",
  652. # Force the C++ standard library and runtime
  653. # libraries to be statically linked. This works even
  654. # with libc++ and libunwind despite the names,
  655. # provided libc++ is built with the CMake option:
  656. # - `-DCMAKE_POSITION_INDEPENDENT_CODE=ON`
  657. "-static-libstdc++",
  658. "-static-libgcc",
  659. # Link with Clang's runtime library. This is always
  660. # linked statically.
  661. "-rtlib=compiler-rt",
  662. # Explicitly add LLVM libs to the search path to
  663. # preempt the detected GCC installation's library
  664. # paths. Those might have a system installed libc++
  665. # and we want to find the one next to our Clang.
  666. "-L" + llvm_bindir + "/../lib",
  667. # Link with pthread.
  668. "-lpthread",
  669. # Force linking the static libc++abi archive here.
  670. # This *should* be linked automatically, but not
  671. # every release of LLVM correctly sets the CMake
  672. # flags to do so.
  673. "-l:libc++abi.a",
  674. ],
  675. ),
  676. ]),
  677. ),
  678. flag_set(
  679. actions = all_compile_actions,
  680. flag_groups = [flag_group(flags = libcpp_debug_flags)],
  681. with_features = [
  682. with_feature_set(not_features = ["opt"]),
  683. ],
  684. ),
  685. flag_set(
  686. actions = all_compile_actions,
  687. flag_groups = [flag_group(flags = libcpp_release_flags)],
  688. with_features = [
  689. with_feature_set(features = ["opt"]),
  690. ],
  691. ),
  692. flag_set(
  693. actions = [
  694. ACTION_NAMES.cpp_link_executable,
  695. ],
  696. flag_groups = [
  697. flag_group(
  698. flags = ["-pie"],
  699. expand_if_available = "force_pic",
  700. ),
  701. ],
  702. ),
  703. ],
  704. )
  705. macos_flags_feature = feature(
  706. name = "macos_flags",
  707. enabled = True,
  708. flag_sets = [
  709. flag_set(
  710. actions = [
  711. ACTION_NAMES.cpp_link_executable,
  712. ],
  713. flag_groups = [
  714. flag_group(
  715. flags = ["-fpie"],
  716. expand_if_available = "force_pic",
  717. ),
  718. ],
  719. ),
  720. ],
  721. )
  722. freebsd_flags_feature = feature(
  723. name = "freebsd_flags",
  724. enabled = True,
  725. flag_sets = [
  726. flag_set(
  727. actions = [
  728. ACTION_NAMES.c_compile,
  729. ACTION_NAMES.cpp_compile,
  730. ACTION_NAMES.cpp_header_parsing,
  731. ACTION_NAMES.cpp_module_compile,
  732. ],
  733. flag_groups = [
  734. flag_group(
  735. flags = [
  736. "-DHAVE_MALLCTL",
  737. ],
  738. ),
  739. ],
  740. ),
  741. flag_set(
  742. actions = [
  743. ACTION_NAMES.cpp_link_executable,
  744. ],
  745. flag_groups = [
  746. flag_group(
  747. flags = ["-fpie"],
  748. expand_if_available = "force_pic",
  749. ),
  750. ],
  751. ),
  752. ],
  753. )
  754. default_link_libraries_feature = feature(
  755. name = "default_link_libraries",
  756. enabled = True,
  757. flag_sets = [
  758. flag_set(
  759. actions = all_link_actions,
  760. flag_groups = [
  761. flag_group(
  762. flags = ["%{linkstamp_paths}"],
  763. iterate_over = "linkstamp_paths",
  764. expand_if_available = "linkstamp_paths",
  765. ),
  766. flag_group(
  767. iterate_over = "libraries_to_link",
  768. flag_groups = [
  769. flag_group(
  770. flags = ["-Wl,--start-lib"],
  771. expand_if_equal = variable_with_value(
  772. name = "libraries_to_link.type",
  773. value = "object_file_group",
  774. ),
  775. ),
  776. flag_group(
  777. flags = ["-Wl,-whole-archive"],
  778. expand_if_true = "libraries_to_link.is_whole_archive",
  779. ),
  780. flag_group(
  781. flags = ["%{libraries_to_link.object_files}"],
  782. iterate_over = "libraries_to_link.object_files",
  783. expand_if_equal = variable_with_value(
  784. name = "libraries_to_link.type",
  785. value = "object_file_group",
  786. ),
  787. ),
  788. flag_group(
  789. flags = ["%{libraries_to_link.name}"],
  790. expand_if_equal = variable_with_value(
  791. name = "libraries_to_link.type",
  792. value = "object_file",
  793. ),
  794. ),
  795. flag_group(
  796. flags = ["%{libraries_to_link.name}"],
  797. expand_if_equal = variable_with_value(
  798. name = "libraries_to_link.type",
  799. value = "interface_library",
  800. ),
  801. ),
  802. flag_group(
  803. flags = ["%{libraries_to_link.name}"],
  804. expand_if_equal = variable_with_value(
  805. name = "libraries_to_link.type",
  806. value = "static_library",
  807. ),
  808. ),
  809. flag_group(
  810. flags = ["-l%{libraries_to_link.name}"],
  811. expand_if_equal = variable_with_value(
  812. name = "libraries_to_link.type",
  813. value = "dynamic_library",
  814. ),
  815. ),
  816. flag_group(
  817. flags = ["-l:%{libraries_to_link.name}"],
  818. expand_if_equal = variable_with_value(
  819. name = "libraries_to_link.type",
  820. value = "versioned_dynamic_library",
  821. ),
  822. ),
  823. flag_group(
  824. flags = ["-Wl,-no-whole-archive"],
  825. expand_if_true = "libraries_to_link.is_whole_archive",
  826. ),
  827. flag_group(
  828. flags = ["-Wl,--end-lib"],
  829. expand_if_equal = variable_with_value(
  830. name = "libraries_to_link.type",
  831. value = "object_file_group",
  832. ),
  833. ),
  834. ],
  835. expand_if_available = "libraries_to_link",
  836. ),
  837. # Note that the params file comes at the end, after the
  838. # libraries to link above.
  839. flag_group(
  840. expand_if_available = "linker_param_file",
  841. flags = ["@%{linker_param_file}"],
  842. ),
  843. ],
  844. ),
  845. ],
  846. )
  847. macos_link_libraries_feature = feature(
  848. name = "macos_link_libraries",
  849. enabled = True,
  850. flag_sets = [
  851. flag_set(
  852. actions = all_link_actions,
  853. flag_groups = [
  854. flag_group(
  855. flags = ["%{linkstamp_paths}"],
  856. iterate_over = "linkstamp_paths",
  857. expand_if_available = "linkstamp_paths",
  858. ),
  859. flag_group(
  860. iterate_over = "libraries_to_link",
  861. flag_groups = [
  862. flag_group(
  863. flags = ["-Wl,--start-lib"],
  864. expand_if_equal = variable_with_value(
  865. name = "libraries_to_link.type",
  866. value = "object_file_group",
  867. ),
  868. ),
  869. flag_group(
  870. iterate_over = "libraries_to_link.object_files",
  871. expand_if_equal = variable_with_value(
  872. name = "libraries_to_link.type",
  873. value = "object_file_group",
  874. ),
  875. flag_groups = [
  876. flag_group(
  877. flags = ["%{libraries_to_link.object_files}"],
  878. expand_if_false = "libraries_to_link.is_whole_archive",
  879. ),
  880. flag_group(
  881. flags = ["-Wl,-force_load,%{libraries_to_link.object_files}"],
  882. expand_if_true = "libraries_to_link.is_whole_archive",
  883. ),
  884. ],
  885. ),
  886. flag_group(
  887. expand_if_equal = variable_with_value(
  888. name = "libraries_to_link.type",
  889. value = "object_file",
  890. ),
  891. flag_groups = [
  892. flag_group(
  893. flags = ["%{libraries_to_link.name}"],
  894. expand_if_false = "libraries_to_link.is_whole_archive",
  895. ),
  896. flag_group(
  897. flags = ["-Wl,-force_load,%{libraries_to_link.name}"],
  898. expand_if_true = "libraries_to_link.is_whole_archive",
  899. ),
  900. ],
  901. ),
  902. flag_group(
  903. expand_if_equal = variable_with_value(
  904. name = "libraries_to_link.type",
  905. value = "interface_library",
  906. ),
  907. flag_groups = [
  908. flag_group(
  909. flags = ["%{libraries_to_link.name}"],
  910. expand_if_false = "libraries_to_link.is_whole_archive",
  911. ),
  912. flag_group(
  913. flags = ["-Wl,-force_load,%{libraries_to_link.name}"],
  914. expand_if_true = "libraries_to_link.is_whole_archive",
  915. ),
  916. ],
  917. ),
  918. flag_group(
  919. expand_if_equal = variable_with_value(
  920. name = "libraries_to_link.type",
  921. value = "static_library",
  922. ),
  923. flag_groups = [
  924. flag_group(
  925. flags = ["%{libraries_to_link.name}"],
  926. expand_if_false = "libraries_to_link.is_whole_archive",
  927. ),
  928. flag_group(
  929. flags = ["-Wl,-force_load,%{libraries_to_link.name}"],
  930. expand_if_true = "libraries_to_link.is_whole_archive",
  931. ),
  932. ],
  933. ),
  934. flag_group(
  935. flags = ["-l%{libraries_to_link.name}"],
  936. expand_if_equal = variable_with_value(
  937. name = "libraries_to_link.type",
  938. value = "dynamic_library",
  939. ),
  940. ),
  941. flag_group(
  942. flags = ["-l:%{libraries_to_link.name}"],
  943. expand_if_equal = variable_with_value(
  944. name = "libraries_to_link.type",
  945. value = "versioned_dynamic_library",
  946. ),
  947. ),
  948. flag_group(
  949. expand_if_true = "libraries_to_link.is_whole_archive",
  950. flag_groups = [
  951. flag_group(
  952. expand_if_false = "macos_flags",
  953. flags = ["-Wl,-no-whole-archive"],
  954. ),
  955. ],
  956. ),
  957. flag_group(
  958. flags = ["-Wl,--end-lib"],
  959. expand_if_equal = variable_with_value(
  960. name = "libraries_to_link.type",
  961. value = "object_file_group",
  962. ),
  963. ),
  964. ],
  965. expand_if_available = "libraries_to_link",
  966. ),
  967. # Note that the params file comes at the end, after the
  968. # libraries to link above.
  969. flag_group(
  970. expand_if_available = "linker_param_file",
  971. flags = ["@%{linker_param_file}"],
  972. ),
  973. ],
  974. ),
  975. ],
  976. )
  977. # Place user provided compile flags after all the features so that these
  978. # flags can override or customize behavior. The only thing user flags
  979. # cannot override is the output file as Bazel depends on that.
  980. #
  981. # Finally, place the source file (if present) and output file last to make
  982. # reading the compile command lines easier for humans.
  983. final_flags_feature = feature(
  984. name = "final_flags",
  985. enabled = True,
  986. flag_sets = [
  987. flag_set(
  988. actions = all_compile_actions,
  989. flag_groups = [
  990. flag_group(
  991. flags = ["%{user_compile_flags}"],
  992. iterate_over = "user_compile_flags",
  993. expand_if_available = "user_compile_flags",
  994. ),
  995. flag_group(
  996. flags = ["%{source_file}"],
  997. expand_if_available = "source_file",
  998. ),
  999. flag_group(
  1000. expand_if_available = "output_file",
  1001. flags = ["-o", "%{output_file}"],
  1002. ),
  1003. ],
  1004. ),
  1005. flag_set(
  1006. actions = all_link_actions,
  1007. flag_groups = [
  1008. flag_group(
  1009. flags = ["%{user_link_flags}"],
  1010. iterate_over = "user_link_flags",
  1011. expand_if_available = "user_link_flags",
  1012. ),
  1013. flag_group(
  1014. flags = ["-o", "%{output_execpath}"],
  1015. expand_if_available = "output_execpath",
  1016. ),
  1017. ],
  1018. ),
  1019. ],
  1020. )
  1021. # Archive actions have an entirely independent set of flags and don't
  1022. # interact with either compiler or link actions.
  1023. default_archiver_flags_feature = feature(
  1024. name = "default_archiver_flags",
  1025. enabled = True,
  1026. flag_sets = [
  1027. flag_set(
  1028. actions = [ACTION_NAMES.cpp_link_static_library],
  1029. flag_groups = [
  1030. flag_group(flags = ["rcsD"]),
  1031. flag_group(
  1032. flags = ["%{output_execpath}"],
  1033. expand_if_available = "output_execpath",
  1034. ),
  1035. flag_group(
  1036. iterate_over = "libraries_to_link",
  1037. flag_groups = [
  1038. flag_group(
  1039. flags = ["%{libraries_to_link.name}"],
  1040. expand_if_equal = variable_with_value(
  1041. name = "libraries_to_link.type",
  1042. value = "object_file",
  1043. ),
  1044. ),
  1045. flag_group(
  1046. flags = ["%{libraries_to_link.object_files}"],
  1047. iterate_over = "libraries_to_link.object_files",
  1048. expand_if_equal = variable_with_value(
  1049. name = "libraries_to_link.type",
  1050. value = "object_file_group",
  1051. ),
  1052. ),
  1053. ],
  1054. expand_if_available = "libraries_to_link",
  1055. ),
  1056. flag_group(
  1057. expand_if_available = "linker_param_file",
  1058. flags = ["@%{linker_param_file}"],
  1059. ),
  1060. ],
  1061. ),
  1062. ],
  1063. )
  1064. # Now that we have built up the constituent feature definitions, compose
  1065. # them, including configuration based on the target platform.
  1066. # First, define features that are simply used to configure others.
  1067. features = [
  1068. feature(name = "dbg"),
  1069. feature(name = "fastbuild"),
  1070. feature(name = "host"),
  1071. feature(name = "no_legacy_features"),
  1072. feature(name = "opt"),
  1073. feature(name = "supports_dynamic_linker", enabled = ctx.attr.target_os == "linux"),
  1074. feature(name = "supports_pic", enabled = True),
  1075. feature(name = "supports_start_end_lib", enabled = ctx.attr.target_os == "linux"),
  1076. # Enable split debug info whenever debug info is requested.
  1077. feature(
  1078. name = "per_object_debug_info",
  1079. enabled = True,
  1080. # This has to be directly conditioned on requesting debug info at
  1081. # all, otherwise Bazel will look for an extra output file and not
  1082. # find one.
  1083. requires = [feature_set(features = ["debug_info_flags"])],
  1084. ),
  1085. ]
  1086. # The order of the features determines the relative order of flags used.
  1087. # Start off adding the baseline features.
  1088. features += [
  1089. default_flags_feature,
  1090. minimal_optimization_flags,
  1091. default_optimization_flags,
  1092. minimal_debug_info_flags,
  1093. debug_info_flags,
  1094. debug_info_compression_flags,
  1095. debugger_flags,
  1096. lldb_flags,
  1097. gdb_flags,
  1098. enable_in_dbg,
  1099. preserve_call_stacks,
  1100. sysroot_feature,
  1101. sanitizer_common_flags,
  1102. asan,
  1103. asan_min_size,
  1104. enable_in_fastbuild,
  1105. fuzzer,
  1106. layering_check,
  1107. module_maps,
  1108. use_module_maps,
  1109. default_archiver_flags_feature,
  1110. ]
  1111. # Next, add the features based on the target platform. Here too the
  1112. # features are order sensitive. We also setup the sysroot here.
  1113. if ctx.attr.target_os == "linux":
  1114. features.append(sanitizer_static_lib_flags)
  1115. features.append(linux_flags_feature)
  1116. sysroot = None
  1117. elif ctx.attr.target_os == "windows":
  1118. # TODO: Need to figure out if we need to add windows specific features
  1119. # I think the .pdb debug files will need to be handled differently,
  1120. # so that might be an example where a feature must be added.
  1121. sysroot = None
  1122. elif ctx.attr.target_os == "macos":
  1123. features.append(macos_asan_workarounds)
  1124. features.append(macos_flags_feature)
  1125. sysroot = sysroot_dir
  1126. elif ctx.attr.target_os == "freebsd":
  1127. features.append(sanitizer_static_lib_flags)
  1128. features.append(freebsd_flags_feature)
  1129. sysroot = sysroot_dir
  1130. else:
  1131. fail("Unsupported target OS!")
  1132. if ctx.attr.target_cpu in ["aarch64", "arm64"]:
  1133. features.append(aarch64_cpu_flags)
  1134. else:
  1135. features.append(x86_64_cpu_flags)
  1136. # Finally append the libraries to link and any final flags.
  1137. if ctx.attr.target_os == "macos":
  1138. features.append(macos_link_libraries_feature)
  1139. else:
  1140. features.append(default_link_libraries_feature)
  1141. features.append(final_flags_feature)
  1142. identifier = "local-{0}-{1}".format(ctx.attr.target_cpu, ctx.attr.target_os)
  1143. return cc_common.create_cc_toolchain_config_info(
  1144. ctx = ctx,
  1145. features = features,
  1146. action_configs = action_configs,
  1147. cxx_builtin_include_directories = clang_include_dirs_list + [
  1148. # Add Clang's resource directory to the end of the builtin include
  1149. # directories to cover the use of sanitizer resource files by the driver.
  1150. clang_resource_dir + "/share",
  1151. ],
  1152. builtin_sysroot = sysroot,
  1153. # This configuration only supports local non-cross builds so derive
  1154. # everything from the target CPU selected.
  1155. toolchain_identifier = identifier,
  1156. host_system_name = identifier,
  1157. target_system_name = identifier,
  1158. target_cpu = ctx.attr.target_cpu,
  1159. # This is used to expose a "flag" that `config_setting` rules can use to
  1160. # determine if the compiler is Clang.
  1161. compiler = "clang",
  1162. # These attributes aren't meaningful at all so just use placeholder
  1163. # values.
  1164. target_libc = "local",
  1165. abi_version = "local",
  1166. abi_libc_version = "local",
  1167. # We do have to pass in our tool paths.
  1168. tool_paths = tool_paths,
  1169. )
  1170. cc_toolchain_config = rule(
  1171. implementation = _impl,
  1172. attrs = {
  1173. "target_cpu": attr.string(mandatory = True),
  1174. "target_os": attr.string(mandatory = True),
  1175. },
  1176. provides = [CcToolchainConfigInfo],
  1177. )
  1178. def cc_local_toolchain_suite(name, configs):
  1179. """Create a toolchain suite that uses the local Clang/LLVM install.
  1180. Args:
  1181. name: The name of the toolchain suite to produce.
  1182. configs: An array of (os, cpu) pairs to support in the toolchain.
  1183. """
  1184. # An empty filegroup to use when stubbing out the toolchains.
  1185. native.filegroup(
  1186. name = name + "_empty",
  1187. srcs = [],
  1188. )
  1189. # Create the individual local toolchains for each CPU.
  1190. for (os, cpu) in configs:
  1191. config_name = "{0}_{1}_{2}".format(name, os, cpu)
  1192. cc_toolchain_config(
  1193. name = config_name + "_config",
  1194. target_os = os,
  1195. target_cpu = cpu,
  1196. )
  1197. cc_toolchain(
  1198. name = config_name + "_tools",
  1199. all_files = ":" + name + "_empty",
  1200. ar_files = ":" + name + "_empty",
  1201. as_files = ":" + name + "_empty",
  1202. compiler_files = ":" + name + "_empty",
  1203. dwp_files = ":" + name + "_empty",
  1204. linker_files = ":" + name + "_empty",
  1205. objcopy_files = ":" + name + "_empty",
  1206. strip_files = ":" + name + "_empty",
  1207. supports_param_files = 1,
  1208. toolchain_config = ":" + config_name + "_config",
  1209. toolchain_identifier = config_name,
  1210. )
  1211. compatible_with = ["@platforms//cpu:" + cpu, "@platforms//os:" + os]
  1212. native.toolchain(
  1213. name = config_name,
  1214. exec_compatible_with = compatible_with,
  1215. target_compatible_with = compatible_with,
  1216. toolchain = config_name + "_tools",
  1217. toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
  1218. )