summaryrefslogtreecommitdiffhomepage
path: root/tools/bazel.mk
diff options
context:
space:
mode:
Diffstat (limited to 'tools/bazel.mk')
-rw-r--r--tools/bazel.mk263
1 files changed, 139 insertions, 124 deletions
diff --git a/tools/bazel.mk b/tools/bazel.mk
index 3a7de427f..2b20457e9 100644
--- a/tools/bazel.mk
+++ b/tools/bazel.mk
@@ -14,49 +14,77 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Make hacks.
-EMPTY :=
-SPACE := $(EMPTY) $(EMPTY)
+##
+## Docker options.
+##
+## This file supports targets that wrap bazel in a running Docker
+## container to simplify development. Some options are available to
+## control the behavior of this container:
+##
+## USER - The in-container user.
+## DOCKER_RUN_OPTIONS - Options for the container (default: --privileged, required for tests).
+## DOCKER_NAME - The container name (default: gvisor-bazel-HASH).
+## DOCKER_PRIVILEGED - Docker privileged flags (default: --privileged).
+## BAZEL_CACHE - The bazel cache directory (default: detected).
+## GCLOUD_CONFIG - The gcloud config directory (detect: detected).
+## DOCKER_SOCKET - The Docker socket (default: detected).
+##
+## To opt out of these wrappers, set DOCKER_BUILD=false.
+DOCKER_BUILD := true
+ifeq ($(DOCKER_BUILD),true)
+-include bazel-server
+endif
# See base Makefile.
-SHELL=/bin/bash -o pipefail
BRANCH_NAME := $(shell (git branch --show-current 2>/dev/null || \
- git rev-parse --abbrev-ref HEAD 2>/dev/null) | \
- xargs -n 1 basename 2>/dev/null)
+ git rev-parse --abbrev-ref HEAD 2>/dev/null) | \
+ xargs -n 1 basename 2>/dev/null)
BUILD_ROOTS := bazel-bin/ bazel-out/
# Bazel container configuration (see below).
USER := $(shell whoami)
HASH := $(shell readlink -m $(CURDIR) | md5sum | cut -c1-8)
-BUILDER_BASE := gvisor.dev/images/default
-BUILDER_IMAGE := gvisor.dev/images/builder
-BUILDER_NAME := gvisor-builder-$(HASH)
-DOCKER_NAME := gvisor-bazel-$(HASH)
+BUILDER_NAME := gvisor-builder-$(HASH)-$(ARCH)
+DOCKER_NAME := gvisor-bazel-$(HASH)-$(ARCH)
DOCKER_PRIVILEGED := --privileged
-BAZEL_CACHE := $(shell readlink -m ~/.cache/bazel/)
-GCLOUD_CONFIG := $(shell readlink -m ~/.config/gcloud/)
+BAZEL_CACHE := $(HOME)/.cache/bazel/
+GCLOUD_CONFIG := $(HOME)/.config/gcloud/
DOCKER_SOCKET := /var/run/docker.sock
-DOCKER_CONFIG := /etc/docker/daemon.json
+DOCKER_CONFIG := /etc/docker
-# Bazel flags.
-BAZEL := bazel $(STARTUP_OPTIONS)
-OPTIONS += --color=no --curses=no
+##
+## Bazel helpers.
+##
+## Bazel will be run with standard flags. You can specify the following flags
+## to control which flags are passed:
+##
+## STARTUP_OPTIONS - Startup options passed to Bazel.
+##
+STARTUP_OPTIONS :=
+BAZEL_OPTIONS :=
+BAZEL := bazel $(STARTUP_OPTIONS)
+BASE_OPTIONS := --color=no --curses=no
+TEST_OPTIONS := $(BASE_OPTIONS) \
+ --test_output=errors \
+ --keep_going \
+ --verbose_failures=true \
+ --build_event_json_file=.build_events.json
# Basic options.
UID := $(shell id -u ${USER})
GID := $(shell id -g ${USER})
USERADD_OPTIONS :=
-FULL_DOCKER_RUN_OPTIONS := $(DOCKER_RUN_OPTIONS)
-FULL_DOCKER_RUN_OPTIONS += --user $(UID):$(GID)
-FULL_DOCKER_RUN_OPTIONS += --entrypoint ""
-FULL_DOCKER_RUN_OPTIONS += --init
-FULL_DOCKER_RUN_OPTIONS += -v "$(BAZEL_CACHE):$(BAZEL_CACHE)"
-FULL_DOCKER_RUN_OPTIONS += -v "$(GCLOUD_CONFIG):$(GCLOUD_CONFIG)"
-FULL_DOCKER_RUN_OPTIONS += -v "/tmp:/tmp"
-FULL_DOCKER_EXEC_OPTIONS := --user $(UID):$(GID)
-FULL_DOCKER_EXEC_OPTIONS += --interactive
-ifeq (true,$(shell [[ -t 0 ]] && echo true))
-FULL_DOCKER_EXEC_OPTIONS += --tty
+DOCKER_RUN_OPTIONS :=
+DOCKER_RUN_OPTIONS += --user $(UID):$(GID)
+DOCKER_RUN_OPTIONS += --entrypoint ""
+DOCKER_RUN_OPTIONS += --init
+DOCKER_RUN_OPTIONS += -v "$(shell readlink -m $(BAZEL_CACHE)):$(BAZEL_CACHE)"
+DOCKER_RUN_OPTIONS += -v "$(shell readlink -m $(GCLOUD_CONFIG)):$(GCLOUD_CONFIG)"
+DOCKER_RUN_OPTIONS += -v "/tmp:/tmp"
+DOCKER_EXEC_OPTIONS := --user $(UID):$(GID)
+DOCKER_EXEC_OPTIONS += --interactive
+ifeq (true,$(shell test -t 0 && echo true))
+DOCKER_EXEC_OPTIONS += --tty
endif
# Add basic UID/GID options.
@@ -72,7 +100,7 @@ endif
# out of disk space.
ifneq ($(UID),0)
USERADD_DOCKER += useradd -l --uid $(UID) --non-unique --no-create-home \
- --gid $(GID) $(USERADD_OPTIONS) -d $(HOME) $(USER) &&
+ --gid $(GID) $(USERADD_OPTIONS) -d $(HOME) $(USER) &&
endif
ifneq ($(GID),0)
GROUPADD_DOCKER += groupadd --gid $(GID) --non-unique $(USER) &&
@@ -80,126 +108,113 @@ endif
# Add docker passthrough options.
ifneq ($(DOCKER_PRIVILEGED),)
-FULL_DOCKER_RUN_OPTIONS += -v "$(DOCKER_SOCKET):$(DOCKER_SOCKET)"
-# TODO(gvisor.dev/issue/1624): Remove docker config volume. This is required
-# temporarily for checking VFS1 vs VFS2 by some tests.
-FULL_DOCKER_RUN_OPTIONS += -v "$(DOCKER_CONFIG):$(DOCKER_CONFIG)"
-FULL_DOCKER_RUN_OPTIONS += $(DOCKER_PRIVILEGED)
-FULL_DOCKER_EXEC_OPTIONS += $(DOCKER_PRIVILEGED)
+DOCKER_RUN_OPTIONS += -v "$(DOCKER_SOCKET):$(DOCKER_SOCKET)"
+DOCKER_RUN_OPTIONS += -v "$(DOCKER_CONFIG):$(DOCKER_CONFIG)"
+DOCKER_RUN_OPTIONS += $(DOCKER_PRIVILEGED)
+DOCKER_EXEC_OPTIONS += $(DOCKER_PRIVILEGED)
DOCKER_GROUP := $(shell stat -c '%g' $(DOCKER_SOCKET))
ifneq ($(GID),$(DOCKER_GROUP))
USERADD_OPTIONS += --groups $(DOCKER_GROUP)
GROUPADD_DOCKER += groupadd --gid $(DOCKER_GROUP) --non-unique docker-$(HASH) &&
-FULL_DOCKER_RUN_OPTIONS += --group-add $(DOCKER_GROUP)
+DOCKER_RUN_OPTIONS += --group-add $(DOCKER_GROUP)
endif
endif
# Add KVM passthrough options.
ifneq (,$(wildcard /dev/kvm))
-FULL_DOCKER_RUN_OPTIONS += --device=/dev/kvm
+DOCKER_RUN_OPTIONS += --device=/dev/kvm
KVM_GROUP := $(shell stat -c '%g' /dev/kvm)
ifneq ($(GID),$(KVM_GROUP))
USERADD_OPTIONS += --groups $(KVM_GROUP)
GROUPADD_DOCKER += groupadd --gid $(KVM_GROUP) --non-unique kvm-$(HASH) &&
-FULL_DOCKER_RUN_OPTIONS += --group-add $(KVM_GROUP)
+DOCKER_RUN_OPTIONS += --group-add $(KVM_GROUP)
endif
endif
-# Load the appropriate config.
-ifneq (,$(BAZEL_CONFIG))
-OPTIONS += --config=$(BAZEL_CONFIG)
+# Top-level functions.
+#
+# This command runs a bazel server, and the container sticks around
+# until the bazel server exits. This should ensure that it does not
+# exit in the middle of running a build, but also it won't stick around
+# forever. The build commands wrap around an appropriate exec into the
+# container in order to perform work via the bazel client.
+ifeq ($(DOCKER_BUILD),true)
+wrapper = docker exec $(DOCKER_EXEC_OPTIONS) $(DOCKER_NAME) $(1)
+else
+wrapper = $(1)
endif
-bazel-image: load-default
- @if docker ps --all | grep $(BUILDER_NAME); then docker rm -f $(BUILDER_NAME); fi
- docker run --user 0:0 --entrypoint "" --name $(BUILDER_NAME) \
- $(BUILDER_BASE) \
- sh -c "$(GROUPADD_DOCKER) \
- $(USERADD_DOCKER) \
- if [[ -e /dev/kvm ]]; then chmod a+rw /dev/kvm; fi"
- docker commit $(BUILDER_NAME) $(BUILDER_IMAGE)
- @docker rm -f $(BUILDER_NAME)
-.PHONY: bazel-image
-
-##
-## Bazel helpers.
-##
-## This file supports targets that wrap bazel in a running Docker
-## container to simplify development. Some options are available to
-## control the behavior of this container:
-## USER - The in-container user.
-## DOCKER_RUN_OPTIONS - Options for the container (default: --privileged, required for tests).
-## DOCKER_NAME - The container name (default: gvisor-bazel-HASH).
-## BAZEL_CACHE - The bazel cache directory (default: detected).
-## GCLOUD_CONFIG - The gcloud config directory (detect: detected).
-## DOCKER_SOCKET - The Docker socket (default: detected).
-##
-bazel-server-start: bazel-image ## Starts the bazel server.
- @mkdir -p $(BAZEL_CACHE)
- @mkdir -p $(GCLOUD_CONFIG)
- @if docker ps --all | grep $(DOCKER_NAME); then docker rm -f $(DOCKER_NAME); fi
- # This command runs a bazel server, and the container sticks around
- # until the bazel server exits. This should ensure that it does not
- # exit in the middle of running a build, but also it won't stick around
- # forever. The build commands wrap around an appropriate exec into the
- # container in order to perform work via the bazel client.
- docker run -d --rm --name $(DOCKER_NAME) \
- -v "$(CURDIR):$(CURDIR)" \
- --workdir "$(CURDIR)" \
- $(FULL_DOCKER_RUN_OPTIONS) \
- $(BUILDER_IMAGE) \
- sh -c "tail -f --pid=\$$($(BAZEL) info server_pid) /dev/null"
-.PHONY: bazel-server-start
-
bazel-shutdown: ## Shuts down a running bazel server.
- @docker exec $(FULL_DOCKER_EXEC_OPTIONS) $(DOCKER_NAME) $(BAZEL) shutdown; \
- rc=$$?; docker kill $(DOCKER_NAME) || [[ $$rc -ne 0 ]]
+ @$(call wrapper,$(BAZEL) shutdown)
.PHONY: bazel-shutdown
bazel-alias: ## Emits an alias that can be used within the shell.
- @echo "alias bazel='docker exec $(FULL_DOCKER_EXEC_OPTIONS) $(DOCKER_NAME) bazel'"
+ @echo "alias bazel='$(call wrapper,$(BAZEL))'"
.PHONY: bazel-alias
-bazel-server: ## Ensures that the server exists. Used as an internal target.
- @docker exec $(FULL_DOCKER_EXEC_OPTIONS) $(DOCKER_NAME) true || $(MAKE) bazel-server-start
-.PHONY: bazel-server
+bazel-image: load-default ## Ensures that the local builder exists.
+ @$(call header,DOCKER BUILD)
+ @docker rm -f $(BUILDER_NAME) 2>/dev/null || true
+ @docker run --user 0:0 --entrypoint "" --name $(BUILDER_NAME) gvisor.dev/images/default \
+ bash -c "$(GROUPADD_DOCKER) $(USERADD_DOCKER) if test -e /dev/kvm; then chmod a+rw /dev/kvm; fi" >&2
+ @docker commit $(BUILDER_NAME) gvisor.dev/images/builder >&2
+.PHONY: bazel-image
-build_cmd = docker exec $(FULL_DOCKER_EXEC_OPTIONS) $(DOCKER_NAME) sh -o pipefail -c '$(BAZEL) build $(OPTIONS) "$(TARGETS)"'
-
-build_paths = $(build_cmd) 2>&1 \
- | tee /proc/self/fd/2 \
- | grep -A1 -E '^Target' \
- | grep -E '^ ($(subst $(SPACE),|,$(BUILD_ROOTS)))' \
- | sed "s/ /\n/g" \
- | strings -n 10 \
- | awk '{$$1=$$1};1' \
- | xargs -n 1 -I {} readlink -f "{}" \
- | xargs -n 1 -I {} sh -c "$(1)"
-
-build: bazel-server
- @$(call build_cmd)
-.PHONY: build
-
-copy: bazel-server
-ifeq (,$(DESTINATION))
- $(error Destination not provided.)
+# Note: when starting the bazel server, we tie the life of the container to the
+# bazel server's life, so that the container disappears naturally.
+ifneq (true,$(shell $(wrapper echo true)))
+bazel-server: bazel-image ## Ensures that the server exists.
+ @$(call header,DOCKER RUN)
+ @docker rm -f $(DOCKER_NAME) 2>/dev/null || true
+ @mkdir -p $(GCLOUD_CONFIG)
+ @mkdir -p $(BAZEL_CACHE)
+ @docker run -d --rm --name $(DOCKER_NAME) \
+ -v "$(CURDIR):$(CURDIR)" \
+ --workdir "$(CURDIR)" \
+ $(DOCKER_RUN_OPTIONS) \
+ gvisor.dev/images/builder \
+ bash -c "set -x; tail -f --pid=\$$($(BAZEL) info server_pid) /dev/null"
+else
+bazel-server:
+ @
endif
- @$(call build_paths,cp -fa {} $(DESTINATION))
-
-run: bazel-server
- @$(call build_paths,{} $(ARGS))
-.PHONY: run
-
-sudo: bazel-server
- @$(call build_paths,sudo -E {} $(ARGS))
-.PHONY: sudo
-
-test: OPTIONS += --test_output=errors --keep_going --verbose_failures=true
-test: bazel-server
- @docker exec $(FULL_DOCKER_EXEC_OPTIONS) $(DOCKER_NAME) $(BAZEL) test $(OPTIONS) $(TARGETS)
-.PHONY: test
+.PHONY: bazel-server
-query:
- @$(MAKE) bazel-server >&2 # If we need to start, ensure stdout is not polluted.
- @docker exec $(FULL_DOCKER_EXEC_OPTIONS) $(DOCKER_NAME) sh -o pipefail -c '$(BAZEL) query $(OPTIONS) "$(TARGETS)" 2>/dev/null'
-.PHONY: query
+# build_paths extracts the built binary from the bazel stderr output.
+#
+# This could be alternately done by parsing the bazel build event stream, but
+# this is a complex schema, and begs the question: what will build the thing
+# that parses the output? Bazel? Do we need a separate bootstrapping build
+# command here? Yikes, let's just stick with the ugly shell pipeline.
+#
+# The last line is used to prevent terminal shenanigans.
+build_paths = \
+ (set -euo pipefail; \
+ $(call wrapper,$(BAZEL) build $(BASE_OPTIONS) $(BAZEL_OPTIONS) $(1)) 2>&1 \
+ | tee /proc/self/fd/2 \
+ | sed -n -e '/^Target/,$$p' \
+ | sed -n -e '/^ \($(subst /,\/,$(subst $(SPACE),\|,$(BUILD_ROOTS)))\)/p' \
+ | sed -e 's/ /\n/g' \
+ | awk '{$$1=$$1};1' \
+ | strings \
+ | xargs -r -n 1 -I {} readlink -f "{}" \
+ | xargs -r -n 1 -I {} bash -c 'set -xeuo pipefail; $(2)')
+
+clean = $(call header,CLEAN) && $(call wrapper,$(BAZEL) clean)
+build = $(call header,BUILD $(1)) && $(call build_paths,$(1),echo {})
+copy = $(call header,COPY $(1) $(2)) && $(call build_paths,$(1),cp -fa {} $(2))
+run = $(call header,RUN $(1) $(2)) && $(call build_paths,$(1),{} $(2))
+sudo = $(call header,SUDO $(1) $(2)) && $(call build_paths,$(1),sudo -E {} $(2))
+test = $(call header,TEST $(1)) && $(call wrapper,$(BAZEL) test $(TEST_OPTIONS) $(1))
+
+clean: ## Cleans the bazel cache.
+ @$(call clean)
+.PHONY: clean
+
+testlogs: ## Returns the most recent set of test logs.
+ @if test -f .build_events.json; then \
+ cat .build_events.json | jq -r \
+ 'select(.testSummary?.overallStatus? | tostring | test("(FAILED|FLAKY|TIMEOUT)")) | "\(.id.testSummary.label) \(.testSummary.failed[].uri)"' | \
+ sed -e 's|file://||'; \
+ fi
+.PHONY: testlogs