Support proper shadowing of target.mk files

The build system overlays multiple source trees (repositories) such that
they can shadow libraries and include search paths. This patch extends
the shadowing concept to build targets. Furthermore, it streamlines the
build stage for generating library depenencies, reducing the processing
time of this stage by 10-20 percent. Fixes #165.
This commit is contained in:
Norman Feske 2012-03-28 18:49:38 +02:00
parent 37bf298b37
commit 75aba75ff8
1 changed files with 71 additions and 48 deletions

View File

@ -90,10 +90,10 @@ export LIBGCC_INC_DIR = $(shell dirname `$(CUSTOM_CXX_LIB) -print-libgcc-file-na
# #
# Find out about the target directories to build # Find out about the target directories to build
# #
DST_DIRS = $(filter-out all clean bin cleanall again run/%,$(MAKECMDGOALS)) DST_DIRS := $(filter-out all clean bin cleanall again run/%,$(MAKECMDGOALS))
ifeq ($(MAKECMDGOALS),) ifeq ($(MAKECMDGOALS),)
DST_DIRS = . DST_DIRS := *
endif endif
# #
@ -102,13 +102,6 @@ endif
all $(DST_DIRS): gen_deps_and_build_targets all $(DST_DIRS): gen_deps_and_build_targets
@true @true
#
# Helper to find targets in repositories
# The sed command is there to replace /./ by /. This happens when DST_DIRS = .
#
find_src_target_mk = $(GNU_FIND) $$i/src/$(@:.visit=) -name target.mk 2>/dev/null | sed "s/\/\.\//\//g"
find_all_src_target_mk = for i in $(REPOSITORIES); do $(find_src_target_mk); done
-include $(call select_from_repositories,etc/specs.conf) -include $(call select_from_repositories,etc/specs.conf)
-include $(BUILD_BASE_DIR)/etc/specs.conf -include $(BUILD_BASE_DIR)/etc/specs.conf
export SPEC_FILES := $(foreach SPEC,$(SPECS),$(call select_from_repositories,mk/spec-$(SPEC).mk)) export SPEC_FILES := $(foreach SPEC,$(SPECS),$(call select_from_repositories,mk/spec-$(SPEC).mk))
@ -135,56 +128,86 @@ init_progress_log:
.PHONY: init_libdep_file .PHONY: init_libdep_file
init_libdep_file: init_libdep_file:
@echo "#" > $(LIB_DEP_FILE) @echo "checking library dependencies..."
@echo "# Library dependencies for build '$(DST_DIRS)'" >> $(LIB_DEP_FILE) @(echo "#"; \
@echo "#" >> $(LIB_DEP_FILE) echo "# Library dependencies for build '$(DST_DIRS)'"; \
@echo "" >> $(LIB_DEP_FILE) echo "#"; \
@echo "export SPEC_FILES := \\" >> $(LIB_DEP_FILE) echo ""; \
@for i in $(SPEC_FILES); do \ echo "export SPEC_FILES := \\"; \
echo " $$i \\" >> $(LIB_DEP_FILE); done for i in $(SPEC_FILES); do \
@echo "" >> $(LIB_DEP_FILE) echo " $$i \\"; done; \
@echo "LIB_CACHE_DIR = $(LIB_CACHE_DIR)" >> $(LIB_DEP_FILE) echo ""; \
@echo "BASE_DIR = $(realpath $(BASE_DIR))" >> $(LIB_DEP_FILE) echo "LIB_CACHE_DIR = $(LIB_CACHE_DIR)"; \
@echo "VERBOSE ?= $(VERBOSE)" >> $(LIB_DEP_FILE) echo "BASE_DIR = $(realpath $(BASE_DIR))"; \
@echo "VERBOSE_MK ?= $(VERBOSE_MK)" >> $(LIB_DEP_FILE) echo "VERBOSE ?= $(VERBOSE)"; \
@echo "VERBOSE_DIR ?= $(VERBOSE_DIR)" >> $(LIB_DEP_FILE) echo "VERBOSE_MK ?= $(VERBOSE_MK)"; \
@echo "INSTALL_DIR ?= $(INSTALL_DIR)" >> $(LIB_DEP_FILE) echo "VERBOSE_DIR ?= $(VERBOSE_DIR)"; \
@echo "SHELL ?= $(SHELL)" >> $(LIB_DEP_FILE) echo "INSTALL_DIR ?= $(INSTALL_DIR)"; \
@echo "MKDIR ?= mkdir" >> $(LIB_DEP_FILE) echo "SHELL ?= $(SHELL)"; \
@echo "" >> $(LIB_DEP_FILE) echo "MKDIR ?= mkdir"; \
@echo "all:" >> $(LIB_DEP_FILE) echo ""; \
@echo " @true # prevent nothing-to-be-done message" >> $(LIB_DEP_FILE) echo "all:"; \
@echo "" >> $(LIB_DEP_FILE) echo " @true # prevent nothing-to-be-done message"; \
echo "") > $(LIB_DEP_FILE)
# #
# We check if any target.mk files exist in the specified src directory. If # We check if any target.mk files exist in the specified directories within
# there exist any target.mk files, we revisit each repository and create # any of the repositories listed in the 'REPOSITORIES' variable.
# corresponding rules in the library-dependency file.
#
# This stage is executed serially.
# #
$(dir $(LIB_DEP_FILE)): $(dir $(LIB_DEP_FILE)):
@mkdir -p $@ @mkdir -p $@
VISIT_DST_DIRS = $(addsuffix .visit,$(DST_DIRS)) #
# Find all 'target.mk' files located within any of the specified subdirectories
# ('DST_DIRS') and any repository. The 'sort' is used to remove duplicates.
#
TARGETS_TO_VISIT := $(shell find $(REPOSITORIES:=/src) -false \
$(foreach DST,$(DST_DIRS), \
-or -path "*/src/$(DST)/**target.mk" \
-printf " %P "))
TARGETS_TO_VISIT := $(sort $(TARGETS_TO_VISIT))
.PHONY: $(VISIT_DST_DIRS) #
.NOTPARALLEL: $(VISIT_DST_DIRS) # Perform sanity check for non-existing targets being specified at the command
$(VISIT_DST_DIRS): $(dir $(LIB_DEP_FILE)) init_libdep_file init_progress_log # line.
@echo "checking library dependencies for $(@:.visit=)..." #
@test "`$(find_all_src_target_mk)`" != "" ||\ MISSING_TARGETS := $(strip \
(echo Error: non-existing target $(@:.visit=); false) $(foreach DST,$(DST_DIRS),\
$(VERBOSE_MK)set -e; for i in $(REPOSITORIES); do \ $(if $(filter $(DST)/%,$(TARGETS_TO_VISIT)),,$(DST))))
for j in `$(find_src_target_mk)`; do \
ifneq ($(MAKECMDGOALS),)
ifneq ($(MISSING_TARGETS),)
init_libdep_file: error_missing_targets
error_missing_targets:
@for target in $(MISSING_TARGETS); do \
echo "Error: target '$$target' does not exist"; done
@false;
endif
endif
#
# The procedure of collecting library dependencies is realized as a single
# rule to gain maximum performance. If we invoked a rule for each target,
# we would need to spawn one additional shell per target, which would take
# 10-20 percent more time.
#
traverse_dependencies: $(dir $(LIB_DEP_FILE)) init_libdep_file init_progress_log
$(VERBOSE_MK) \
for target in $(TARGETS_TO_VISIT); do \
for rep in $(REPOSITORIES); do \
test -f $$rep/src/$$target || continue; \
$(MAKE) $(VERBOSE_DIR) -f $(BASE_DIR)/mk/dep_prg.mk \ $(MAKE) $(VERBOSE_DIR) -f $(BASE_DIR)/mk/dep_prg.mk \
REP_DIR=$$i TARGET_MK=$$j \ REP_DIR=$$rep TARGET_MK=$$rep/src/$$target \
BUILD_BASE_DIR=$(BUILD_BASE_DIR) \ BUILD_BASE_DIR=$(BUILD_BASE_DIR) \
SHELL=$(SHELL) \ SHELL=$(SHELL) \
DARK_COL="$(DARK_COL)" DEFAULT_COL="$(DEFAULT_COL)"; done; done DARK_COL="$(DARK_COL)" DEFAULT_COL="$(DEFAULT_COL)"; \
break; \
done; \
done
.PHONY: $(LIB_DEP_FILE) .PHONY: $(LIB_DEP_FILE)
$(LIB_DEP_FILE): $(VISIT_DST_DIRS) $(LIB_DEP_FILE): traverse_dependencies
## ##
## Second stage: build targets based on the result of the first stage ## Second stage: build targets based on the result of the first stage