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