github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/tools/bazel.mk (about) 1 #!/usr/bin/make -f 2 3 # Copyright 2018 The gVisor Authors. 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 ## 18 ## Docker options. 19 ## 20 ## This file supports targets that wrap bazel in a running Docker 21 ## container to simplify development. Some options are available to 22 ## control the behavior of this container: 23 ## 24 ## USER - The in-container user. 25 ## DOCKER_RUN_OPTIONS - Options for the container (default: --privileged, required for tests). 26 ## DOCKER_NAME - The container name (default: gvisor-bazel-HASH). 27 ## DOCKER_PRIVILEGED - Docker privileged flags (default: --privileged). 28 ## BAZEL_CACHE - The bazel cache directory (default: detected). 29 ## GCLOUD_CONFIG - The gcloud config directory (detect: detected). 30 ## DOCKER_SOCKET - The Docker socket (default: detected). 31 ## 32 ## To opt out of these wrappers, set DOCKER_BUILD=false. 33 DOCKER_BUILD := true 34 ifeq ($(DOCKER_BUILD),true) 35 -include bazel-server 36 endif 37 38 # See base Makefile. 39 BRANCH_NAME := $(shell (git branch --show-current 2>/dev/null || \ 40 git rev-parse --abbrev-ref HEAD 2>/dev/null) | \ 41 xargs -n 1 basename 2>/dev/null) 42 BUILD_ROOTS := bazel-bin/ bazel-out/ 43 44 # Bazel container configuration (see below). 45 USER := $(shell whoami) 46 HASH := $(shell readlink -m $(CURDIR) | md5sum | cut -c1-8) 47 BUILDER_NAME := gvisor-builder-$(HASH)-$(ARCH) 48 DOCKER_NAME := gvisor-bazel-$(HASH)-$(ARCH) 49 DOCKER_PRIVILEGED := --privileged 50 BAZEL_CACHE := $(HOME)/.cache/bazel/ 51 GCLOUD_CONFIG := $(HOME)/.config/gcloud/ 52 DOCKER_SOCKET := /var/run/docker.sock 53 DOCKER_CONFIG := /etc/docker 54 55 ## 56 ## Bazel helpers. 57 ## 58 ## Bazel will be run with standard flags. You can specify the following flags 59 ## to control which flags are passed: 60 ## 61 ## STARTUP_OPTIONS - Startup options passed to Bazel. 62 ## 63 STARTUP_OPTIONS := 64 BAZEL_OPTIONS := 65 BAZEL := bazel $(STARTUP_OPTIONS) 66 BASE_OPTIONS := --color=no --curses=no 67 TEST_OPTIONS := $(BASE_OPTIONS) \ 68 --test_output=errors \ 69 --keep_going \ 70 --verbose_failures=true \ 71 --build_event_json_file=.build_events.json 72 73 # Basic options. 74 UID := $(shell id -u ${USER}) 75 GID := $(shell id -g ${USER}) 76 USERADD_OPTIONS := 77 DOCKER_RUN_OPTIONS := 78 DOCKER_RUN_OPTIONS += --rm 79 DOCKER_RUN_OPTIONS += --user $(UID):$(GID) 80 DOCKER_RUN_OPTIONS += --entrypoint "" 81 DOCKER_RUN_OPTIONS += --init 82 DOCKER_RUN_OPTIONS += -v "$(shell readlink -m $(BAZEL_CACHE)):$(BAZEL_CACHE)" 83 DOCKER_RUN_OPTIONS += -v "$(shell readlink -m $(GCLOUD_CONFIG)):$(GCLOUD_CONFIG)" 84 DOCKER_RUN_OPTIONS += -v "/tmp:/tmp" 85 DOCKER_EXEC_OPTIONS := --user $(UID):$(GID) 86 DOCKER_EXEC_OPTIONS += --interactive 87 ifeq (true,$(shell test -t 0 && echo true)) 88 DOCKER_EXEC_OPTIONS += --tty 89 endif 90 91 # Add basic UID/GID options. 92 # 93 # Note that USERADD_DOCKER and GROUPADD_DOCKER are both defined as "deferred" 94 # variables in Make terminology, that is they will be expanded at time of use 95 # and may include other variables, including those defined below. 96 # 97 # NOTE: we pass -l to useradd below because otherwise you can hit a bug 98 # best described here: 99 # https://github.com/moby/moby/issues/5419#issuecomment-193876183 100 # TLDR; trying to add to /var/log/lastlog (sparse file) runs the machine out 101 # out of disk space. 102 ifneq ($(UID),0) 103 USERADD_DOCKER += useradd -l --uid $(UID) --non-unique --no-create-home \ 104 --gid $(GID) $(USERADD_OPTIONS) -d $(HOME) $(USER) && 105 endif 106 ifneq ($(GID),0) 107 GROUPADD_DOCKER += groupadd --gid $(GID) --non-unique $(USER) && 108 endif 109 110 # Add docker passthrough options. 111 ifneq ($(DOCKER_PRIVILEGED),) 112 DOCKER_RUN_OPTIONS += -v "$(DOCKER_SOCKET):$(DOCKER_SOCKET)" 113 DOCKER_RUN_OPTIONS += -v "$(DOCKER_CONFIG):$(DOCKER_CONFIG)" 114 DOCKER_RUN_OPTIONS += $(DOCKER_PRIVILEGED) 115 DOCKER_EXEC_OPTIONS += $(DOCKER_PRIVILEGED) 116 DOCKER_GROUP := $(shell stat -c '%g' $(DOCKER_SOCKET)) 117 ifneq ($(GID),$(DOCKER_GROUP)) 118 USERADD_OPTIONS += --groups $(DOCKER_GROUP) 119 GROUPADD_DOCKER += groupadd --gid $(DOCKER_GROUP) --non-unique docker-$(HASH) && 120 DOCKER_RUN_OPTIONS += --group-add $(DOCKER_GROUP) 121 endif 122 endif 123 124 # Add KVM passthrough options. 125 ifneq (,$(wildcard /dev/kvm)) 126 DOCKER_RUN_OPTIONS += --device=/dev/kvm 127 KVM_GROUP := $(shell stat -c '%g' /dev/kvm) 128 ifneq ($(GID),$(KVM_GROUP)) 129 USERADD_OPTIONS += --groups $(KVM_GROUP) 130 GROUPADD_DOCKER += groupadd --gid $(KVM_GROUP) --non-unique kvm-$(HASH) && 131 DOCKER_RUN_OPTIONS += --group-add $(KVM_GROUP) 132 endif 133 endif 134 135 # Top-level functions. 136 # 137 # This command runs a bazel server, and the container sticks around 138 # until the bazel server exits. This should ensure that it does not 139 # exit in the middle of running a build, but also it won't stick around 140 # forever. The build commands wrap around an appropriate exec into the 141 # container in order to perform work via the bazel client. 142 ifeq ($(DOCKER_BUILD),true) 143 wrapper = docker exec $(DOCKER_EXEC_OPTIONS) $(DOCKER_NAME) $(1) 144 else 145 wrapper = $(1) 146 endif 147 148 bazel-shutdown: ## Shuts down a running bazel server. 149 @$(call wrapper,$(BAZEL) shutdown) 150 .PHONY: bazel-shutdown 151 152 bazel-alias: ## Emits an alias that can be used within the shell. 153 @echo "alias bazel='$(call wrapper,$(BAZEL))'" 154 .PHONY: bazel-alias 155 156 bazel-image: load-default ## Ensures that the local builder exists. 157 @$(call header,DOCKER BUILD) 158 @docker rm -f $(BUILDER_NAME) 2>/dev/null || true 159 @docker run --user 0:0 --entrypoint "" --name $(BUILDER_NAME) gvisor.dev/images/default \ 160 bash -c "$(GROUPADD_DOCKER) $(USERADD_DOCKER) if test -e /dev/kvm; then chmod a+rw /dev/kvm; fi" >&2 161 @docker commit $(BUILDER_NAME) gvisor.dev/images/builder >&2 162 .PHONY: bazel-image 163 164 ifneq (true,$(shell $(wrapper echo true))) 165 bazel-server: bazel-image ## Ensures that the server exists. 166 @$(call header,DOCKER RUN) 167 @docker rm -f $(DOCKER_NAME) 2>/dev/null || true 168 @mkdir -p $(BAZEL_CACHE) 169 @mkdir -p $(GCLOUD_CONFIG) 170 @docker run -d --name $(DOCKER_NAME) \ 171 -v "$(CURDIR):$(CURDIR)" \ 172 --workdir "$(CURDIR)" \ 173 $(DOCKER_RUN_OPTIONS) \ 174 gvisor.dev/images/builder \ 175 bash -c "set -x; tail -f --pid=\$$($(BAZEL) info server_pid) /dev/null" 176 else 177 bazel-server: 178 @ 179 endif 180 .PHONY: bazel-server 181 182 # build_paths extracts the built binary from the bazel stderr output. 183 # 184 # This could be alternately done by parsing the bazel build event stream, but 185 # this is a complex schema, and begs the question: what will build the thing 186 # that parses the output? Bazel? Do we need a separate bootstrapping build 187 # command here? Yikes, let's just stick with the ugly shell pipeline. 188 # 189 # The last line is used to prevent terminal shenanigans. 190 build_paths = \ 191 (set -euo pipefail; \ 192 $(call wrapper,$(BAZEL) build $(BASE_OPTIONS) $(BAZEL_OPTIONS) $(1)) 2>&1 \ 193 | tee /dev/fd/2 \ 194 | sed -n -e '/^Target/,$$p' \ 195 | sed -n -e '/^ \($(subst /,\/,$(subst $(SPACE),\|,$(BUILD_ROOTS)))\)/p' \ 196 | sed -e 's/ /\n/g' \ 197 | awk '{$$1=$$1};1' \ 198 | strings \ 199 | xargs -r -n 1 -I {} readlink -f "{}" \ 200 | xargs -r -n 1 -I {} bash -c 'set -xeuo pipefail; $(2)') 201 202 clean = $(call header,CLEAN) && $(call wrapper,$(BAZEL) clean) 203 build = $(call header,BUILD $(1)) && $(call build_paths,$(1),echo {}) 204 copy = $(call header,COPY $(1) $(2)) && $(call build_paths,$(1),cp -fa {} $(2)) 205 run = $(call header,RUN $(1) $(2)) && $(call build_paths,$(1),{} $(2)) 206 sudo = $(call header,SUDO $(1) $(2)) && $(call build_paths,$(1),sudo -E {} $(2)) 207 test = $(call header,TEST $(1)) && $(call wrapper,$(BAZEL) test $(TEST_OPTIONS) $(1)) 208 209 clean: ## Cleans the bazel cache. 210 @$(call clean) 211 .PHONY: clean 212 213 testlogs: ## Returns the most recent set of test logs. 214 @if test -f .build_events.json; then \ 215 cat .build_events.json | jq -r \ 216 'select(.testSummary?.overallStatus? | tostring | test("(FAILED|FLAKY|TIMEOUT)")) | "\(.id.testSummary.label) \(.testSummary.failed[].uri)"' | \ 217 sed -e 's|file://||'; \ 218 fi 219 .PHONY: testlogs