defs.bzl 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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/common:cc_info.bzl", "CcInfo")
  6. def _carbon_binary_impl(ctx):
  7. toolchain_driver = ctx.executable.internal_exec_toolchain_driver
  8. toolchain_data = ctx.files.internal_exec_toolchain_data
  9. # If the exec driver isn't provided, that means we're trying to use a target
  10. # config toolchain, likely to avoid build overhead of two configs.
  11. if toolchain_driver == None:
  12. toolchain_driver = ctx.executable.internal_target_toolchain_driver
  13. toolchain_data = ctx.files.internal_target_toolchain_data
  14. # Pass any C++ flags from our dependencies onto Carbon.
  15. dep_flags = []
  16. dep_hdrs = []
  17. dep_link_flags = []
  18. dep_link_inputs = []
  19. for dep in ctx.attr.deps:
  20. if CcInfo in dep:
  21. cc_info = dep[CcInfo]
  22. # TODO: We should reuse the feature-based flag generation in
  23. # bazel/cc_toolchains here.
  24. dep_flags += ["--clang-arg=-D{0}".format(define) for define in cc_info.compilation_context.defines.to_list()]
  25. dep_flags += ["--clang-arg=-I{0}".format(path) for path in cc_info.compilation_context.includes.to_list()]
  26. dep_flags += ["--clang-arg=-iquote{0}".format(path) for path in cc_info.compilation_context.quote_includes.to_list()]
  27. dep_flags += ["--clang-arg=-isystem{0}".format(path) for path in cc_info.compilation_context.system_includes.to_list()]
  28. dep_hdrs.append(cc_info.compilation_context.headers)
  29. for link_input in cc_info.linking_context.linker_inputs.to_list():
  30. # TODO: `carbon link` doesn't support linker flags yet.
  31. # dep_link_flags += link_input.user_link_flags
  32. dep_link_inputs += link_input.additional_inputs
  33. for lib in link_input.libraries:
  34. dep_link_inputs += [dep for dep in [lib.dynamic_library, lib.static_library] if dep]
  35. dep_link_inputs += lib.objects
  36. if DefaultInfo in dep:
  37. dep_link_inputs += dep[DefaultInfo].files.to_list()
  38. dep_link_flags += [dep.path for dep in dep_link_inputs]
  39. # Build object files for the prelude and for the binary itself.
  40. # TODO: Eventually the prelude should be build as a separate `carbon_library`.
  41. srcs_and_flags = [
  42. (ctx.files.prelude_srcs, ["--no-prelude-import"]),
  43. (ctx.files.srcs, dep_flags),
  44. ]
  45. objs = []
  46. for (srcs, extra_flags) in srcs_and_flags:
  47. for src in srcs:
  48. # Build each source file. For now, we pass all sources to each compile
  49. # because we don't have visibility into dependencies and have no way to
  50. # specify multiple output files. Object code for each input is written
  51. # into the output file in turn, so the final carbon source file
  52. # specified ends up determining the contents of the object file.
  53. #
  54. # TODO: This is a hack; replace with something better once the toolchain
  55. # supports doing so.
  56. #
  57. # TODO: Switch to the `prefix_root` based rule similar to linking when
  58. # the prelude moves there.
  59. out = ctx.actions.declare_file("_objs/{0}/{1}o".format(
  60. ctx.label.name,
  61. src.short_path.removeprefix(ctx.label.package).removesuffix(src.extension),
  62. ))
  63. objs.append(out)
  64. srcs_reordered = [s for s in srcs if s != src] + [src]
  65. ctx.actions.run(
  66. outputs = [out],
  67. inputs = depset(direct = srcs_reordered, transitive = dep_hdrs),
  68. executable = toolchain_driver,
  69. tools = depset(toolchain_data),
  70. arguments = ["compile", "--output=" + out.path, "--clang-arg=-stdlib=libc++"] + [s.path for s in srcs_reordered] + extra_flags,
  71. mnemonic = "CarbonCompile",
  72. progress_message = "Compiling " + src.short_path,
  73. )
  74. bin = ctx.actions.declare_file(ctx.label.name)
  75. ctx.actions.run(
  76. outputs = [bin],
  77. inputs = objs + dep_link_inputs,
  78. executable = toolchain_driver,
  79. tools = depset(toolchain_data),
  80. arguments = ["link", "--output=" + bin.path] + dep_link_flags + [o.path for o in objs],
  81. mnemonic = "CarbonLink",
  82. progress_message = "Linking " + bin.short_path,
  83. )
  84. return [DefaultInfo(files = depset([bin]), executable = bin)]
  85. _carbon_binary_internal = rule(
  86. implementation = _carbon_binary_impl,
  87. attrs = {
  88. "deps": attr.label_list(allow_files = True, providers = [[CcInfo]]),
  89. # The exec config toolchain driver and data. These will be `None` when
  90. # using the target config and populated when using the exec config. We
  91. # have to use duplicate attributes here and below to have different
  92. # `cfg` settings, as that isn't `select`-able, and we'll use `select`s
  93. # when populating these.
  94. "internal_exec_toolchain_data": attr.label(
  95. cfg = "exec",
  96. ),
  97. "internal_exec_toolchain_driver": attr.label(
  98. allow_single_file = True,
  99. executable = True,
  100. cfg = "exec",
  101. ),
  102. # The target config toolchain driver and data. These will be 'None' when
  103. # using the exec config and populated when using the target config. We
  104. # have to use duplicate attributes here and below to have different
  105. # `cfg` settings, as that isn't `select`-able, and we'll use `select`s
  106. # when populating these.
  107. "internal_target_toolchain_data": attr.label(
  108. cfg = "target",
  109. ),
  110. "internal_target_toolchain_driver": attr.label(
  111. allow_single_file = True,
  112. executable = True,
  113. cfg = "target",
  114. ),
  115. "prelude_srcs": attr.label_list(allow_files = [".carbon"]),
  116. "srcs": attr.label_list(allow_files = [".carbon"]),
  117. "_cc_toolchain": attr.label(default = "@bazel_tools//tools/cpp:current_cc_toolchain"),
  118. },
  119. executable = True,
  120. )
  121. def carbon_binary(name, srcs, deps = [], tags = []):
  122. """Compiles a Carbon binary.
  123. Args:
  124. name: The name of the build target.
  125. srcs: List of Carbon source files to compile.
  126. deps: List of dependencies.
  127. tags: Tags to apply to the rule.
  128. """
  129. _carbon_binary_internal(
  130. name = name,
  131. srcs = srcs,
  132. prelude_srcs = ["//core:prelude_files"],
  133. deps = deps,
  134. tags = tags,
  135. # We synthesize two sets of attributes from mirrored `select`s here
  136. # because we want to select on an internal property of these attributes
  137. # but that isn't `select`-able. Instead, we have both attributes and
  138. # `select` which one we use.
  139. internal_exec_toolchain_driver = select({
  140. "//bazel/carbon_rules:use_target_config_carbon_rules_config": None,
  141. "//conditions:default": "//toolchain/install:prefix_root/bin/carbon",
  142. }),
  143. internal_exec_toolchain_data = select({
  144. "//bazel/carbon_rules:use_target_config_carbon_rules_config": None,
  145. "//conditions:default": "//toolchain/install:install_data",
  146. }),
  147. internal_target_toolchain_driver = select({
  148. "//bazel/carbon_rules:use_target_config_carbon_rules_config": "//toolchain/install:prefix_root/bin/carbon",
  149. "//conditions:default": None,
  150. }),
  151. internal_target_toolchain_data = select({
  152. "//bazel/carbon_rules:use_target_config_carbon_rules_config": "//toolchain/install:install_data",
  153. "//conditions:default": None,
  154. }),
  155. )