michael@0: # This Source Code Form is subject to the terms of the Mozilla Public michael@0: # License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: # You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: michael@0: ifndef INCLUDED_RULES_MK michael@0: include $(topsrcdir)/config/rules.mk michael@0: endif michael@0: michael@0: # The traditional model of directory traversal with make is as follows: michael@0: # make -C foo michael@0: # Entering foo michael@0: # make -C bar michael@0: # Entering foo/bar michael@0: # make -C baz michael@0: # Entering foo/baz michael@0: # make -C qux michael@0: # Entering qux michael@0: # michael@0: # Pseudo derecurse transforms the above into: michael@0: # make -C foo michael@0: # make -C foo/bar michael@0: # make -C foo/baz michael@0: # make -C qux michael@0: michael@0: # MOZ_PSEUDO_DERECURSE can have values other than 1. michael@0: ifeq (1_.,$(if $(MOZ_PSEUDO_DERECURSE),1)_$(DEPTH)) michael@0: michael@0: include root.mk michael@0: michael@0: # Disable build status for mach in top directories without TIERS. michael@0: # In practice this disables it when recursing under js/src, which confuses mach. michael@0: ifndef TIERS michael@0: BUILDSTATUS = michael@0: endif michael@0: michael@0: # Main rules (export, compile, binaries, libs and tools) call recurse_* rules. michael@0: # This wrapping is only really useful for build status. michael@0: compile binaries libs export tools:: michael@0: $(call BUILDSTATUS,TIER_START $@) michael@0: +$(MAKE) recurse_$@ michael@0: $(call BUILDSTATUS,TIER_FINISH $@) michael@0: michael@0: # Carefully avoid $(eval) type of rule generation, which makes pymake slower michael@0: # than necessary. michael@0: # Get current tier and corresponding subtiers from the data in root.mk. michael@0: CURRENT_TIER := $(filter $(foreach tier,compile binaries libs export tools,recurse_$(tier) $(tier)-deps),$(MAKECMDGOALS)) michael@0: ifneq (,$(filter-out 0 1,$(words $(CURRENT_TIER)))) michael@0: $(error $(CURRENT_TIER) not supported on the same make command line) michael@0: endif michael@0: CURRENT_TIER := $(subst recurse_,,$(CURRENT_TIER:-deps=)) michael@0: CURRENT_SUBTIERS := $($(CURRENT_TIER)_subtiers) michael@0: michael@0: # The rules here are doing directory traversal, so we don't want further michael@0: # recursion to happen when running make -C subdir $tier. But some make files michael@0: # further call make -C something else, and sometimes expect recursion to michael@0: # happen in that case (see browser/metro/locales/Makefile.in for example). michael@0: # Conveniently, every invocation of make increases MAKELEVEL, so only stop michael@0: # recursion from happening at current MAKELEVEL + 1. michael@0: ifdef CURRENT_TIER michael@0: ifeq (0,$(MAKELEVEL)) michael@0: export NO_RECURSE_MAKELEVEL=1 michael@0: else michael@0: export NO_RECURSE_MAKELEVEL=$(word $(MAKELEVEL),2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20) michael@0: endif michael@0: endif michael@0: michael@0: # Get all directories traversed for all subtiers in the current tier, or use michael@0: # directly the $(*_dirs) variables available in root.mk when there is no michael@0: # TIERS (like for js/src). michael@0: TIER_DIRS = $(or $($(1)_dirs),$(foreach subtier,$($(1)_subtiers),$($(1)_subtier_$(subtier)))) michael@0: CURRENT_DIRS := $(call TIER_DIRS,$(CURRENT_TIER)) michael@0: michael@0: ifneq (,$(filter binaries libs,$(CURRENT_TIER))) michael@0: WANT_STAMPS = 1 michael@0: STAMP_TOUCH = $(TOUCH) $(@D)/binaries michael@0: endif michael@0: michael@0: # Subtier delimiter rules michael@0: $(addprefix subtiers/,$(addsuffix _start/$(CURRENT_TIER),$(CURRENT_SUBTIERS))): subtiers/%_start/$(CURRENT_TIER): $(if $(WANT_STAMPS),$(call mkdir_deps,subtiers/%_start)) michael@0: @$(STAMP_TOUCH) michael@0: michael@0: $(addprefix subtiers/,$(addsuffix _finish/$(CURRENT_TIER),$(CURRENT_SUBTIERS))): subtiers/%_finish/$(CURRENT_TIER): $(if $(WANT_STAMPS),$(call mkdir_deps,subtiers/%_finish)) michael@0: @$(STAMP_TOUCH) michael@0: michael@0: $(addprefix subtiers/,$(addsuffix /$(CURRENT_TIER),$(CURRENT_SUBTIERS))): %/$(CURRENT_TIER): $(if $(WANT_STAMPS),$(call mkdir_deps,%)) michael@0: @$(STAMP_TOUCH) michael@0: michael@0: GARBAGE_DIRS += subtiers michael@0: michael@0: # Recursion rule for all directories traversed for all subtiers in the michael@0: # current tier. michael@0: # root.mk defines subtier_of_* variables, that map a normalized subdir path to michael@0: # a subtier name (e.g. subtier_of_memory_jemalloc = base) michael@0: $(addsuffix /$(CURRENT_TIER),$(CURRENT_DIRS)): %/$(CURRENT_TIER): michael@0: +@$(MAKE) -C $* $(if $(filter $*,$(tier_$(subtier_of_$(subst /,_,$*))_staticdirs)),,$(CURRENT_TIER)) michael@0: # Ensure existing stamps are up-to-date, but don't create one if submake didn't create one. michael@0: $(if $(wildcard $@),@$(STAMP_TOUCH)) michael@0: michael@0: # Dummy rules for possibly inexisting dependencies for the above tier targets michael@0: $(addsuffix /Makefile,$(CURRENT_DIRS)) $(addsuffix /backend.mk,$(CURRENT_DIRS)): michael@0: michael@0: # The export tier requires nsinstall, which is built from config. So every michael@0: # subdirectory traversal needs to happen after traversing config. michael@0: ifeq ($(CURRENT_TIER),export) michael@0: $(addsuffix /$(CURRENT_TIER),$(filter-out config,$(CURRENT_DIRS))): config/$(CURRENT_TIER) michael@0: endif michael@0: michael@0: ifdef COMPILE_ENVIRONMENT michael@0: ifneq (,$(filter libs binaries,$(CURRENT_TIER))) michael@0: # When doing a "libs" build, target_libs.mk ensures the interesting dependency data michael@0: # is available in the "binaries" stamp. Once recursion is done, aggregate all that michael@0: # dependency info so that stamps depend on relevant files and relevant other stamps. michael@0: # When doing a "binaries" build, the aggregate dependency file and those stamps are michael@0: # used and allow to skip recursing directories where changes are not going to require michael@0: # rebuild. A few directories, however, are still traversed all the time, mostly, the michael@0: # gyp managed ones and js/src. michael@0: # A few things that are not traversed by a "binaries" build, but should, in an ideal michael@0: # world, are nspr, nss, icu and ffi. michael@0: recurse_$(CURRENT_TIER): michael@0: @$(MAKE) binaries-deps michael@0: michael@0: # Creating binaries-deps.mk directly would make us build it twice: once when beginning michael@0: # the build because of the include, and once at the end because of the stamps. michael@0: binaries-deps: $(addsuffix /binaries,$(CURRENT_DIRS)) michael@0: @$(call py_action,link_deps,-o $@.mk --group-by-depfile --topsrcdir $(topsrcdir) --topobjdir $(DEPTH) --dist $(DIST) --guard $(addprefix ',$(addsuffix ',$^))) michael@0: @$(TOUCH) $@ michael@0: michael@0: ifeq (recurse_binaries,$(MAKECMDGOALS)) michael@0: $(call include_deps,binaries-deps.mk) michael@0: endif michael@0: michael@0: endif michael@0: michael@0: DIST_GARBAGE += binaries-deps.mk binaries-deps michael@0: michael@0: endif michael@0: michael@0: else michael@0: michael@0: # Don't recurse if MAKELEVEL is NO_RECURSE_MAKELEVEL as defined above michael@0: ifeq ($(NO_RECURSE_MAKELEVEL),$(MAKELEVEL)) michael@0: michael@0: compile binaries libs export tools:: michael@0: michael@0: else michael@0: ######################### michael@0: # Tier traversal handling michael@0: ######################### michael@0: michael@0: ifdef TIERS michael@0: michael@0: libs export tools:: michael@0: $(call BUILDSTATUS,TIER_START $@) michael@0: $(foreach tier,$(TIERS), $(if $(filter-out libs_precompile tools_precompile,$@_$(tier)), \ michael@0: $(if $(filter libs,$@),$(foreach dir, $(tier_$(tier)_staticdirs), $(call TIER_DIR_SUBMAKE,$@,$(tier),$(dir),,1))) \ michael@0: $(foreach dir, $(tier_$(tier)_dirs), $(call TIER_DIR_SUBMAKE,$@,$(tier),$(dir),$@)))) michael@0: $(call BUILDSTATUS,TIER_FINISH $@) michael@0: michael@0: else michael@0: michael@0: define CREATE_SUBTIER_TRAVERSAL_RULE michael@0: PARALLEL_DIRS_$(1) = $$(addsuffix _$(1),$$(PARALLEL_DIRS)) michael@0: michael@0: .PHONY: $(1) $$(PARALLEL_DIRS_$(1)) michael@0: michael@0: ifdef PARALLEL_DIRS michael@0: $$(PARALLEL_DIRS_$(1)): %_$(1): %/Makefile michael@0: +@$$(call SUBMAKE,$(1),$$*) michael@0: endif michael@0: michael@0: $(1):: $$(SUBMAKEFILES) michael@0: ifdef PARALLEL_DIRS michael@0: +@$(MAKE) $$(PARALLEL_DIRS_$(1)) michael@0: endif michael@0: $$(LOOP_OVER_DIRS) michael@0: michael@0: endef michael@0: michael@0: $(foreach subtier,export compile binaries libs tools,$(eval $(call CREATE_SUBTIER_TRAVERSAL_RULE,$(subtier)))) michael@0: michael@0: tools export:: $(SUBMAKEFILES) michael@0: $(LOOP_OVER_TOOL_DIRS) michael@0: michael@0: endif # ifdef TIERS michael@0: michael@0: endif # ifeq ($(NO_RECURSE_MAKELEVEL),$(MAKELEVEL)) michael@0: michael@0: endif # ifeq (1_.,$(MOZ_PSEUDO_DERECURSE)_$(DEPTH)) michael@0: michael@0: ifdef MOZ_PSEUDO_DERECURSE michael@0: michael@0: ifdef COMPILE_ENVIRONMENT michael@0: michael@0: # Aggregate all dependency files relevant to a binaries build except in michael@0: # the mozilla top-level directory. michael@0: ifneq (.,$(DEPTH)) michael@0: ALL_DEP_FILES := \ michael@0: $(BINARIES_PP) \ michael@0: $(addsuffix .pp,$(addprefix $(MDDEPDIR)/,$(sort \ michael@0: $(TARGETS) \ michael@0: $(filter-out $(SOBJS) $(ASOBJS) $(EXCLUDED_OBJS),$(OBJ_TARGETS)) \ michael@0: ))) \ michael@0: $(NULL) michael@0: endif michael@0: michael@0: binaries libs:: $(TARGETS) $(BINARIES_PP) michael@0: ifneq (.,$(DEPTH)) michael@0: @$(if $^,$(call py_action,link_deps,-o binaries --group-all --topsrcdir $(topsrcdir) --topobjdir $(DEPTH) --dist $(DIST) $(ALL_DEP_FILES))) michael@0: endif michael@0: michael@0: endif michael@0: michael@0: endif # ifdef MOZ_PSEUDO_DERECURSE michael@0: michael@0: recurse: michael@0: @$(RECURSED_COMMAND) michael@0: $(LOOP_OVER_PARALLEL_DIRS) michael@0: $(LOOP_OVER_DIRS) michael@0: $(LOOP_OVER_TOOL_DIRS)