install_filegroups.bzl 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  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. """Rules for constructing install information."""
  5. load("@rules_pkg//pkg:mappings.bzl", "pkg_attributes", "pkg_filegroup", "pkg_files", "pkg_mklink", "strip_prefix")
  6. load("//toolchain/base:llvm_tools.bzl", "LLVM_MAIN_TOOLS", "LLVM_TOOL_ALIASES")
  7. _clang_aliases = [
  8. "clang",
  9. "clang++",
  10. "clang-cl",
  11. "clang-cpp",
  12. ]
  13. # TODO: Add remaining aliases of LLD for Windows and WASM when we have support
  14. # for them wired up through the busybox.
  15. _lld_aliases = [
  16. "ld.lld",
  17. "ld64.lld",
  18. ]
  19. _llvm_binaries = _clang_aliases + _lld_aliases + [
  20. tool.bin_name
  21. for tool in LLVM_MAIN_TOOLS.values()
  22. ] + [
  23. "llvm-" + alias
  24. for (_, aliases) in LLVM_TOOL_ALIASES.items()
  25. for alias in aliases
  26. ]
  27. def _toolchain_llvm_binaries_impl(ctx):
  28. outputs = []
  29. for bin in _llvm_binaries:
  30. out = ctx.actions.declare_file(ctx.attr.prefix + "llvm/bin/" + bin)
  31. ctx.actions.symlink(
  32. output = out,
  33. target_file = ctx.files.carbon_binary[0],
  34. )
  35. outputs.append(out)
  36. return [DefaultInfo(files = depset(direct = outputs))]
  37. toolchain_llvm_binaries = rule(
  38. doc = "Creates symlinks for LLVM binaries pointing to a single Carbon binary.",
  39. implementation = _toolchain_llvm_binaries_impl,
  40. attrs = {
  41. "carbon_binary": attr.label(
  42. allow_single_file = True,
  43. #executable = True,
  44. mandatory = True,
  45. #cfg = None,
  46. ),
  47. "prefix": attr.string(default = ""),
  48. },
  49. )
  50. def _removeprefix_or_fail(s, prefix):
  51. if prefix == "":
  52. return s
  53. new_s = s.removeprefix(prefix)
  54. if new_s == s:
  55. fail("Unable to remove prefix '{0}' from '{1}'".format(prefix, s))
  56. return new_s
  57. def _get_pkg_relative_path(file):
  58. path = file.path
  59. if file.root.path != "":
  60. path = _removeprefix_or_fail(path, file.root.path + "/")
  61. if file.owner.workspace_root != "":
  62. path = _removeprefix_or_fail(path, file.owner.workspace_root + "/")
  63. return _removeprefix_or_fail(path, file.owner.package + "/")
  64. def _toolchain_files_impl(ctx):
  65. prefix = ctx.attr.prefix
  66. outputs = []
  67. for src in ctx.files.srcs:
  68. rel_path = _get_pkg_relative_path(src)
  69. rel_path = _removeprefix_or_fail(rel_path, ctx.attr.remove_prefix)
  70. if rel_path in ctx.attr.renames:
  71. rel_path = ctx.attr.renames[rel_path]
  72. out = ctx.actions.declare_file("{0}{1}".format(prefix, rel_path))
  73. ctx.actions.symlink(output = out, target_file = src)
  74. outputs.append(out)
  75. return [DefaultInfo(files = depset(outputs))]
  76. toolchain_files = rule(
  77. doc = "Arranges files into a directory structure by symlinking them with prefix removal and renames.",
  78. implementation = _toolchain_files_impl,
  79. attrs = {
  80. "prefix": attr.string(default = ""),
  81. "remove_prefix": attr.string(default = ""),
  82. "renames": attr.string_dict(default = {}),
  83. "srcs": attr.label_list(allow_files = True),
  84. },
  85. )
  86. def _filtered_files_impl(ctx):
  87. include_set = set()
  88. for filter_src in ctx.files.filter_to_srcs:
  89. rel_path = _get_pkg_relative_path(filter_src)
  90. include_set.add(_removeprefix_or_fail(rel_path, ctx.attr.filter_to_srcs_prefix))
  91. outputs = []
  92. for src in ctx.files.srcs:
  93. rel_path = _get_pkg_relative_path(src)
  94. if _removeprefix_or_fail(rel_path, ctx.attr.srcs_prefix) in include_set:
  95. outputs.append(src)
  96. return [DefaultInfo(files = depset(outputs))]
  97. filtered_files = rule(
  98. doc = "Filters a set of files based on their relative paths matching another set of files.",
  99. implementation = _filtered_files_impl,
  100. attrs = {
  101. "filter_to_srcs": attr.label_list(),
  102. "filter_to_srcs_prefix": attr.string(default = ""),
  103. "srcs": attr.label_list(),
  104. "srcs_prefix": attr.string(default = ""),
  105. },
  106. )
  107. def filtered_toolchain_files(name, prefix, remove_prefix, srcs_groups):
  108. """A collection of filtered toolchain files from overlapping `srcs`."""
  109. name_base = name.removesuffix("_srcs")
  110. if name_base == "" or name_base == name:
  111. fail("Invalid name for building a set of filtered toolchain files.")
  112. toolchain_files(
  113. name = name_base + "_all_srcs",
  114. srcs = srcs_groups,
  115. prefix = prefix,
  116. remove_prefix = remove_prefix,
  117. )
  118. for srcs in srcs_groups:
  119. suffix = srcs.partition(":")[2].removeprefix(name_base)
  120. filtered_files(
  121. name = name_base + suffix,
  122. srcs = [":" + name_base + "_all_srcs"],
  123. srcs_prefix = prefix,
  124. filter_to_srcs = [srcs],
  125. filter_to_srcs_prefix = remove_prefix,
  126. )
  127. def toolchain_pkg_filegroup(name, carbon_busybox, srcs, tags = []):
  128. """Given a CMake-style install prefix[1], the hierarchy looks like:
  129. - prefix/bin: Binaries intended for direct use.
  130. - prefix/lib/carbon: Private data and files.
  131. - prefix/lib/carbon/core: The `Core` package files.
  132. - prefix/lib/carbon/llvm/bin: LLVM binaries.
  133. This will be how installs are provided on Unix-y platforms, and is loosely
  134. based on the FHS (Filesystem Hierarchy Standard). See the CMake install prefix
  135. documentation[1] for more details.
  136. [1]: https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html
  137. """
  138. pkg_srcs = []
  139. # Separately handle the busybox so that we can set its attributes.
  140. pkg_files(
  141. name = name + "_busybox",
  142. srcs = [carbon_busybox],
  143. prefix = "lib/carbon",
  144. attributes = pkg_attributes(mode = "0755"),
  145. tags = tags,
  146. )
  147. pkg_srcs.append(":" + name + "_busybox")
  148. pkg_files(
  149. name = name + "_srcs",
  150. srcs = srcs,
  151. prefix = "lib/carbon",
  152. strip_prefix = strip_prefix.from_pkg(),
  153. tags = tags,
  154. )
  155. pkg_srcs.append(":" + name + "_srcs")
  156. for bin in _llvm_binaries:
  157. pkg_mklink(
  158. name = name + "_llvm_symlink_" + bin,
  159. link_name = "lib/carbon/llvm/bin/" + bin,
  160. target = "../../carbon-busybox",
  161. tags = tags,
  162. )
  163. pkg_srcs.append(":" + name + "_llvm_symlink_" + bin)
  164. pkg_mklink(
  165. name = name + "_bin_symlink",
  166. link_name = "bin/carbon",
  167. target = "../lib/carbon/carbon-busybox",
  168. tags = tags,
  169. )
  170. pkg_srcs.append(":" + name + "_bin_symlink")
  171. pkg_filegroup(name = name, srcs = pkg_srcs, tags = tags)