clang_cc_toolchain_config.bzl 49 KB

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