third_party/linux: build using unhermetic rule
This replaces ad-hoc genrules (for the node Linux image and the ktest
image) with a real Bazel rule with an attached transition which ensures
we end up with the same-ish configurations for all builds of an image.
This reduces rebuilds of the ktest Linux kernel, from three down to one.
Before: https://drive.google.com/file/d/1c6VmY2bqx9Pgs61TOUfgMi8Sn0WQeobu/view
After: https://drive.google.com/file/d/13eO1rLhoBCMMRUKrmJz8QnhdAR3ctIGb/view
We also drive-by fix the Kubernetes CTS test suite to run on a single-node
Cluster (instead of failing early due to that being currently reworked).
Test Plan: Build system refactor, following existing test.
X-Origin-Diff: phab/D761
GitOrigin-RevId: b5545ac5fd402fbf0340d941a90b9ea6ea0b6d43
diff --git a/third_party/linux/BUILD.bazel b/third_party/linux/BUILD.bazel
index 2a52fe3..0d1bad9 100644
--- a/third_party/linux/BUILD.bazel
+++ b/third_party/linux/BUILD.bazel
@@ -1,28 +1,8 @@
-genrule(
- name = "bzImage",
- srcs = [
- "@linux//:all",
- "linux-metropolis.config",
- ],
- outs = [
- "bzImage",
- ],
- cmd = """
- DIR=external/linux
+load("//third_party/linux:def.bzl", "linux_image")
- mkdir $$DIR/.bin
+exports_files(["linux-metropolis.config"])
- cp $(location linux-metropolis.config) $$DIR/.config
-
- (cd $$DIR && make -j $$(nproc) >/dev/null)
-
- cp $$DIR/arch/x86/boot/bzImage $(RULEDIR)
- """,
- visibility = ["//visibility:public"],
-)
-
-filegroup(
- name = "kernel-config",
- srcs = ["linux-metropolis.config"],
+linux_image(
+ name = "linux",
visibility = ["//visibility:public"],
)
diff --git a/third_party/linux/def.bzl b/third_party/linux/def.bzl
new file mode 100644
index 0000000..21282f4
--- /dev/null
+++ b/third_party/linux/def.bzl
@@ -0,0 +1,147 @@
+# Copyright 2020 The Monogon Project Authors.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+Rules for building Linux kernel images.
+
+This currently performs the build in a fully unhermetic manner, using
+make/gcc/... from the host, and is only slightly better than a genrule. This
+should be replaced by a hermetic build that at least uses rules_cc toolchain
+information, or even better, just uses cc_library targets.
+"""
+
+load("//build/utils:detect_root.bzl", "detect_root")
+
+
+def _ignore_unused_configuration_impl(settings, attr):
+ return {
+ # This list should be expanded with any configuration options that end
+ # up reaching this rule with different values across different build
+ # graph paths, but that do not actually influence the kernel build.
+ # Force-setting them to a stable value forces the build configuration
+ # to a stable hash.
+ # See the transition's comment block for more information.
+ "@io_bazel_rules_go//go/config:pure": True,
+ "@io_bazel_rules_go//go/config:static": True,
+ # Note: this toolchain is not actually used to perform the build.
+ "//command_line_option:crosstool_top": "//build/toolchain/musl-host-gcc:musl_host_cc_suite",
+ }
+
+# Transition to flip all known-unimportant but varying configuration options to
+# a known, stable value.
+# This is to prevent Bazel from creating extra configurations for possible
+# combinations of options in case the linux_image rule is pulled through build
+# graph fragments that have different options set.
+#
+# Ideally, Bazel would let us mark in a list that we only care about some set
+# of options (or at least let us mark those that we explicitly don't care
+# about, instead of manually setting them to some value). However, this doesn't
+# seem to be possible, thus this transition is a bit of a hack.
+ignore_unused_configuration = transition(
+ implementation = _ignore_unused_configuration_impl,
+ inputs = [],
+ outputs = [
+ "@io_bazel_rules_go//go/config:pure",
+ "@io_bazel_rules_go//go/config:static",
+ "//command_line_option:crosstool_top",
+ ],
+)
+
+
+def _linux_image_impl(ctx):
+ kernel_config = ctx.file.kernel_config
+ kernel_src = ctx.files.kernel_src
+ image_format = ctx.attr.image_format
+
+ # Tuple containing information about how to build and access the resulting
+ # image.
+ # The first element (target) is the make target to build, the second
+ # (output_source) is the resulting file to be copied and the last
+ # (output_name) is the name of the output that will be generated by this
+ # rule.
+ (target, output_source, output_name) = {
+ 'vmlinux': ('vmlinux', 'vmlinux', 'vmlinux'),
+ 'bzImage': ('all', 'arch/x86/boot/bzImage', 'bzImage'),
+ }[image_format]
+
+ # Root of the given Linux sources.
+ root = detect_root(ctx.attr.kernel_src)
+
+ output = ctx.actions.declare_file(output_name)
+ ctx.actions.run_shell(
+ outputs = [ output ],
+ inputs = [ kernel_config ] + kernel_src,
+ command = '''
+ kconfig=$1
+ target=$2
+ output_source=$3
+ output=$4
+ root=$5
+
+ mkdir ${root}/.bin
+ cp ${kconfig} ${root}/.config
+ (cd ${root} && make -j $(nproc) ${target} >/dev/null)
+ cp ${root}/${output_source} ${output}
+ ''',
+ arguments = [
+ kernel_config.path,
+ target,
+ output_source,
+ output.path,
+ root,
+ ],
+ use_default_shell_env = True,
+ )
+
+ files = depset([output])
+ runfiles = ctx.runfiles(files=[output])
+ return [DefaultInfo(files=files, runfiles=runfiles)]
+
+
+linux_image = rule(
+ doc = '''
+ Build Linux kernel image unhermetically in a given format.
+ ''',
+ implementation = _linux_image_impl,
+ cfg = ignore_unused_configuration,
+ attrs = {
+ "kernel_config": attr.label(
+ doc = '''
+ Linux kernel configuration file to build this kernel image with.
+ ''',
+ allow_single_file = True,
+ default = ":linux-metropolis.config",
+ ),
+ "kernel_src": attr.label(
+ doc = '''
+ Filegroup containing Linux kernel sources.
+ ''',
+ default = "@linux//:all",
+ ),
+ "image_format": attr.string(
+ doc = '''
+ Format of generated Linux image, one of 'vmlinux' or 'bzImage',
+ ''',
+ values = [
+ 'vmlinux', 'bzImage',
+ ],
+ default = 'bzImage',
+ ),
+ "_allowlist_function_transition": attr.label(
+ default = "@bazel_tools//tools/allowlists/function_transition_allowlist"
+ ),
+ },
+)