Skip to content

Commit ecf7f7e

Browse files
committed
Transition container image target platform
Transition to the target platform associated with the `architecture` and `operating_system` attributes on container image rules. This change allows for container image rules to build the correct binary for the target platform, regardless of the host platform. Container image rules would require the use of the `target_compatible_with` attribute to prevent mismatching host and target platforms building dependencies incorrectly. Additionally, hosts which did not match the target platform had to explicitly specify the target platform with the `--platforms` command-line option. This change fixes the aforementioned issues and #690. Massive thank you to @joneshf for the initial source. It has been adapted to automatically select the target platform associated with the container image, as opposed to always using `@io_bazel_rules_go//go/toolchain:linux_amd64`.
1 parent 8f6a2aa commit ecf7f7e

File tree

10 files changed

+117
-29
lines changed

10 files changed

+117
-29
lines changed

container/image.bzl

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ def _impl(
324324
executable = True,
325325
outputs = _container.image.outputs,
326326
implementation = _impl,
327+
cfg = _container.image.cfg,
327328
)
328329
329330
Args:
@@ -625,7 +626,7 @@ _attrs = dicts.add(_layer.attrs, {
625626
Acceptable formats: Integer or floating point seconds since Unix Epoch, RFC 3339 date/time.
626627
627628
This field supports stamp variables.
628-
629+
629630
If not set, defaults to {BUILD_TIMESTAMP} when stamp = True, otherwise 0""",
630631
),
631632
"docker_run_flags": attr.string(
@@ -637,14 +638,14 @@ _attrs = dicts.add(_layer.attrs, {
637638
doc = """List of entrypoints to add in the image.
638639
639640
See https://docs.docker.com/engine/reference/builder/#entrypoint
640-
641+
641642
Set `entrypoint` to `None`, `[]` or `""` will set the `Entrypoint` of the image
642643
to be `null`.
643644
644645
The behavior between using `""` and `[]` may differ.
645646
Please see [#1448](https://github.com/bazelbuild/rules_docker/issues/1448)
646647
for more details.
647-
648+
648649
This field supports stamp variables.""",
649650
),
650651
"experimental_tarball_format": attr.string(
@@ -667,12 +668,12 @@ _attrs = dicts.add(_layer.attrs, {
667668
),
668669
"labels": attr.string_dict(
669670
doc = """Dictionary from custom metadata names to their values.
670-
671+
671672
See https://docs.docker.com/engine/reference/builder/#label
672-
673+
673674
You can also put a file name prefixed by '@' as a value.
674675
Then the value is replaced with the contents of the file.
675-
676+
676677
Example:
677678
678679
labels = {
@@ -699,7 +700,7 @@ _attrs = dicts.add(_layer.attrs, {
699700
),
700701
"layers": attr.label_list(
701702
doc = """List of `container_layer` targets.
702-
703+
703704
The data from each `container_layer` will be part of container image,
704705
and the environment variable will be available in the image as well.""",
705706
providers = [LayerInfo],
@@ -731,7 +732,7 @@ _attrs = dicts.add(_layer.attrs, {
731732
# Starlark doesn't support int_list...
732733
"ports": attr.string_list(
733734
doc = """List of ports to expose.
734-
735+
735736
See https://docs.docker.com/engine/reference/builder/#expose""",
736737
),
737738
"repository": attr.string(
@@ -741,7 +742,7 @@ _attrs = dicts.add(_layer.attrs, {
741742
Images generated by `container_image` are tagged by default to
742743
`bazel/package_name:target` for a `container_image` target at
743744
`//package/name:target`.
744-
745+
745746
Setting this attribute to `gcr.io/dummy` would set the default tag to
746747
`gcr.io/dummy/package_name:target`.""",
747748
),
@@ -767,19 +768,22 @@ _attrs = dicts.add(_layer.attrs, {
767768
),
768769
"volumes": attr.string_list(
769770
doc = """List of volumes to mount.
770-
771+
771772
See https://docs.docker.com/engine/reference/builder/#volumes""",
772773
),
773774
"workdir": attr.string(
774775
doc = """Initial working directory when running the Docker image.
775776
776777
See https://docs.docker.com/engine/reference/builder/#workdir
777-
778+
778779
Because building the image never happens inside a Docker container,
779780
this working directory does not affect the other actions (e.g., adding files).
780781
781782
This field supports stamp variables.""",
782783
),
784+
"_allowlist_function_transition": attr.label(
785+
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
786+
),
783787
"_digester": attr.label(
784788
default = "//container/go/cmd/digester",
785789
cfg = "host",
@@ -799,19 +803,40 @@ _outputs["config_digest"] = "%{name}.json.sha256"
799803

800804
_outputs["build_script"] = "%{name}.executable"
801805

806+
def _image_transition_impl(settings, attr):
807+
# Architecture aliases.
808+
architecture = {
809+
"386": "x86_32",
810+
"amd64": "x86_64",
811+
"ppc64le": "ppc",
812+
}.get(attr.architecture, attr.architecture)
813+
return dicts.add(settings, {
814+
"//command_line_option:platforms": "//platforms:{}_{}".format(attr.operating_system, architecture),
815+
})
816+
817+
_image_transition = transition(
818+
implementation = _image_transition_impl,
819+
inputs = [],
820+
outputs = [
821+
"//command_line_option:platforms",
822+
],
823+
)
824+
802825
image = struct(
803826
attrs = _attrs,
804827
outputs = _outputs,
805828
implementation = _impl,
829+
cfg = _image_transition,
806830
)
807831

808832
container_image_ = rule(
809-
attrs = _attrs,
833+
attrs = image.attrs,
810834
doc = "Called by the `container_image` macro with **kwargs, see below",
811835
executable = True,
812-
outputs = _outputs,
836+
outputs = image.outputs,
813837
toolchains = ["@io_bazel_rules_docker//toolchains/docker:toolchain_type"],
814-
implementation = _impl,
838+
implementation = image.implementation,
839+
cfg = image.cfg,
815840
)
816841

817842
# This validates the two forms of value accepted by

container/layer.bzl

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ _layer_attrs = dicts.add({
294294
"compression_options": attr.string_list(),
295295
"data_path": attr.string(
296296
doc = """Root path of the files.
297-
297+
298298
The directory structure from the files is preserved inside the
299299
Docker image, but a prefix path determined by `data_path`
300300
is removed from the directory structure. This path can
@@ -307,7 +307,7 @@ _layer_attrs = dicts.add({
307307
"debs": attr.label_list(
308308
allow_files = deb_filetype,
309309
doc = """Debian packages to extract.
310-
310+
311311
Deprecated: A list of debian packages that will be extracted in the Docker image.
312312
Note that this doesn't actually install the packages. Installation needs apt
313313
or apt-get which need to be executed within a running container which
@@ -316,7 +316,7 @@ _layer_attrs = dicts.add({
316316
"directory": attr.string(
317317
default = "/",
318318
doc = """Target directory.
319-
319+
320320
The directory in which to expand the specified files, defaulting to '/'.
321321
Only makes sense accompanying one of files/tars/debs.""",
322322
),
@@ -326,16 +326,16 @@ _layer_attrs = dicts.add({
326326
"enable_mtime_preservation": attr.bool(default = False),
327327
"env": attr.string_dict(
328328
doc = """Dictionary from environment variable names to their values when running the Docker image.
329-
329+
330330
See https://docs.docker.com/engine/reference/builder/#env
331331
332332
For example,
333333
334334
env = {
335335
"FOO": "bar",
336336
...
337-
},
338-
337+
},
338+
339339
The values of this field support make variables (e.g., `$(FOO)`)
340340
and stamp variables; keys support make variables as well.""",
341341
),
@@ -357,9 +357,9 @@ _layer_attrs = dicts.add({
357357
"portable_mtime": attr.bool(default = False),
358358
"symlinks": attr.string_dict(
359359
doc = """Symlinks to create in the Docker image.
360-
360+
361361
For example,
362-
362+
363363
symlinks = {
364364
"/path/to/link": "/path/to/target",
365365
...
@@ -369,7 +369,7 @@ _layer_attrs = dicts.add({
369369
"tars": attr.label_list(
370370
allow_files = tar_filetype,
371371
doc = """Tar file to extract in the layer.
372-
372+
373373
A list of tar files whose content should be in the Docker image.""",
374374
),
375375
}, _hash_tools, _layer_tools, _zip_tools)
@@ -387,10 +387,10 @@ layer = struct(
387387

388388
container_layer_ = rule(
389389
doc = _DOC,
390-
attrs = _layer_attrs,
390+
attrs = layer.attrs,
391391
executable = False,
392-
outputs = _layer_outputs,
393-
implementation = _impl,
392+
outputs = layer.outputs,
393+
implementation = layer.implementation,
394394
toolchains = ["@io_bazel_rules_docker//toolchains/docker:toolchain_type"],
395395
)
396396

contrib/repro_test.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,4 +328,5 @@ container_repro_test = rule(
328328
}),
329329
test = True,
330330
toolchains = ["@io_bazel_rules_docker//toolchains/docker:toolchain_type"],
331+
cfg = _container.image.cfg,
331332
)

docker/package_managers/apt_key.bzl

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,12 +155,14 @@ key = struct(
155155
attrs = _attrs,
156156
outputs = _outputs,
157157
implementation = _impl,
158+
cfg = _container.image.cfg,
158159
)
159160

160161
add_apt_key = rule(
161-
attrs = _attrs,
162-
outputs = _outputs,
163-
implementation = _impl,
162+
attrs = key.attrs,
163+
outputs = key.outputs,
164+
implementation = key.implementation,
164165
toolchains = ["@io_bazel_rules_docker//toolchains/docker:toolchain_type"],
165166
executable = True,
167+
cfg = key.cfg,
166168
)

docker/toolchain_container/toolchain_container.bzl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ language_tool_layer_ = rule(
243243
outputs = _container.image.outputs,
244244
toolchains = ["@io_bazel_rules_docker//toolchains/docker:toolchain_type"],
245245
implementation = _language_tool_layer_impl,
246+
cfg = _container.image.cfg,
246247
)
247248

248249
def language_tool_layer(**kwargs):
@@ -350,6 +351,7 @@ toolchain_container_ = rule(
350351
outputs = _container.image.outputs,
351352
toolchains = ["@io_bazel_rules_docker//toolchains/docker:toolchain_type"],
352353
implementation = _toolchain_container_impl,
354+
cfg = _container.image.cfg,
353355
)
354356

355357
def toolchain_container(**kwargs):

docs/container.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ You can write a customized container_image rule by writing something like:
414414
executable = True,
415415
outputs = _container.image.outputs,
416416
implementation = _impl,
417+
cfg = _container.image.cfg,
417418
)
418419

419420

java/image.bzl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ jar_dep_layer = rule(
163163
outputs = lang_image.outputs,
164164
toolchains = lang_image.toolchains,
165165
implementation = _jar_dep_layer_impl,
166+
cfg = lang_image.cfg,
166167
)
167168

168169
def _jar_app_layer_impl(ctx):
@@ -255,6 +256,7 @@ jar_app_layer = rule(
255256
outputs = _container.image.outputs,
256257
toolchains = ["@io_bazel_rules_docker//toolchains/docker:toolchain_type"],
257258
implementation = _jar_app_layer_impl,
259+
cfg = _container.image.cfg,
258260
)
259261

260262
def java_image(
@@ -362,6 +364,7 @@ _war_dep_layer = rule(
362364
outputs = _container.image.outputs,
363365
toolchains = ["@io_bazel_rules_docker//toolchains/docker:toolchain_type"],
364366
implementation = _war_dep_layer_impl,
367+
cfg = _container.image.cfg,
365368
)
366369

367370
def _war_app_layer_impl(ctx):
@@ -400,6 +403,7 @@ _war_app_layer = rule(
400403
outputs = _container.image.outputs,
401404
toolchains = ["@io_bazel_rules_docker//toolchains/docker:toolchain_type"],
402405
implementation = _war_app_layer_impl,
406+
cfg = _container.image.cfg,
403407
)
404408

405409
def war_image(name, base = None, deps = [], layers = [], **kwargs):

lang/image.bzl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ image = struct(
272272
outputs = _container.image.outputs,
273273
toolchains = ["@io_bazel_rules_docker//toolchains/docker:toolchain_type"],
274274
implementation = _app_layer_impl,
275+
cfg = _container.image.cfg,
275276
)
276277

277278
_app_layer = rule(
@@ -280,6 +281,7 @@ _app_layer = rule(
280281
outputs = image.outputs,
281282
toolchains = image.toolchains,
282283
implementation = image.implementation,
284+
cfg = image.cfg,
283285
)
284286

285287
# Convenience function that instantiates the _app_layer rule and returns

nodejs/image.bzl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ _dep_layer = rule(
8686
outputs = lang_image.outputs,
8787
toolchains = lang_image.toolchains,
8888
implementation = _dep_layer_impl,
89+
cfg = lang_image.cfg,
8990
)
9091

9192
def _npm_deps_runfiles(dep):
@@ -107,6 +108,7 @@ _npm_deps_layer = rule(
107108
outputs = lang_image.outputs,
108109
toolchains = lang_image.toolchains,
109110
implementation = _npm_deps_layer_impl,
111+
cfg = lang_image.cfg,
110112
)
111113

112114
def nodejs_image(

platforms/BUILD

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,52 @@ platform(
5656
],
5757
parents = ["@buildkite_config//config:platform"],
5858
)
59+
60+
# All OSs known to Bazel.
61+
#
62+
# curl -Lfs https://raw.githubusercontent.com/bazelbuild/platforms/main/os/BUILD | grep -Eo 'name = "\w+"' | grep -Eo '"\w+"' | grep -Ev 'srcs|os|none' | tr -d '"' | sort -u -f | xargs -I '{}' echo '"@platforms//os:{}",'
63+
_OS_CONSTRAINTS = (
64+
"@platforms//os:android",
65+
"@platforms//os:freebsd",
66+
"@platforms//os:linux",
67+
"@platforms//os:netbsd",
68+
"@platforms//os:openbsd",
69+
"@platforms//os:qnx",
70+
"@platforms//os:wasi",
71+
"@platforms//os:windows",
72+
)
73+
74+
# All CPUs known to Bazel.
75+
#
76+
# curl -Lfs https://raw.githubusercontent.com/bazelbuild/platforms/main/cpu/BUILD | grep -Eo 'name = "\w+"' | grep -Eo '"\w+"' | grep -Ev 'cpu|srcs' | tr -d '"' | sort -u -f | xargs -I '{}' echo '"@platforms//cpu:{}",'
77+
_CPU_CONSTRAINTS = (
78+
"@platforms//cpu:aarch64",
79+
"@platforms//cpu:arm",
80+
"@platforms//cpu:arm64",
81+
"@platforms//cpu:arm64e",
82+
"@platforms//cpu:arm64_32",
83+
"@platforms//cpu:armv7",
84+
"@platforms//cpu:armv7k",
85+
"@platforms//cpu:i386",
86+
"@platforms//cpu:mips64",
87+
"@platforms//cpu:ppc",
88+
"@platforms//cpu:riscv32",
89+
"@platforms//cpu:riscv64",
90+
"@platforms//cpu:s390x",
91+
"@platforms//cpu:wasm32",
92+
"@platforms//cpu:wasm64",
93+
"@platforms//cpu:x86_32",
94+
"@platforms//cpu:x86_64",
95+
)
96+
97+
# Register all known Bazel platform combinations for use with transitions.
98+
[platform(
99+
name = "{}_{}".format(
100+
os.rsplit(":", 1)[1],
101+
cpu.rsplit(":", 1)[1],
102+
),
103+
constraint_values = [
104+
os,
105+
cpu,
106+
],
107+
) for os in _OS_CONSTRAINTS for cpu in _CPU_CONSTRAINTS]

0 commit comments

Comments
 (0)