carbon_runtimes.bzl 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  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 rules for building a Carbon runtimes tree.
  5. TODO: Currently, this produces a complete, static Carbon runtimes tree that
  6. mirrors the exact style of runtimes tree the Carbon toolchain would build on its
  7. own. However, it would be preferable to preserve the builtins, libc++, and
  8. libunwind `cc_library` rules as "normal" library rules (if behind a transition)
  9. and automatically depend on them. This would allow things like LTO and such to
  10. include these. However, this requires support in `@rules_cc` for this kind of
  11. dependency to be added.
  12. """
  13. load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
  14. load("@rules_cc//cc/common:cc_common.bzl", "cc_common")
  15. def _build_crt_file(ctx, cc_toolchain, feature_configuration, crt_file, crt_copts):
  16. _, compilation_outputs = cc_common.compile(
  17. name = "{}.compile_{}".format(ctx.label.name, crt_file.basename),
  18. actions = ctx.actions,
  19. feature_configuration = feature_configuration,
  20. cc_toolchain = cc_toolchain,
  21. srcs = [crt_file],
  22. user_compile_flags = crt_copts,
  23. )
  24. # Extract the PIC object file and make sure we built one.
  25. obj = compilation_outputs.pic_objects[0]
  26. if not obj:
  27. fail("The toolchain failed to produce a PIC object file. Ensure your " +
  28. "toolchain supports PIC.")
  29. return obj
  30. def _removeprefix_or_fail(s, prefix):
  31. new_s = s.removeprefix(prefix)
  32. if new_s == s:
  33. fail("Unable to remove prefix '{0}' from '{1}'".format(prefix, s))
  34. return new_s
  35. CarbonRuntimesConfigInfo = provider(
  36. doc = """Configuration for Carbon runtimes.
  37. This provider is used to collect all of the information that will be needed
  38. to build a Carbon runtimes directory for a Bazel Carbon `cc_toolchain`.
  39. """,
  40. fields = [
  41. "builtins_archive",
  42. "clang_hdrs_prefix",
  43. "crt_copts",
  44. "crtbegin_src",
  45. "crtend_src",
  46. "darwin_os_suffix",
  47. "libcxx_archive",
  48. "libunwind_archive",
  49. "target_triple",
  50. ],
  51. )
  52. def _carbon_runtimes_config_impl(ctx):
  53. return [
  54. CarbonRuntimesConfigInfo(
  55. builtins_archive = ctx.files.builtins_archive[0],
  56. clang_hdrs_prefix = ctx.attr.clang_hdrs_prefix,
  57. crt_copts = ctx.attr.crt_copts,
  58. crtbegin_src = ctx.files.crtbegin_src[0] if ctx.files.crtbegin_src else None,
  59. crtend_src = ctx.files.crtend_src[0] if ctx.files.crtend_src else None,
  60. darwin_os_suffix = ctx.attr.darwin_os_suffix,
  61. libcxx_archive = ctx.files.libcxx_archive[0],
  62. libunwind_archive = ctx.files.libunwind_archive[0],
  63. target_triple = ctx.attr.target_triple,
  64. ),
  65. ]
  66. carbon_runtimes_config = rule(
  67. implementation = _carbon_runtimes_config_impl,
  68. attrs = {
  69. "builtins_archive": attr.label(mandatory = True, allow_files = [".a"]),
  70. "clang_hdrs_prefix": attr.string(default = "include/"),
  71. "crt_copts": attr.string_list(default = []),
  72. "crtbegin_src": attr.label(allow_files = [".c"]),
  73. "crtend_src": attr.label(allow_files = [".c"]),
  74. "darwin_os_suffix": attr.string(mandatory = False),
  75. "libcxx_archive": attr.label(mandatory = True, allow_files = [".a"]),
  76. "libunwind_archive": attr.label(mandatory = True, allow_files = [".a"]),
  77. "target_triple": attr.string(mandatory = False),
  78. },
  79. doc = "Collects configuration for building a Carbon runtimes tree.",
  80. )
  81. def _carbon_runtimes_build_impl(ctx):
  82. config = ctx.attr.config[CarbonRuntimesConfigInfo]
  83. outputs = []
  84. prefix = ctx.attr.name
  85. # Create a marker file in the runtimes root first. We'll use this to locate
  86. # the runtimes for the toolchain.
  87. root_out = ctx.actions.declare_file("{0}/runtimes_root".format(prefix))
  88. ctx.actions.write(output = root_out, content = "")
  89. outputs.append(root_out)
  90. # Setup the C++ toolchain and configuration. We also force the `pic` feature
  91. # to be enabled for these actions as we always want PIC generated code --
  92. # this avoids the need to build two versions of the runtimes and doesn't
  93. # create problems with modern code generation when linking statically. This
  94. # also simplifies extracting the outputs as we only need to look at
  95. # `pic_objects`.
  96. cc_toolchain = find_cpp_toolchain(ctx)
  97. feature_configuration = cc_common.configure_features(
  98. ctx = ctx,
  99. cc_toolchain = cc_toolchain,
  100. requested_features = ctx.features + ["pic"],
  101. unsupported_features = ctx.disabled_features,
  102. )
  103. builtins_lib_path = "clang_resource_dir/lib"
  104. builtins_archive_name = "libclang_rt.builtins.a"
  105. if config.target_triple != "":
  106. builtins_lib_path = "clang_resource_dir/lib/{0}".format(config.target_triple)
  107. elif config.darwin_os_suffix:
  108. builtins_lib_path = "clang_resource_dir/lib/darwin"
  109. builtins_archive_name = "libclang_rt.{0}.a".format(config.darwin_os_suffix)
  110. for filename, src in [
  111. ("crtbegin", config.crtbegin_src),
  112. ("crtend", config.crtend_src),
  113. ]:
  114. if not src:
  115. continue
  116. crt_obj = _build_crt_file(ctx, cc_toolchain, feature_configuration, src, config.crt_copts)
  117. crt_out = ctx.actions.declare_file("{0}/{1}/clang_rt.{2}.o".format(
  118. prefix,
  119. builtins_lib_path,
  120. filename,
  121. ))
  122. ctx.actions.symlink(output = crt_out, target_file = crt_obj)
  123. outputs.append(crt_out)
  124. for runtime_dir, archive_name, archive in [
  125. (builtins_lib_path, builtins_archive_name, config.builtins_archive),
  126. ("libcxx/lib", "libc++.a", config.libcxx_archive),
  127. ("libunwind/lib", "libunwind.a", config.libunwind_archive),
  128. ]:
  129. runtime_out = ctx.actions.declare_file("{0}/{1}/{2}".format(
  130. prefix,
  131. runtime_dir,
  132. archive_name,
  133. ))
  134. ctx.actions.symlink(output = runtime_out, target_file = archive)
  135. outputs.append(runtime_out)
  136. for hdr in ctx.files.clang_hdrs:
  137. # Incrementally remove prefixes of the paths to find the `include`
  138. # directory we want to symlink into the output tree.
  139. rel_path = hdr.path
  140. if hdr.root.path != "":
  141. rel_path = _removeprefix_or_fail(rel_path, "{}/".format(hdr.root.path))
  142. if hdr.owner.workspace_root != "":
  143. rel_path = _removeprefix_or_fail(rel_path, "{}/".format(hdr.owner.workspace_root))
  144. if hdr.owner.package != "":
  145. rel_path = _removeprefix_or_fail(rel_path, "{}/".format(hdr.owner.package))
  146. rel_path = _removeprefix_or_fail(rel_path, config.clang_hdrs_prefix)
  147. out_hdr = ctx.actions.declare_file(
  148. "{0}/clang_resource_dir/include/{1}".format(prefix, rel_path),
  149. )
  150. ctx.actions.symlink(output = out_hdr, target_file = hdr)
  151. outputs.append(out_hdr)
  152. return [DefaultInfo(files = depset(outputs))]
  153. carbon_runtimes_build = rule(
  154. implementation = _carbon_runtimes_build_impl,
  155. attrs = {
  156. "clang_hdrs": attr.label_list(
  157. mandatory = True,
  158. allow_files = True,
  159. ),
  160. "config": attr.label(mandatory = True, providers = [CarbonRuntimesConfigInfo]),
  161. "_cc_toolchain": attr.label(
  162. default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"),
  163. ),
  164. },
  165. toolchains = ["@bazel_tools//tools/cpp:toolchain_type"],
  166. fragments = ["cpp"],
  167. doc = """Builds a Carbon runtimes tree using a config rule and clang_hdrs.
  168. The configuration provides access to all of the targets that should be built
  169. into the runtimes.
  170. Any files, such as `clang_hdrs`, that should be built _prior_ to the
  171. runtimes build taking place are accepted as separate file groups so that
  172. they can be properly handled when bootstrapping.
  173. """,
  174. )