platforms.bzl 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. # Copyright 2019 The Kubernetes Authors.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. load("@bazel_skylib//lib:new_sets.bzl", "sets")
  15. load("@bazel_skylib//lib:types.bzl", "types")
  16. # KUBE_SERVER_PLATFORMS in hack/lib/golang.sh
  17. SERVER_PLATFORMS = {
  18. "linux": [
  19. "amd64",
  20. "arm",
  21. "arm64",
  22. "ppc64le",
  23. "s390x",
  24. ],
  25. }
  26. # KUBE_NODE_PLATFORMS in hack/lib/golang.sh
  27. NODE_PLATFORMS = {
  28. "linux": [
  29. "amd64",
  30. "arm",
  31. "arm64",
  32. "ppc64le",
  33. "s390x",
  34. ],
  35. "windows": [
  36. "amd64",
  37. ],
  38. }
  39. # KUBE_CLIENT_PLATFORMS in hack/lib/golang.sh
  40. CLIENT_PLATFORMS = {
  41. "linux": [
  42. "386",
  43. "amd64",
  44. "arm",
  45. "arm64",
  46. "ppc64le",
  47. "s390x",
  48. ],
  49. "darwin": [
  50. "386",
  51. "amd64",
  52. ],
  53. "windows": [
  54. "386",
  55. "amd64",
  56. ],
  57. }
  58. # KUBE_TEST_PLATFORMS in hack/lib/golang.sh
  59. TEST_PLATFORMS = {
  60. "linux": [
  61. "amd64",
  62. "arm",
  63. "arm64",
  64. "s390x",
  65. "ppc64le",
  66. ],
  67. "darwin": [
  68. "amd64",
  69. ],
  70. "windows": [
  71. "amd64",
  72. ],
  73. }
  74. # Helper which produces the ALL_PLATFORMS dictionary, composed of the union of
  75. # CLIENT, NODE, SERVER, and TEST platforms
  76. def _all_platforms():
  77. all_platforms = {}
  78. for platforms in [CLIENT_PLATFORMS, NODE_PLATFORMS, SERVER_PLATFORMS, TEST_PLATFORMS]:
  79. for os, archs in platforms.items():
  80. all_platforms[os] = sets.union(
  81. all_platforms.setdefault(os, sets.make()),
  82. sets.make(archs),
  83. )
  84. for os, archs in all_platforms.items():
  85. all_platforms[os] = sets.to_list(archs)
  86. return all_platforms
  87. ALL_PLATFORMS = _all_platforms()
  88. def go_platform_constraint(os, arch):
  89. return "@io_bazel_rules_go//go/platform:%s_%s" % (os, arch)
  90. # Helper to for_platforms which updates the select() dictionary.
  91. # d is the dictionary being updated.
  92. # value is the value to set for each item of platforms, which should
  93. # be a single platform category dictionary (e.g. SERVER_PLATFORMS).
  94. # only_os selects one of the OSes in platforms.
  95. def _update_dict_for_platform_category(d, value, platforms, only_os = None):
  96. if not value:
  97. return
  98. for os, arches in platforms.items():
  99. if only_os and os != only_os:
  100. continue
  101. for arch in arches:
  102. constraint = go_platform_constraint(os, arch)
  103. fmt_args = {"OS": os, "ARCH": arch}
  104. if types.is_list(value):
  105. # Format all items in the list, and hope there are no duplicates
  106. d.setdefault(constraint, []).extend(
  107. [v.format(**fmt_args) for v in value],
  108. )
  109. else:
  110. # Don't overwrite existing value
  111. if constraint in d:
  112. fail("duplicate entry for constraint %s", constraint)
  113. if types.is_dict(value):
  114. # Format dictionary values only
  115. d[constraint] = {
  116. dict_key: dict_value.format(**fmt_args)
  117. for dict_key, dict_value in value.items()
  118. }
  119. else:
  120. # Hopefully this is just a string
  121. d[constraint] = value.format(**fmt_args)
  122. # for_platforms returns a dictionary to be used with select().
  123. # select() is used for configurable attributes (most attributes, notably
  124. # excluding output filenames), and takes a dictionary mapping a condition
  125. # to a value for that attribute.
  126. # select() is described in more detail in the Bazel documentation:
  127. # https://docs.bazel.build/versions/master/be/functions.html#select
  128. #
  129. # One notable condition is the target platform (os and arch).
  130. # Kubernetes binaries generally target particular platform categories,
  131. # such as client binaries like kubectl, or node binaries like kubelet.
  132. # Additionally, some build artifacts need specific configurations such as
  133. # the appropriate arch-specific base image.
  134. #
  135. # This macro produces a dictionary where each of the platform categories
  136. # (client, node, server, test, all) is enumerated and filled in
  137. # with the provided arguments as the values.
  138. #
  139. # For example, a filegroup might want to include one binary for all client
  140. # platforms and another binary for server platforms. The client and server
  141. # platform lists have some shared items but also some disjoint items.
  142. # The client binary can be provided in for_client and the server binary provided
  143. # in for_server; this macro will then return a select() dictionary that
  144. # includes the appropriate binaries based on the configured platform.
  145. #
  146. # Another example selecting the appropriate base image for a docker container.
  147. # One can use select(for_platforms(for_server="base-image-{ARCH}//image"))
  148. # to have the appropriate arch-specific image selected.
  149. #
  150. # The for_platform arguments can be lists, dictionaries, or strings, but
  151. # they should all be the same type for a given call.
  152. # The tokens {OS} and {ARCH} will be substituted with the corresponding values,
  153. # but if a dictionary is provided, only the dictionary values will be formatted.
  154. #
  155. # If default is provided, a default condition will be added with the provided
  156. # value.
  157. # only_os can be used to select a single OS from a platform category that lists
  158. # multiple OSes. For example, it doesn't make sense to build debs or RPMs for
  159. # anything besides Linux, so you might supply only_os="linux" for those rules.
  160. #
  161. # For a complete example, consult something like the release-tars target in
  162. # build/release-tars/BUILD.
  163. def for_platforms(
  164. for_client = None,
  165. for_node = None,
  166. for_server = None,
  167. for_test = None,
  168. for_all = None,
  169. default = None,
  170. only_os = None):
  171. d = {}
  172. if default != None:
  173. d["//conditions:default"] = default
  174. _update_dict_for_platform_category(d, for_client, CLIENT_PLATFORMS, only_os)
  175. _update_dict_for_platform_category(d, for_node, NODE_PLATFORMS, only_os)
  176. _update_dict_for_platform_category(d, for_server, SERVER_PLATFORMS, only_os)
  177. _update_dict_for_platform_category(d, for_test, TEST_PLATFORMS, only_os)
  178. _update_dict_for_platform_category(d, for_all, ALL_PLATFORMS, only_os)
  179. return d