clang_cc_toolchain_config.bzl 49 KB

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