carbon_cc_toolchain_config.bzl 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  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. """Starlark cc_toolchain configuration rules for using the Carbon toolchain"""
  5. load(
  6. "@carbon_toolchain_config//:carbon_detected_variables.bzl",
  7. "clang_include_dirs",
  8. "clang_sysroot",
  9. )
  10. load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES")
  11. load(
  12. "@rules_cc//cc:cc_toolchain_config_lib.bzl",
  13. "action_config",
  14. "flag_group",
  15. "flag_set",
  16. "tool",
  17. )
  18. load(
  19. "@rules_cc//cc:defs.bzl",
  20. "CcToolchainConfigInfo",
  21. "cc_toolchain",
  22. )
  23. load("@rules_cc//cc/common:cc_common.bzl", "cc_common")
  24. load("//bazel:runtimes_build_vars.bzl", "llvm_version_major")
  25. load(
  26. ":cc_toolchain_actions.bzl",
  27. "all_c_compile_actions",
  28. "all_cpp_compile_actions",
  29. "all_link_actions",
  30. )
  31. load(":cc_toolchain_features.bzl", "clang_cc_toolchain_features")
  32. load(
  33. ":cc_toolchain_tools.bzl",
  34. "llvm_tool_paths",
  35. )
  36. def _make_action_configs(runtimes_path = None):
  37. runtimes_flag = "--no-build-runtimes"
  38. if runtimes_path:
  39. runtimes_flag = "--prebuilt-runtimes={0}".format(runtimes_path)
  40. return [
  41. action_config(
  42. action_name = name,
  43. enabled = True,
  44. tools = [tool(path = "llvm/bin/clang")],
  45. )
  46. for name in all_c_compile_actions
  47. ] + [
  48. action_config(
  49. action_name = name,
  50. enabled = True,
  51. tools = [tool(path = "llvm/bin/clang++")],
  52. )
  53. for name in all_cpp_compile_actions
  54. ] + [
  55. action_config(
  56. action_name = name,
  57. enabled = True,
  58. tools = [tool(path = "carbon-busybox")],
  59. flag_sets = [flag_set(flag_groups = [flag_group(flags = [
  60. runtimes_flag,
  61. "link",
  62. # We want to allow Bazel to intermingle linked object files and
  63. # Clang-spelled link flags. The first `--` starts the list of
  64. # initial object files by ending flags to the `link` subcommand,
  65. # and the second `--` switches to Clang-spelled flags.
  66. "--",
  67. "--",
  68. ])])],
  69. )
  70. for name in all_link_actions
  71. ] + [
  72. action_config(
  73. action_name = name,
  74. enabled = True,
  75. tools = [tool(path = "llvm/bin/llvm-ar")],
  76. )
  77. for name in [ACTION_NAMES.cpp_link_static_library]
  78. ] + [
  79. action_config(
  80. action_name = name,
  81. enabled = True,
  82. tools = [tool(path = "llvm/bin/llvm-strip")],
  83. )
  84. for name in [ACTION_NAMES.strip]
  85. ]
  86. def _carbon_cc_toolchain_config_impl(ctx):
  87. # Hard code the the repository-relative path of the LLVM (and Clang)
  88. # binaries as it is a fixed aspect of the install structure.
  89. llvm_bindir = "llvm/bin"
  90. # Only use a sysroot if a non-trivial one is set in Carbon's config.
  91. builtin_sysroot = None
  92. if clang_sysroot != "None" and clang_sysroot != "/":
  93. builtin_sysroot = clang_sysroot
  94. runtimes_path = None
  95. if ctx.attr.runtimes:
  96. for f in ctx.files.runtimes:
  97. if f.basename == "runtimes_root":
  98. runtimes_path = f.dirname
  99. break
  100. if not runtimes_path:
  101. fail("Unable to compute the runtimes path for: {0}".format(
  102. ctx.attr.runtimes,
  103. ))
  104. identifier = "carbon-toolchain-{0}-{1}".format(
  105. ctx.attr.target_cpu,
  106. ctx.attr.target_os,
  107. )
  108. return cc_common.create_cc_toolchain_config_info(
  109. ctx = ctx,
  110. features = clang_cc_toolchain_features(
  111. target_os = ctx.attr.target_os,
  112. target_cpu = ctx.attr.target_cpu,
  113. ),
  114. action_configs = _make_action_configs(runtimes_path),
  115. cxx_builtin_include_directories = clang_include_dirs,
  116. builtin_sysroot = builtin_sysroot,
  117. # This configuration only supports local non-cross builds so derive
  118. # everything from the target CPU selected.
  119. toolchain_identifier = identifier,
  120. # This is used to expose a "flag" that `config_setting` rules can use to
  121. # determine if the compiler is Clang.
  122. compiler = "clang",
  123. # We do have to pass in our tool paths.
  124. tool_paths = llvm_tool_paths(llvm_bindir),
  125. )
  126. carbon_cc_toolchain_config = rule(
  127. implementation = _carbon_cc_toolchain_config_impl,
  128. attrs = {
  129. "runtimes": attr.label(mandatory = False),
  130. "target_cpu": attr.string(mandatory = True),
  131. "target_os": attr.string(mandatory = True),
  132. },
  133. provides = [CcToolchainConfigInfo],
  134. )
  135. def _runtimes_transition_impl(_, attr):
  136. # Adjust the platform to the runtimes platform across the transition.
  137. return {"//command_line_option:platforms": [str(attr.runtimes_platform)]}
  138. runtimes_transition = transition(
  139. inputs = [],
  140. outputs = ["//command_line_option:platforms"],
  141. implementation = _runtimes_transition_impl,
  142. )
  143. def _runtimes_filegroup_impl(ctx):
  144. return [DefaultInfo(files = depset(ctx.files.srcs))]
  145. runtimes_filegroup = rule(
  146. implementation = _runtimes_filegroup_impl,
  147. attrs = {
  148. # The platform to use when building the runtimes.
  149. "runtimes_platform": attr.label(mandatory = True),
  150. # Mark that our dependencies are built through a transition.
  151. "srcs": attr.label_list(mandatory = True, cfg = runtimes_transition),
  152. # Enable transitions in this rule.
  153. "_allowlist_function_transition": attr.label(
  154. default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
  155. ),
  156. },
  157. )
  158. def carbon_cc_toolchain_suite(name, platforms):
  159. """Create a toolchain suite that uses the local Clang/LLVM install.
  160. Args:
  161. name: The name of the toolchain suite to produce.
  162. platforms: An array of (os, cpu) pairs to support in the toolchain.
  163. """
  164. # Our base filegroup for the toolchain just includes the busybox and the
  165. # LLVM symlinks. Importantly, this _doesn't_ include the install digest that
  166. # would cause cache misses as-if every file in the toolchain were an input
  167. # to every action.
  168. native.filegroup(
  169. name = name + "_base_files",
  170. srcs = ["carbon-busybox", "carbon_install.txt"] + native.glob([
  171. "llvm/bin/*",
  172. ]),
  173. )
  174. # We also need a compile-specific filegroup for use when _building_
  175. # runtimes. This needs to include the dedicated Clang headers, but we
  176. # require the runtimes themselves to provide the relevant headers and
  177. # dependencies.
  178. native.filegroup(
  179. name = name + "_runtimes_compile_files",
  180. srcs = [
  181. ":" + name + "_base_files",
  182. "//llvm/lib/clang/{0}:clang_hdrs".format(llvm_version_major),
  183. ],
  184. )
  185. # We can build a single common compile filegroup regardless of CPU and OS.
  186. # This needs to include all the headers of the runtimes, but those are
  187. # architecture independent.
  188. native.filegroup(
  189. name = name + "_compile_files",
  190. srcs = [
  191. ":" + name + "_runtimes_compile_files",
  192. "//runtimes:libunwind_hdrs",
  193. "//runtimes:libcxx_hdrs",
  194. ],
  195. )
  196. # Create the actual toolchains for each OS and CPU.
  197. for (os, cpu) in platforms:
  198. platform_name = "{0}_{1}_{2}".format(name, os, cpu)
  199. platform_constraints = [
  200. "@platforms//os:" + os,
  201. "@platforms//cpu:" + cpu,
  202. ]
  203. # First, configure a platform and toolchain for building runtimes. This
  204. # toolchain will only have the Clang headers and no runtime libraries
  205. # included.
  206. native.platform(
  207. name = platform_name + "_runtimes_platform",
  208. constraint_values = [":is_runtimes_build"] + platform_constraints,
  209. )
  210. carbon_cc_toolchain_config(
  211. name = platform_name + "_runtimes_toolchain_config",
  212. target_cpu = cpu,
  213. target_os = os,
  214. )
  215. cc_toolchain(
  216. name = platform_name + "_runtimes_cc_toolchain",
  217. all_files = ":" + name + "_runtimes_compile_files",
  218. ar_files = ":" + name + "_base_files",
  219. as_files = ":" + name + "_runtimes_compile_files",
  220. compiler_files = ":" + name + "_runtimes_compile_files",
  221. dwp_files = ":" + name + "_base_files",
  222. linker_files = ":" + name + "_base_files",
  223. objcopy_files = ":" + name + "_base_files",
  224. strip_files = ":" + name + "_base_files",
  225. toolchain_config = ":" + platform_name + "_runtimes_toolchain_config",
  226. toolchain_identifier = platform_name + "_runtimes",
  227. )
  228. native.toolchain(
  229. name = platform_name + "_runtimes_toolchain",
  230. exec_compatible_with = platform_constraints,
  231. target_compatible_with = [":is_runtimes_build"] + platform_constraints,
  232. toolchain = platform_name + "_runtimes_cc_toolchain",
  233. toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
  234. )
  235. # Now we can use the runtimes platform to build the runtimes on-demand.
  236. runtimes_filegroup(
  237. name = platform_name + "_runtimes",
  238. srcs = ["//runtimes:carbon_runtimes"],
  239. runtimes_platform = ":" + platform_name + "_runtimes_platform",
  240. )
  241. # Finally, we can build the main platform and toolchain.
  242. native.platform(
  243. name = platform_name + "_platform",
  244. constraint_values = platform_constraints,
  245. )
  246. # Build the main config with runtimes passed in. This allows the
  247. # configuration to use these built runtimes where needed.
  248. carbon_cc_toolchain_config(
  249. name = platform_name + "_toolchain_config",
  250. target_cpu = cpu,
  251. target_os = os,
  252. runtimes = ":" + platform_name + "_runtimes",
  253. )
  254. # We also include the runtimes in the linker files. We have to do this
  255. # in addition to the config parameter as the config can't carry the
  256. # actual dependency.
  257. native.filegroup(
  258. name = platform_name + "_linker_files",
  259. srcs = [
  260. ":" + name + "_base_files",
  261. ":" + platform_name + "_runtimes",
  262. ],
  263. )
  264. native.filegroup(
  265. name = platform_name + "_all_files",
  266. srcs = [
  267. ":" + name + "_compile_files",
  268. ":" + platform_name + "_linker_files",
  269. ],
  270. )
  271. cc_toolchain(
  272. name = platform_name + "_cc_toolchain",
  273. all_files = ":" + platform_name + "_all_files",
  274. ar_files = ":" + name + "_base_files",
  275. as_files = ":" + name + "_compile_files",
  276. compiler_files = ":" + name + "_compile_files",
  277. dwp_files = ":" + platform_name + "_linker_files",
  278. linker_files = ":" + platform_name + "_linker_files",
  279. objcopy_files = ":" + name + "_base_files",
  280. strip_files = ":" + name + "_base_files",
  281. toolchain_config = ":" + platform_name + "_toolchain_config",
  282. toolchain_identifier = platform_name,
  283. )
  284. native.toolchain(
  285. name = platform_name + "_toolchain",
  286. exec_compatible_with = platform_constraints,
  287. target_compatible_with = platform_constraints,
  288. toolchain = platform_name + "_cc_toolchain",
  289. toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
  290. )