diff --git a/Makefile b/Makefile index 392ce028385..8d35c52e445 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ DBG_MAKEFILE ?= ifeq ($(DBG_MAKEFILE),1) - $(warning ***** starting makefile for goal(s) "$(MAKECMDGOALS)") + $(warning ***** starting Makefile for goal(s) "$(MAKECMDGOALS)") $(warning ***** $(shell date)) else # If we're not debugging the Makefile, don't echo recipes. @@ -29,38 +29,25 @@ endif # test: Run tests. # clean: Clean up. -# It's necessary to set this because some docker images don't make sh -> bash. +# It's necessary to set this because some environments don't link sh -> bash. SHELL := /bin/bash # We don't need make's built-in rules. MAKEFLAGS += --no-builtin-rules .SUFFIXES: -# We want make to yell at us if we use undefined variables. -MAKEFLAGS += --warn-undefined-variables - # Constants used throughout. +.EXPORT_ALL_VARIABLES: OUT_DIR ?= _output BIN_DIR := $(OUT_DIR)/bin PRJ_SRC_PATH := k8s.io/kubernetes +GENERATED_FILE_PREFIX := zz_generated. # Metadata for driving the build lives here. META_DIR := .make -# -# Define variables that we use as inputs so we can warn about undefined variables. -# - -WHAT ?= -TESTS ?= - -GOFLAGS ?= -KUBE_GOFLAGS = $(GOFLAGS) -export KUBE_GOFLAGS GOFLAGS - -GOLDFLAGS ?= -KUBE_GOLDFLAGS = $(GOLDFLAGS) -export KUBE_GOLDFLAGS GOLDFLAGS +KUBE_GOFLAGS := $(GOFLAGS) +KUBE_GOLDFLAGS := $(GOLDFLAGS) GOGCFLAGS ?= KUBE_GOGCFLAGS = $(GOGCFLAGS) @@ -99,7 +86,7 @@ ginkgo: # Runs all the presubmission verifications. # # Args: -# BRANCH: Branch to be passed to hack/verify-godeps.sh script. +# BRANCH: Branch to be passed to verify-godeps.sh script. # # Example: # make verify @@ -184,7 +171,7 @@ test-e2e-node: ginkgo generated_files # # Example: # make test-cmd -test-cmd: +test-cmd: generated_files @hack/make-rules/test-cmd.sh .PHONY: test-cmd @@ -208,6 +195,14 @@ clean: clean_meta clean_meta: rm -rf $(META_DIR) +# Remove all auto-generated artifacts. +# +# Example: +# make clean_generated +.PHONY: clean_generated +clean_generated: + find . -type f -name $(GENERATED_FILE_PREFIX)\* | xargs rm -f + # Run 'go vet'. # # Args: @@ -227,7 +222,7 @@ vet: # Example: # make release .PHONY: release -release: generated_files +release: build/release.sh # Build a release, but skip tests @@ -235,7 +230,7 @@ release: generated_files # Example: # make release-skip-tests .PHONY: release-skip-tests quick-release -release-skip-tests quick-release: generated_files +release-skip-tests quick-release: KUBE_RELEASE_RUN_TESTS=n KUBE_FASTBUILD=true build/release.sh # Cross-compile for all platforms @@ -254,5 +249,10 @@ cross: $(notdir $(abspath $(wildcard cmd/*/))): generated_files hack/make-rules/build.sh cmd/$@ -# Include logic for generated files. -include Makefile.generated_files +# Produce auto-generated files needed for the build. +# +# Example: +# make generated_files +.PHONY: generated_files +generated_files: + $(MAKE) -f Makefile.$@ $@ diff --git a/Makefile.generated_files b/Makefile.generated_files index 1e4a83c9137..fe21e394ff1 100644 --- a/Makefile.generated_files +++ b/Makefile.generated_files @@ -12,8 +12,24 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Constants used throughout. -GENERATED_FILE_PREFIX := zz_generated. +# Don't allow an implicit 'all' rule. This is not a user-facing file. +ifeq ($(MAKECMDGOALS),) + $(error This Makefile requires an explicit rule to be specified) +endif + +ifeq ($(DBG_MAKEFILE),1) + $(warning ***** starting Makefile.generated_files for goal(s) "$(MAKECMDGOALS)") + $(warning ***** $(shell date)) +endif + + +# It's necessary to set this because some environments don't link sh -> bash. +SHELL := /bin/bash + +# This rule collects all the generated file sets into a single rule. Other +# rules should depend on this to ensure generated files are rebuilt. +.PHONY: generated_files +generated_files: gen_deepcopy gen_conversion # Code-generation logic. # @@ -92,24 +108,11 @@ GENERATED_FILE_PREFIX := zz_generated. ifeq ($(DBG_MAKEFILE),1) $(warning ***** finding all *.go dirs) endif -ALL_GO_DIRS := $(shell \ - find . \ - -not \( \ - \( \ - -path ./vendor -o \ - -path ./_\* -o \ - -path ./.\* -o \ - -path ./docs -o \ - -path ./examples \ - \) -prune \ - \) \ - -type f -name \*.go \ - | sed 's|^./||' \ - | xargs -n1 dirname \ - | sort -u \ +ALL_GO_DIRS := $(shell \ + hack/make-rules/helpers/cache_go_dirs.sh $(META_DIR)/all_go_dirs.mk \ ) -# The name of the make metadata file listing Go files. +# The name of the metadata file which lists *.go files in each pkg. GOFILES_META := gofiles.mk # Establish a dependency between the deps file and the dir. Whenever a dir @@ -139,12 +142,18 @@ $(foreach dir, $(ALL_GO_DIRS), $(eval \ # We regenerate the output file in order to satisfy make's "newer than" rules, # but we only need to rebuild targets if the contents actually changed. That # is what the .stamp file represents. -$(foreach dir, $(ALL_GO_DIRS), $(META_DIR)/$(dir)/$(GOFILES_META)): +$(foreach dir, $(ALL_GO_DIRS), \ + $(META_DIR)/$(dir)/$(GOFILES_META)): FILES=$$(ls $$@.tmp; \ cmp -s $@.tmp $@ || touch $@.stamp; \ mv $@.tmp $@ +# This is required to fill in the DAG, since some cases (e.g. 'make clean all') +# will reference the .stamp file when it doesn't exist. We don't need to +# rebuild it in that case, just keep make happy. +$(foreach dir, $(ALL_GO_DIRS), \ + $(META_DIR)/$(dir)/$(GOFILES_META).stamp): # Include any deps files as additional Makefile rules. This triggers make to # consider the deps files for rebuild, which makes the whole @@ -219,7 +228,7 @@ gen_deepcopy: $(DEEPCOPY_FILES) # has changed. This allows us to detect deleted input files. $(foreach dir, $(DEEPCOPY_DIRS), $(eval \ $(dir)/$(DEEPCOPY_FILENAME): $(META_DIR)/$(dir)/$(GOFILES_META).stamp \ - $(gofiles__$(dir)) \ + $(gofiles__$(dir)) \ )) # Unilaterally remove any leftovers from previous runs. @@ -228,6 +237,7 @@ $(shell rm -f $(META_DIR)/$(DEEPCOPY_GEN)*.todo) # How to regenerate deep-copy code. This is a little slow to run, so we batch # it up and trigger the batch from the 'generated_files' target. $(DEEPCOPY_FILES): $(DEEPCOPY_GEN) + mkdir -p $$(dirname $(META_DIR)/$(DEEPCOPY_GEN)) echo $(PRJ_SRC_PATH)/$(@D) >> $(META_DIR)/$(DEEPCOPY_GEN).todo # This calculates the dependencies for the generator tool, so we only rebuild @@ -291,7 +301,7 @@ CONVERSION_FILENAME := $(CONVERSION_BASENAME).go # The tool used to generate conversions. CONVERSION_GEN := $(BIN_DIR)/conversion-gen -# The name of the make metadata file controlling conversions. +# The name of the metadata file listing conversion peers for each pkg. CONVERSIONS_META := conversions.mk # All directories that request any form of conversion generation. @@ -341,8 +351,9 @@ $(foreach dir, $(CONVERSION_DIRS), $(eval \ # We regenerate the output file in order to satisfy make's "newer than" rules, # but we only need to rebuild targets if the contents actually changed. That # is what the .stamp file represents. -$(foreach dir, $(CONVERSION_DIRS), $(META_DIR)/$(dir)/$(CONVERSIONS_META)): - TAGS=$$(grep --color=never -h '^// *+k8s:conversion-gen=' $> $(META_DIR)/$(CONVERSION_GEN).todo # This calculates the dependencies for the generator tool, so we only rebuild @@ -446,17 +458,3 @@ sinclude $(META_DIR)/$(CONVERSION_GEN).mk $(CONVERSION_GEN): hack/make-rules/build.sh cmd/libs/go2idl/conversion-gen touch $@ - -# This rule collects all the generated file sets into a single dep, which is -# defined BELOW the *_FILES variables and leaves higher-level rules clean. -# Top-level rules should depend on this to ensure generated files are rebuilt. -.PHONY: generated_files -generated_files: gen_deepcopy gen_conversion - -# Remove all auto-generated artifacts. -# -# Example: -# make clean_generated -.PHONY: clean_generated -clean_generated: - find . -type f -name $(GENERATED_FILE_PREFIX)\* | xargs rm -f diff --git a/hack/make-rules/helpers/cache_go_dirs.sh b/hack/make-rules/helpers/cache_go_dirs.sh new file mode 100755 index 00000000000..133a2d22fa6 --- /dev/null +++ b/hack/make-rules/helpers/cache_go_dirs.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +# Copyright 2014 The Kubernetes Authors. +# +# 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. + +# This script finds, caches, and prints a list of all directories that hold +# *.go files. If any directory is newer than the cache, re-find everything and +# update the cache. Otherwise use the cached file. + +set -o errexit +set -o nounset +set -o pipefail + +if [[ -z "${1:-}" ]]; then + echo "usage: $0 " + exit 1 +fi +CACHE="$1"; shift + +# This is a partial 'find' command. The caller is expected to pass the +# remaining arguments. +# +# Example: +# kfind -type f -name foobar.go +function kfind() { + find . \ + -not \( \ + \( \ + -path ./vendor -o \ + -path ./_\* -o \ + -path ./.\* -o \ + -path ./docs -o \ + -path ./examples \ + \) -prune \ + \) \ + "$@" +} + +NEED_FIND=true +# It's *significantly* faster to check whether any directories are newer than +# the cache than to blindly rebuild it. +if [[ -f "${CACHE}" ]]; then + N=$(kfind -type d -newer "${CACHE}" -print -quit | wc -l) + [[ "${N}" == 0 ]] && NEED_FIND=false +fi +mkdir -p $(dirname "${CACHE}") +if $("${NEED_FIND}"); then + kfind -type f -name \*.go \ + | xargs -n1 dirname \ + | sort -u \ + | sed 's|^./||' \ + > "${CACHE}" +fi +cat "${CACHE}"