clang_cc_toolchain_config.bzl 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148
  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,--gdb-index"],
  250. expand_if_available = "is_using_fission",
  251. ),
  252. flag_group(
  253. flags = ["-Wl,-S"],
  254. expand_if_available = "strip_debug_symbols",
  255. ),
  256. flag_group(
  257. flags = ["-L%{library_search_directories}"],
  258. iterate_over = "library_search_directories",
  259. expand_if_available = "library_search_directories",
  260. ),
  261. flag_group(
  262. iterate_over = "runtime_library_search_directories",
  263. flags = [
  264. "-Wl,-rpath,$ORIGIN/%{runtime_library_search_directories}",
  265. ],
  266. expand_if_available =
  267. "runtime_library_search_directories",
  268. ),
  269. ],
  270. ),
  271. ],
  272. )
  273. # Handle different levels of optimization with individual features so that
  274. # they can be ordered and the defaults can override the minimal settings if
  275. # both are enabled.
  276. minimal_optimization_flags = feature(
  277. name = "minimal_optimization_flags",
  278. flag_sets = [
  279. flag_set(
  280. actions = codegen_compile_actions,
  281. flag_groups = [flag_group(flags = [
  282. "-O1",
  283. ])],
  284. ),
  285. ],
  286. )
  287. default_optimization_flags = feature(
  288. name = "default_optimization_flags",
  289. enabled = True,
  290. requires = [feature_set(["opt"])],
  291. flag_sets = [
  292. flag_set(
  293. actions = all_compile_actions,
  294. flag_groups = [flag_group(flags = [
  295. "-DNDEBUG",
  296. ])],
  297. ),
  298. flag_set(
  299. actions = codegen_compile_actions,
  300. flag_groups = [flag_group(flags = [
  301. "-O3",
  302. ])],
  303. ),
  304. ],
  305. )
  306. x86_64_cpu_flags = feature(
  307. name = "x86_64_cpu_flags",
  308. enabled = True,
  309. flag_sets = [
  310. flag_set(
  311. actions = all_compile_actions,
  312. flag_groups = [flag_group(flags = [
  313. "-march=x86-64-v2",
  314. ])],
  315. ),
  316. ],
  317. )
  318. aarch64_cpu_flags = feature(
  319. name = "aarch64_cpu_flags",
  320. enabled = True,
  321. flag_sets = [
  322. flag_set(
  323. actions = all_compile_actions,
  324. flag_groups = [flag_group(flags = [
  325. "-march=armv8.2-a",
  326. ])],
  327. ),
  328. ],
  329. )
  330. # Handle different levels and forms of debug info emission with individual
  331. # features so that they can be ordered and the defaults can override the
  332. # minimal settings if both are enabled.
  333. minimal_debug_info_flags = feature(
  334. name = "minimal_debug_info_flags",
  335. flag_sets = [
  336. flag_set(
  337. actions = codegen_compile_actions,
  338. flag_groups = [
  339. flag_group(
  340. flags = ["-gmlt"],
  341. ),
  342. ],
  343. ),
  344. ],
  345. )
  346. default_debug_info_flags = feature(
  347. name = "default_debug_info_flags",
  348. enabled = True,
  349. flag_sets = [
  350. flag_set(
  351. actions = codegen_compile_actions,
  352. flag_groups = ([
  353. flag_group(
  354. flags = ["-g"],
  355. ),
  356. ]),
  357. with_features = [with_feature_set(features = ["dbg"])],
  358. ),
  359. flag_set(
  360. actions = codegen_compile_actions,
  361. flag_groups = [
  362. flag_group(
  363. flags = ["-gsplit-dwarf", "-g"],
  364. expand_if_available = "per_object_debug_info_file",
  365. ),
  366. ],
  367. ),
  368. ],
  369. )
  370. # This feature can be enabled in conjunction with any optimizations to
  371. # ensure accurate call stacks and backtraces for profilers or errors.
  372. preserve_call_stacks = feature(
  373. name = "preserve_call_stacks",
  374. flag_sets = [flag_set(
  375. actions = codegen_compile_actions,
  376. flag_groups = [flag_group(flags = [
  377. # Ensure good backtraces by preserving frame pointers and
  378. # disabling tail call elimination.
  379. "-fno-omit-frame-pointer",
  380. "-mno-omit-leaf-frame-pointer",
  381. "-fno-optimize-sibling-calls",
  382. ])],
  383. )],
  384. )
  385. sysroot_feature = feature(
  386. name = "sysroot",
  387. enabled = True,
  388. flag_sets = [
  389. flag_set(
  390. actions = all_compile_actions + all_link_actions,
  391. flag_groups = [
  392. flag_group(
  393. flags = ["--sysroot=%{sysroot}"],
  394. expand_if_available = "sysroot",
  395. ),
  396. ],
  397. ),
  398. ],
  399. )
  400. use_module_maps = feature(
  401. name = "use_module_maps",
  402. requires = [feature_set(features = ["module_maps"])],
  403. flag_sets = [
  404. flag_set(
  405. actions = [
  406. ACTION_NAMES.c_compile,
  407. ACTION_NAMES.cpp_compile,
  408. ACTION_NAMES.cpp_header_parsing,
  409. ACTION_NAMES.cpp_module_compile,
  410. ],
  411. flag_groups = [
  412. # These flag groups are separate so they do not expand to
  413. # the cross product of the variables.
  414. flag_group(flags = ["-fmodule-name=%{module_name}"]),
  415. flag_group(
  416. flags = ["-fmodule-map-file=%{module_map_file}"],
  417. ),
  418. ],
  419. ),
  420. ],
  421. )
  422. # Tell bazel we support module maps in general, so they will be generated
  423. # for all c/c++ rules.
  424. # Note: not all C++ rules support module maps; thus, do not imply this
  425. # feature from other features - instead, require it.
  426. module_maps = feature(
  427. name = "module_maps",
  428. enabled = True,
  429. implies = [
  430. # "module_map_home_cwd",
  431. # "module_map_without_extern_module",
  432. # "generate_submodules",
  433. ],
  434. )
  435. layering_check = feature(
  436. name = "layering_check",
  437. implies = ["use_module_maps"],
  438. flag_sets = [
  439. flag_set(
  440. actions = [
  441. ACTION_NAMES.c_compile,
  442. ACTION_NAMES.cpp_compile,
  443. ACTION_NAMES.cpp_header_parsing,
  444. ACTION_NAMES.cpp_module_compile,
  445. ],
  446. flag_groups = [
  447. flag_group(flags = [
  448. "-fmodules-strict-decluse",
  449. "-Wprivate-header",
  450. ]),
  451. flag_group(
  452. iterate_over = "dependent_module_map_files",
  453. flags = [
  454. "-fmodule-map-file=%{dependent_module_map_files}",
  455. ],
  456. ),
  457. ],
  458. ),
  459. ],
  460. )
  461. sanitizer_common_flags = feature(
  462. name = "sanitizer_common_flags",
  463. requires = [feature_set(["nonhost"])],
  464. implies = ["minimal_optimization_flags", "minimal_debug_info_flags", "preserve_call_stacks"],
  465. )
  466. # Separated from the feature above so it can only be included on platforms
  467. # where it is supported. There is no negative flag in Clang so we can't just
  468. # override it later.
  469. sanitizer_static_lib_flags = feature(
  470. name = "sanitizer_static_lib_flags",
  471. enabled = True,
  472. requires = [feature_set(["sanitizer_common_flags"])],
  473. flag_sets = [flag_set(
  474. actions = all_link_actions,
  475. flag_groups = [flag_group(flags = [
  476. "-static-libsan",
  477. ])],
  478. )],
  479. )
  480. asan = feature(
  481. name = "asan",
  482. requires = [feature_set(["nonhost"])],
  483. implies = ["sanitizer_common_flags"],
  484. flag_sets = [flag_set(
  485. actions = all_compile_actions + all_link_actions,
  486. flag_groups = [flag_group(flags = [
  487. "-fsanitize=address,undefined,nullability",
  488. "-fsanitize-address-use-after-scope",
  489. # We don't need the recovery behavior of UBSan as we expect
  490. # builds to be clean. Not recovering is a bit cheaper.
  491. "-fno-sanitize-recover=undefined",
  492. # Don't embed the full path name for files. This limits the size
  493. # and combined with line numbers is unlikely to result in many
  494. # ambiguities.
  495. "-fsanitize-undefined-strip-path-components=-1",
  496. # Needed due to clang AST issues, such as in
  497. # clang/AST/Redeclarable.h line 199.
  498. "-fno-sanitize=vptr",
  499. ])],
  500. )],
  501. )
  502. # Likely due to being unable to use the static-linked and up-to-date
  503. # sanitizer runtimes, we have to disable a number of sanitizers on macOS.
  504. macos_asan_workarounds = feature(
  505. name = "macos_sanitizer_workarounds",
  506. enabled = True,
  507. requires = [feature_set(["asan"])],
  508. flag_sets = [flag_set(
  509. actions = all_compile_actions + all_link_actions,
  510. flag_groups = [flag_group(flags = [
  511. "-fno-sanitize=function",
  512. ])],
  513. )],
  514. )
  515. enable_asan_in_fastbuild = feature(
  516. name = "enable_asan_in_fastbuild",
  517. enabled = True,
  518. requires = [feature_set(["nonhost", "fastbuild"])],
  519. implies = ["asan"],
  520. )
  521. fuzzer = feature(
  522. name = "fuzzer",
  523. requires = [feature_set(["nonhost"])],
  524. implies = ["asan"],
  525. flag_sets = [flag_set(
  526. actions = all_compile_actions + all_link_actions,
  527. flag_groups = [flag_group(flags = [
  528. "-fsanitize=fuzzer-no-link",
  529. ])],
  530. )],
  531. )
  532. if clang_version and clang_version <= 16:
  533. libcpp_debug_flags = ["-D_LIBCPP_ENABLE_ASSERTIONS=1"]
  534. else:
  535. # Clang 17 deprecates LIBCPP_ENABLE_ASSERTIONS in favor of
  536. # HARDENED_MODE.
  537. libcpp_debug_flags = ["-D_LIBCPP_ENABLE_HARDENED_MODE=1"]
  538. linux_flags_feature = feature(
  539. name = "linux_flags",
  540. enabled = True,
  541. flag_sets = [
  542. flag_set(
  543. actions = all_link_actions,
  544. flag_groups = ([
  545. flag_group(
  546. flags = [
  547. "-fuse-ld=lld",
  548. "-stdlib=libc++",
  549. "-unwindlib=libunwind",
  550. # Force the C++ standard library and runtime
  551. # libraries to be statically linked. This works even
  552. # with libc++ and libunwind despite the names,
  553. # provided libc++ is built with the CMake option:
  554. # - `-DCMAKE_POSITION_INDEPENDENT_CODE=ON`
  555. "-static-libstdc++",
  556. "-static-libgcc",
  557. # Link with Clang's runtime library. This is always
  558. # linked statically.
  559. "-rtlib=compiler-rt",
  560. # Explicitly add LLVM libs to the search path to
  561. # preempt the detected GCC installation's library
  562. # paths. Those might have a system installed libc++
  563. # and we want to find the one next to our Clang.
  564. "-L" + llvm_bindir + "/../lib",
  565. # Link with pthread.
  566. "-lpthread",
  567. # Force linking the static libc++abi archive here.
  568. # This *should* be linked automatically, but not
  569. # every release of LLVM correctly sets the CMake
  570. # flags to do so.
  571. "-l:libc++abi.a",
  572. ],
  573. ),
  574. ]),
  575. ),
  576. flag_set(
  577. actions = all_compile_actions,
  578. flag_groups = [flag_group(flags = libcpp_debug_flags)],
  579. with_features = [
  580. with_feature_set(not_features = ["opt"]),
  581. ],
  582. ),
  583. flag_set(
  584. actions = [
  585. ACTION_NAMES.cpp_link_executable,
  586. ],
  587. flag_groups = [
  588. flag_group(
  589. flags = ["-pie"],
  590. expand_if_available = "force_pic",
  591. ),
  592. ],
  593. ),
  594. ],
  595. )
  596. macos_flags_feature = feature(
  597. name = "macos_flags",
  598. enabled = True,
  599. flag_sets = [
  600. flag_set(
  601. actions = [
  602. ACTION_NAMES.cpp_link_executable,
  603. ],
  604. flag_groups = [
  605. flag_group(
  606. flags = ["-fpie"],
  607. expand_if_available = "force_pic",
  608. ),
  609. ],
  610. ),
  611. ],
  612. )
  613. freebsd_flags_feature = feature(
  614. name = "freebsd_flags",
  615. enabled = True,
  616. flag_sets = [
  617. flag_set(
  618. actions = [
  619. ACTION_NAMES.c_compile,
  620. ACTION_NAMES.cpp_compile,
  621. ACTION_NAMES.cpp_header_parsing,
  622. ACTION_NAMES.cpp_module_compile,
  623. ],
  624. flag_groups = [
  625. flag_group(
  626. flags = [
  627. "-DHAVE_MALLCTL",
  628. ],
  629. ),
  630. ],
  631. ),
  632. flag_set(
  633. actions = [
  634. ACTION_NAMES.cpp_link_executable,
  635. ],
  636. flag_groups = [
  637. flag_group(
  638. flags = ["-fpie"],
  639. expand_if_available = "force_pic",
  640. ),
  641. ],
  642. ),
  643. ],
  644. )
  645. default_link_libraries_feature = feature(
  646. name = "default_link_libraries",
  647. enabled = True,
  648. flag_sets = [
  649. flag_set(
  650. actions = all_link_actions,
  651. flag_groups = [
  652. flag_group(
  653. flags = ["%{linkstamp_paths}"],
  654. iterate_over = "linkstamp_paths",
  655. expand_if_available = "linkstamp_paths",
  656. ),
  657. flag_group(
  658. iterate_over = "libraries_to_link",
  659. flag_groups = [
  660. flag_group(
  661. flags = ["-Wl,--start-lib"],
  662. expand_if_equal = variable_with_value(
  663. name = "libraries_to_link.type",
  664. value = "object_file_group",
  665. ),
  666. ),
  667. flag_group(
  668. flags = ["-Wl,-whole-archive"],
  669. expand_if_true = "libraries_to_link.is_whole_archive",
  670. ),
  671. flag_group(
  672. flags = ["%{libraries_to_link.object_files}"],
  673. iterate_over = "libraries_to_link.object_files",
  674. expand_if_equal = variable_with_value(
  675. name = "libraries_to_link.type",
  676. value = "object_file_group",
  677. ),
  678. ),
  679. flag_group(
  680. flags = ["%{libraries_to_link.name}"],
  681. expand_if_equal = variable_with_value(
  682. name = "libraries_to_link.type",
  683. value = "object_file",
  684. ),
  685. ),
  686. flag_group(
  687. flags = ["%{libraries_to_link.name}"],
  688. expand_if_equal = variable_with_value(
  689. name = "libraries_to_link.type",
  690. value = "interface_library",
  691. ),
  692. ),
  693. flag_group(
  694. flags = ["%{libraries_to_link.name}"],
  695. expand_if_equal = variable_with_value(
  696. name = "libraries_to_link.type",
  697. value = "static_library",
  698. ),
  699. ),
  700. flag_group(
  701. flags = ["-l%{libraries_to_link.name}"],
  702. expand_if_equal = variable_with_value(
  703. name = "libraries_to_link.type",
  704. value = "dynamic_library",
  705. ),
  706. ),
  707. flag_group(
  708. flags = ["-l:%{libraries_to_link.name}"],
  709. expand_if_equal = variable_with_value(
  710. name = "libraries_to_link.type",
  711. value = "versioned_dynamic_library",
  712. ),
  713. ),
  714. flag_group(
  715. flags = ["-Wl,-no-whole-archive"],
  716. expand_if_true = "libraries_to_link.is_whole_archive",
  717. ),
  718. flag_group(
  719. flags = ["-Wl,--end-lib"],
  720. expand_if_equal = variable_with_value(
  721. name = "libraries_to_link.type",
  722. value = "object_file_group",
  723. ),
  724. ),
  725. ],
  726. expand_if_available = "libraries_to_link",
  727. ),
  728. # Note that the params file comes at the end, after the
  729. # libraries to link above.
  730. flag_group(
  731. expand_if_available = "linker_param_file",
  732. flags = ["@%{linker_param_file}"],
  733. ),
  734. ],
  735. ),
  736. ],
  737. )
  738. macos_link_libraries_feature = feature(
  739. name = "macos_link_libraries",
  740. enabled = True,
  741. flag_sets = [
  742. flag_set(
  743. actions = all_link_actions,
  744. flag_groups = [
  745. flag_group(
  746. flags = ["%{linkstamp_paths}"],
  747. iterate_over = "linkstamp_paths",
  748. expand_if_available = "linkstamp_paths",
  749. ),
  750. flag_group(
  751. iterate_over = "libraries_to_link",
  752. flag_groups = [
  753. flag_group(
  754. flags = ["-Wl,--start-lib"],
  755. expand_if_equal = variable_with_value(
  756. name = "libraries_to_link.type",
  757. value = "object_file_group",
  758. ),
  759. ),
  760. flag_group(
  761. iterate_over = "libraries_to_link.object_files",
  762. expand_if_equal = variable_with_value(
  763. name = "libraries_to_link.type",
  764. value = "object_file_group",
  765. ),
  766. flag_groups = [
  767. flag_group(
  768. flags = ["%{libraries_to_link.object_files}"],
  769. expand_if_false = "libraries_to_link.is_whole_archive",
  770. ),
  771. flag_group(
  772. flags = ["-Wl,-force_load,%{libraries_to_link.object_files}"],
  773. expand_if_true = "libraries_to_link.is_whole_archive",
  774. ),
  775. ],
  776. ),
  777. flag_group(
  778. expand_if_equal = variable_with_value(
  779. name = "libraries_to_link.type",
  780. value = "object_file",
  781. ),
  782. flag_groups = [
  783. flag_group(
  784. flags = ["%{libraries_to_link.name}"],
  785. expand_if_false = "libraries_to_link.is_whole_archive",
  786. ),
  787. flag_group(
  788. flags = ["-Wl,-force_load,%{libraries_to_link.name}"],
  789. expand_if_true = "libraries_to_link.is_whole_archive",
  790. ),
  791. ],
  792. ),
  793. flag_group(
  794. expand_if_equal = variable_with_value(
  795. name = "libraries_to_link.type",
  796. value = "interface_library",
  797. ),
  798. flag_groups = [
  799. flag_group(
  800. flags = ["%{libraries_to_link.name}"],
  801. expand_if_false = "libraries_to_link.is_whole_archive",
  802. ),
  803. flag_group(
  804. flags = ["-Wl,-force_load,%{libraries_to_link.name}"],
  805. expand_if_true = "libraries_to_link.is_whole_archive",
  806. ),
  807. ],
  808. ),
  809. flag_group(
  810. expand_if_equal = variable_with_value(
  811. name = "libraries_to_link.type",
  812. value = "static_library",
  813. ),
  814. flag_groups = [
  815. flag_group(
  816. flags = ["%{libraries_to_link.name}"],
  817. expand_if_false = "libraries_to_link.is_whole_archive",
  818. ),
  819. flag_group(
  820. flags = ["-Wl,-force_load,%{libraries_to_link.name}"],
  821. expand_if_true = "libraries_to_link.is_whole_archive",
  822. ),
  823. ],
  824. ),
  825. flag_group(
  826. flags = ["-l%{libraries_to_link.name}"],
  827. expand_if_equal = variable_with_value(
  828. name = "libraries_to_link.type",
  829. value = "dynamic_library",
  830. ),
  831. ),
  832. flag_group(
  833. flags = ["-l:%{libraries_to_link.name}"],
  834. expand_if_equal = variable_with_value(
  835. name = "libraries_to_link.type",
  836. value = "versioned_dynamic_library",
  837. ),
  838. ),
  839. flag_group(
  840. expand_if_true = "libraries_to_link.is_whole_archive",
  841. flag_groups = [
  842. flag_group(
  843. expand_if_false = "macos_flags",
  844. flags = ["-Wl,-no-whole-archive"],
  845. ),
  846. ],
  847. ),
  848. flag_group(
  849. flags = ["-Wl,--end-lib"],
  850. expand_if_equal = variable_with_value(
  851. name = "libraries_to_link.type",
  852. value = "object_file_group",
  853. ),
  854. ),
  855. ],
  856. expand_if_available = "libraries_to_link",
  857. ),
  858. # Note that the params file comes at the end, after the
  859. # libraries to link above.
  860. flag_group(
  861. expand_if_available = "linker_param_file",
  862. flags = ["@%{linker_param_file}"],
  863. ),
  864. ],
  865. ),
  866. ],
  867. )
  868. # Place user provided compile flags after all the features so that these
  869. # flags can override or customize behavior. The only thing user flags
  870. # cannot override is the output file as Bazel depends on that.
  871. #
  872. # Finally, place the source file (if present) and output file last to make
  873. # reading the compile command lines easier for humans.
  874. final_flags_feature = feature(
  875. name = "final_flags",
  876. enabled = True,
  877. flag_sets = [
  878. flag_set(
  879. actions = all_compile_actions,
  880. flag_groups = [
  881. flag_group(
  882. flags = ["%{user_compile_flags}"],
  883. iterate_over = "user_compile_flags",
  884. expand_if_available = "user_compile_flags",
  885. ),
  886. flag_group(
  887. flags = ["%{source_file}"],
  888. expand_if_available = "source_file",
  889. ),
  890. flag_group(
  891. expand_if_available = "output_file",
  892. flags = ["-o", "%{output_file}"],
  893. ),
  894. ],
  895. ),
  896. flag_set(
  897. actions = all_link_actions,
  898. flag_groups = [
  899. flag_group(
  900. flags = ["%{user_link_flags}"],
  901. iterate_over = "user_link_flags",
  902. expand_if_available = "user_link_flags",
  903. ),
  904. flag_group(
  905. flags = ["-o", "%{output_execpath}"],
  906. expand_if_available = "output_execpath",
  907. ),
  908. ],
  909. ),
  910. ],
  911. )
  912. # Archive actions have an entirely independent set of flags and don't
  913. # interact with either compiler or link actions.
  914. default_archiver_flags_feature = feature(
  915. name = "default_archiver_flags",
  916. enabled = True,
  917. flag_sets = [
  918. flag_set(
  919. actions = [ACTION_NAMES.cpp_link_static_library],
  920. flag_groups = [
  921. flag_group(flags = ["rcsD"]),
  922. flag_group(
  923. flags = ["%{output_execpath}"],
  924. expand_if_available = "output_execpath",
  925. ),
  926. flag_group(
  927. iterate_over = "libraries_to_link",
  928. flag_groups = [
  929. flag_group(
  930. flags = ["%{libraries_to_link.name}"],
  931. expand_if_equal = variable_with_value(
  932. name = "libraries_to_link.type",
  933. value = "object_file",
  934. ),
  935. ),
  936. flag_group(
  937. flags = ["%{libraries_to_link.object_files}"],
  938. iterate_over = "libraries_to_link.object_files",
  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. flag_group(
  948. expand_if_available = "linker_param_file",
  949. flags = ["@%{linker_param_file}"],
  950. ),
  951. ],
  952. ),
  953. ],
  954. )
  955. # Now that we have built up the constituent feature definitions, compose
  956. # them, including configuration based on the target platform.
  957. # First, define features that are simply used to configure others.
  958. features = [
  959. feature(name = "dbg"),
  960. feature(name = "fastbuild"),
  961. feature(name = "host"),
  962. feature(name = "no_legacy_features"),
  963. feature(name = "nonhost"),
  964. feature(name = "opt"),
  965. feature(name = "supports_dynamic_linker", enabled = ctx.attr.target_os == "linux"),
  966. feature(name = "supports_pic", enabled = True),
  967. feature(name = "supports_start_end_lib", enabled = ctx.attr.target_os == "linux"),
  968. ]
  969. # The order of the features determines the relative order of flags used.
  970. # Start off adding the baseline features.
  971. features += [
  972. default_flags_feature,
  973. minimal_optimization_flags,
  974. default_optimization_flags,
  975. minimal_debug_info_flags,
  976. default_debug_info_flags,
  977. preserve_call_stacks,
  978. sysroot_feature,
  979. sanitizer_common_flags,
  980. asan,
  981. enable_asan_in_fastbuild,
  982. fuzzer,
  983. layering_check,
  984. module_maps,
  985. use_module_maps,
  986. default_archiver_flags_feature,
  987. ]
  988. # Next, add the features based on the target platform. Here too the
  989. # features are order sensitive. We also setup the sysroot here.
  990. if ctx.attr.target_os == "linux":
  991. features.append(sanitizer_static_lib_flags)
  992. features.append(linux_flags_feature)
  993. sysroot = None
  994. elif ctx.attr.target_os == "windows":
  995. # TODO: Need to figure out if we need to add windows specific features
  996. # I think the .pdb debug files will need to be handled differently,
  997. # so that might be an example where a feature must be added.
  998. sysroot = None
  999. elif ctx.attr.target_os == "macos":
  1000. features.append(macos_asan_workarounds)
  1001. features.append(macos_flags_feature)
  1002. sysroot = sysroot_dir
  1003. elif ctx.attr.target_os == "freebsd":
  1004. features.append(sanitizer_static_lib_flags)
  1005. features.append(freebsd_flags_feature)
  1006. sysroot = sysroot_dir
  1007. else:
  1008. fail("Unsupported target OS!")
  1009. if ctx.attr.target_cpu in ["aarch64", "arm64"]:
  1010. features.append(aarch64_cpu_flags)
  1011. else:
  1012. features.append(x86_64_cpu_flags)
  1013. # Finally append the libraries to link and any final flags.
  1014. if ctx.attr.target_os == "macos":
  1015. features.append(macos_link_libraries_feature)
  1016. else:
  1017. features.append(default_link_libraries_feature)
  1018. features.append(final_flags_feature)
  1019. identifier = "local-{0}-{1}".format(ctx.attr.target_cpu, ctx.attr.target_os)
  1020. return cc_common.create_cc_toolchain_config_info(
  1021. ctx = ctx,
  1022. features = features,
  1023. action_configs = action_configs,
  1024. cxx_builtin_include_directories = clang_include_dirs_list + [
  1025. # Add Clang's resource directory to the end of the builtin include
  1026. # directories to cover the use of sanitizer resource files by the driver.
  1027. clang_resource_dir + "/share",
  1028. ],
  1029. builtin_sysroot = sysroot,
  1030. # This configuration only supports local non-cross builds so derive
  1031. # everything from the target CPU selected.
  1032. toolchain_identifier = identifier,
  1033. host_system_name = identifier,
  1034. target_system_name = identifier,
  1035. target_cpu = ctx.attr.target_cpu,
  1036. # This is used to expose a "flag" that `config_setting` rules can use to
  1037. # determine if the compiler is Clang.
  1038. compiler = "clang",
  1039. # These attributes aren't meaningful at all so just use placeholder
  1040. # values.
  1041. target_libc = "local",
  1042. abi_version = "local",
  1043. abi_libc_version = "local",
  1044. # We do have to pass in our tool paths.
  1045. tool_paths = tool_paths,
  1046. )
  1047. cc_toolchain_config = rule(
  1048. implementation = _impl,
  1049. attrs = {
  1050. "target_cpu": attr.string(mandatory = True),
  1051. "target_os": attr.string(mandatory = True),
  1052. },
  1053. provides = [CcToolchainConfigInfo],
  1054. )
  1055. def cc_local_toolchain_suite(name, configs):
  1056. """Create a toolchain suite that uses the local Clang/LLVM install.
  1057. Args:
  1058. name: The name of the toolchain suite to produce.
  1059. configs: An array of (os, cpu) pairs to support in the toolchain.
  1060. """
  1061. # An empty filegroup to use when stubbing out the toolchains.
  1062. native.filegroup(
  1063. name = name + "_empty",
  1064. srcs = [],
  1065. )
  1066. # Create the individual local toolchains for each CPU.
  1067. for (os, cpu) in configs:
  1068. config_name = "{0}_{1}_{2}".format(name, os, cpu)
  1069. cc_toolchain_config(
  1070. name = config_name + "_config",
  1071. target_os = os,
  1072. target_cpu = cpu,
  1073. )
  1074. cc_toolchain(
  1075. name = config_name + "_tools",
  1076. all_files = ":" + name + "_empty",
  1077. ar_files = ":" + name + "_empty",
  1078. as_files = ":" + name + "_empty",
  1079. compiler_files = ":" + name + "_empty",
  1080. dwp_files = ":" + name + "_empty",
  1081. linker_files = ":" + name + "_empty",
  1082. objcopy_files = ":" + name + "_empty",
  1083. strip_files = ":" + name + "_empty",
  1084. supports_param_files = 1,
  1085. toolchain_config = ":" + config_name + "_config",
  1086. toolchain_identifier = config_name,
  1087. )
  1088. compatible_with = ["@platforms//cpu:" + cpu, "@platforms//os:" + os]
  1089. native.toolchain(
  1090. name = config_name,
  1091. exec_compatible_with = compatible_with,
  1092. target_compatible_with = compatible_with,
  1093. toolchain = config_name + "_tools",
  1094. toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
  1095. )