defs.bzl 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  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. """Provides rules for building Carbon files using the toolchain."""
  5. load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES")
  6. load("@rules_cc//cc/common:cc_common.bzl", "cc_common")
  7. load("@rules_cc//cc/common:cc_info.bzl", "CcInfo")
  8. def _carbon_binary_impl(ctx):
  9. toolchain_driver = ctx.executable.internal_exec_toolchain_driver
  10. toolchain_data = ctx.files.internal_exec_toolchain_data
  11. prebuilt_runtimes = ctx.files.internal_exec_prebuilt_runtimes
  12. # If the exec driver isn't provided, that means we're trying to use a target
  13. # config toolchain, likely to avoid build overhead of two configs.
  14. if toolchain_driver == None:
  15. toolchain_driver = ctx.executable.internal_target_toolchain_driver
  16. toolchain_data = ctx.files.internal_target_toolchain_data
  17. prebuilt_runtimes = ctx.files.internal_target_prebuilt_runtimes
  18. # The extra link flags needed.
  19. link_flags = []
  20. # Pass any C++ flags from our dependencies onto Carbon.
  21. dep_flags = []
  22. dep_hdrs = []
  23. dep_link_inputs = []
  24. for dep in ctx.attr.deps:
  25. if CcInfo in dep:
  26. cc_info = dep[CcInfo]
  27. # TODO: We should reuse the feature-based flag generation in
  28. # bazel/cc_toolchains here.
  29. dep_flags += ["--clang-arg=-D{0}".format(define) for define in cc_info.compilation_context.defines.to_list()]
  30. dep_flags += ["--clang-arg=-I{0}".format(path) for path in cc_info.compilation_context.includes.to_list()]
  31. dep_flags += ["--clang-arg=-iquote{0}".format(path) for path in cc_info.compilation_context.quote_includes.to_list()]
  32. dep_flags += ["--clang-arg=-isystem{0}".format(path) for path in cc_info.compilation_context.system_includes.to_list()]
  33. dep_hdrs.append(cc_info.compilation_context.headers)
  34. for link_input in cc_info.linking_context.linker_inputs.to_list():
  35. link_flags += link_input.user_link_flags
  36. dep_link_inputs += link_input.additional_inputs
  37. for lib in link_input.libraries:
  38. dep_link_inputs += [dep for dep in [lib.dynamic_library, lib.static_library] if dep]
  39. dep_link_inputs += lib.objects
  40. if DefaultInfo in dep:
  41. dep_link_inputs += dep[DefaultInfo].files.to_list()
  42. # Add the dependencies' link flags and inputs to the link flags.
  43. link_flags += [dep.path for dep in dep_link_inputs]
  44. # Build object files for the prelude and for the binary itself.
  45. # TODO: Eventually the prelude should be build as a separate `carbon_library`.
  46. srcs_and_flags = [
  47. (ctx.files.prelude_srcs, ["--no-prelude-import"]),
  48. (ctx.files.srcs, dep_flags),
  49. ]
  50. objs = []
  51. for (srcs, extra_flags) in srcs_and_flags:
  52. for src in srcs:
  53. # Build each source file. For now, we pass all sources to each compile
  54. # because we don't have visibility into dependencies and have no way to
  55. # specify multiple output files. Object code for each input is written
  56. # into the output file in turn, so the final carbon source file
  57. # specified ends up determining the contents of the object file.
  58. #
  59. # TODO: This is a hack; replace with something better once the toolchain
  60. # supports doing so.
  61. #
  62. # TODO: Switch to the `prefix` based rule similar to linking when
  63. # the prelude moves there.
  64. out = ctx.actions.declare_file("_objs/{0}/{1}o".format(
  65. ctx.label.name,
  66. src.short_path.removeprefix(ctx.label.package).removesuffix(src.extension),
  67. ))
  68. objs.append(out)
  69. srcs_reordered = [s for s in srcs if s != src] + [src]
  70. ctx.actions.run(
  71. outputs = [out],
  72. inputs = depset(direct = srcs_reordered, transitive = dep_hdrs),
  73. executable = toolchain_driver,
  74. tools = depset(toolchain_data),
  75. arguments = ["compile", "--output=" + out.path, "--output-last-input-only"] +
  76. [s.path for s in srcs_reordered] + extra_flags + ctx.attr.flags,
  77. mnemonic = "CarbonCompile",
  78. progress_message = "Compiling " + src.short_path,
  79. )
  80. # Add the Carbon object files to the link flags.
  81. link_flags += [o.path for o in objs]
  82. bin = ctx.actions.declare_file(ctx.label.name)
  83. # Get all link options from the toolchain and dependencies using standard pattern.
  84. cc_toolchain = ctx.attr._cc_toolchain[cc_common.CcToolchainInfo]
  85. feature_configuration = cc_common.configure_features(
  86. ctx = ctx,
  87. cc_toolchain = cc_toolchain,
  88. requested_features = ctx.features,
  89. unsupported_features = ctx.disabled_features,
  90. )
  91. variables = cc_common.create_link_variables(
  92. feature_configuration = feature_configuration,
  93. cc_toolchain = cc_toolchain,
  94. is_using_linker = True,
  95. user_link_flags = link_flags + [
  96. # TODO: Remove once the sanitizer runtimes are available.
  97. "-fno-sanitize=all",
  98. ],
  99. output_file = bin.path,
  100. )
  101. full_link_flags = cc_common.get_memory_inefficient_command_line(
  102. feature_configuration = feature_configuration,
  103. action_name = ACTION_NAMES.cpp_link_executable,
  104. variables = variables,
  105. )
  106. ctx.actions.run(
  107. outputs = [bin],
  108. inputs = objs + dep_link_inputs,
  109. executable = toolchain_driver,
  110. tools = depset(toolchain_data + prebuilt_runtimes),
  111. arguments = full_link_flags,
  112. mnemonic = "CarbonLink",
  113. progress_message = "Linking " + bin.short_path,
  114. )
  115. return [DefaultInfo(files = depset([bin]), executable = bin)]
  116. _carbon_binary_internal = rule(
  117. implementation = _carbon_binary_impl,
  118. attrs = {
  119. "deps": attr.label_list(allow_files = True, providers = [[CcInfo]]),
  120. "flags": attr.string_list(),
  121. # The exec config toolchain attributes. These will be `None` when using
  122. # the target config and populated when using the exec config. We have to
  123. # use duplicate attributes here and below to have different `cfg`
  124. # settings, as that isn't `select`-able, and we'll use `select`s when
  125. # populating these.
  126. "internal_exec_prebuilt_runtimes": attr.label(
  127. cfg = "exec",
  128. ),
  129. "internal_exec_toolchain_data": attr.label(
  130. cfg = "exec",
  131. ),
  132. "internal_exec_toolchain_driver": attr.label(
  133. allow_single_file = True,
  134. executable = True,
  135. cfg = "exec",
  136. ),
  137. # The target config toolchain attributes. These will be 'None' when
  138. # using the exec config and populated when using the target config. We
  139. # have to use duplicate attributes here and below to have different
  140. # `cfg` settings, as that isn't `select`-able, and we'll use `select`s
  141. # when populating these.
  142. "internal_target_prebuilt_runtimes": attr.label(
  143. cfg = "target",
  144. ),
  145. "internal_target_toolchain_data": attr.label(
  146. cfg = "target",
  147. ),
  148. "internal_target_toolchain_driver": attr.label(
  149. allow_single_file = True,
  150. executable = True,
  151. cfg = "target",
  152. ),
  153. "prelude_srcs": attr.label_list(allow_files = [".carbon"]),
  154. "srcs": attr.label_list(allow_files = [".carbon"]),
  155. "_cc_toolchain": attr.label(default = "//toolchain/install:carbon_stage1_cc_toolchain"),
  156. },
  157. executable = True,
  158. fragments = ["cpp"],
  159. )
  160. def carbon_binary(name, srcs, deps = [], flags = [], tags = []):
  161. """Compiles a Carbon binary.
  162. Args:
  163. name: The name of the build target.
  164. srcs: List of Carbon source files to compile.
  165. deps: List of dependencies.
  166. flags: Extra flags to pass to the Carbon compile command.
  167. tags: Tags to apply to the rule.
  168. """
  169. _carbon_binary_internal(
  170. name = name,
  171. srcs = srcs,
  172. prelude_srcs = ["//core:prelude_files"],
  173. deps = deps,
  174. flags = flags,
  175. tags = tags,
  176. # We synthesize two sets of attributes from mirrored `select`s here
  177. # because we want to select on an internal property of these attributes
  178. # but that isn't `select`-able. Instead, we have both attributes and
  179. # `select` which one we use.
  180. internal_exec_toolchain_driver = select({
  181. "//bazel/carbon_rules:use_target_config_carbon_rules_config": None,
  182. "//conditions:default": "//toolchain/install:carbon-busybox",
  183. }),
  184. internal_exec_toolchain_data = select({
  185. "//bazel/carbon_rules:use_target_config_carbon_rules_config": None,
  186. "//conditions:default": "//toolchain/install:install_data",
  187. }),
  188. internal_exec_prebuilt_runtimes = select({
  189. "//bazel/carbon_rules:use_target_config_carbon_rules_config": None,
  190. "//conditions:default": "//toolchain/install:built_runtimes",
  191. }),
  192. internal_target_toolchain_driver = select({
  193. "//bazel/carbon_rules:use_target_config_carbon_rules_config": "//toolchain/install:carbon-busybox",
  194. "//conditions:default": None,
  195. }),
  196. internal_target_toolchain_data = select({
  197. "//bazel/carbon_rules:use_target_config_carbon_rules_config": "//toolchain/install:install_data",
  198. "//conditions:default": None,
  199. }),
  200. internal_target_prebuilt_runtimes = select({
  201. "//bazel/carbon_rules:use_target_config_carbon_rules_config": "//toolchain/install:built_runtimes",
  202. "//conditions:default": None,
  203. }),
  204. )