Bug 1043344 - Move libraries and programs build to the compile tier. r=gps
authorMike Hommey <mh+mozilla@glandium.org>
Fri, 25 Jul 2014 07:14:40 +0900
changeset 217705 0300f04572b6
parent 217704 77804ecb8566
child 217706 b0a916157c9a
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps
bugs1043344
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1043344 - Move libraries and programs build to the compile tier. r=gps
Makefile.in
config/Makefile.in
config/config.mk
config/makefiles/target_binaries.mk
config/nspr/Makefile.in
config/recurse.mk
config/rules.mk
modules/libmar/tool/Makefile.in
moz.build
mozglue/build/Makefile.in
python/mozbuild/mozbuild/backend/recursivemake.py
python/mozbuild/mozbuild/frontend/emitter.py
python/mozbuild/mozbuild/frontend/reader.py
python/mozbuild/mozbuild/frontend/sandbox_symbols.py
security/build/Makefile.in
toolkit/library/Makefile.in
toolkit/toolkit.mozbuild
--- a/Makefile.in
+++ b/Makefile.in
@@ -312,10 +312,24 @@ source-package install:
 config/export:
 
 endif
 
 # Interdependencies for parallel export.
 js/xpconnect/src/export: dom/bindings/export xpcom/xpidl/export
 accessible/xpcom/export: xpcom/xpidl/export
 ifdef ENABLE_CLANG_PLUGIN
-js/src/export config/export: build/clang-plugin/export
+js/src/export config/host: build/clang-plugin/export
+endif
+
+# Interdependencies that moz.build world don't know about yet for compilation.
+# Note some others are hardcoded or "guessed" in recursivemake.py and emitter.py
+ifeq ($(MOZ_WIDGET_TOOLKIT),gtk3)
+toolkit/library/target: widget/gtk/mozgtk/gtk3/target
 endif
+ifndef MOZ_FOLD_LIBS
+ifndef MOZ_NATIVE_SQLITE
+security/build/target: db/sqlite3/src/target
+endif
+endif
+ifeq ($(MOZ_REPLACE_MALLOC_LINKAGE),dummy library)
+mozglue/build/target: memory/replace/dummy/target
+endif
--- a/config/Makefile.in
+++ b/config/Makefile.in
@@ -1,18 +1,14 @@
 # -*- Makefile -*-
 #
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-# STDCXX_COMPAT is not needed here, and will actually fail because
-# libstdc++-compat is not built yet.
-MOZ_LIBSTDCXX_HOST_VERSION =
-
 # IMPORTANT: Disable NSBUILDROOT for this directory only, otherwise we have
 # a recursive rule for finding nsinstall and the Perl scripts.
 ifdef NSBUILDROOT
 override NSBUILDROOT :=
 endif
 
 ifdef GNU_CC
 MODULE_OPTIMIZE_FLAGS = -O3
@@ -24,17 +20,17 @@ ifneq (WINNT,$(HOST_OS_ARCH))
 ifdef COMPILE_ENVIRONMENT
 # Ensure nsinstall is atomically created
 nsinstall$(HOST_BIN_SUFFIX): $(HOST_PROGRAM)
 	cp $^ $@.tmp
 	mv $@.tmp $@
 
 NSINSTALL_EXECUTABLES := nsinstall$(HOST_BIN_SUFFIX)
 NSINSTALL_DEST := $(DIST)/bin
-NSINSTALL_TARGET := export
+NSINSTALL_TARGET := host
 INSTALL_TARGETS += NSINSTALL
 endif
 endif
 
 ifndef JS_STANDALONE
 HEADERS_FILES = \
 	$(DEPTH)/mozilla-config.h \
 	$(NULL)
--- a/config/config.mk
+++ b/config/config.mk
@@ -767,23 +767,16 @@ ifdef SYMBOL_ORDER
 EXPAND_MKSHLIB_ARGS += --symbol-order $(SYMBOL_ORDER)
 endif
 EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) $(EXPAND_MKSHLIB_ARGS) -- $(MKSHLIB)
 
 ifneq (,$(MOZ_LIBSTDCXX_TARGET_VERSION)$(MOZ_LIBSTDCXX_HOST_VERSION))
 ifneq ($(OS_ARCH),Darwin)
 CHECK_STDCXX = @$(TOOLCHAIN_PREFIX)objdump -p $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' > /dev/null && echo 'TEST-UNEXPECTED-FAIL | check_stdcxx | We do not want these libstdc++ symbols to be used:' && $(TOOLCHAIN_PREFIX)objdump -T $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' && false || true
 endif
-
-ifdef MOZ_LIBSTDCXX_TARGET_VERSION
-OS_LIBS += $(call EXPAND_LIBNAME_PATH,stdc++compat,$(DEPTH)/build/unix/stdc++compat)
-endif
-ifdef MOZ_LIBSTDCXX_HOST_VERSION
-HOST_EXTRA_LIBS += $(call EXPAND_LIBNAME_PATH,host_stdc++compat,$(DEPTH)/build/unix/stdc++compat)
-endif
 endif
 
 ifeq (,$(filter $(OS_TARGET),WINNT Darwin))
 CHECK_TEXTREL = @$(TOOLCHAIN_PREFIX)readelf -d $(1) | grep TEXTREL > /dev/null && echo 'TEST-UNEXPECTED-FAIL | check_textrel | We do not want text relocations in libraries and programs' || true
 endif
 
 define CHECK_BINARY
 $(call CHECK_STDCXX,$(1))
--- a/config/makefiles/target_binaries.mk
+++ b/config/makefiles/target_binaries.mk
@@ -18,69 +18,69 @@ endif # IS_COMPONENT
 endif # SHARED_LIBRARY
 endif # !NO_DIST_INSTALL
 
 ifndef NO_DIST_INSTALL
 
 ifneq (,$(strip $(PROGRAM)$(SIMPLE_PROGRAMS)))
 PROGRAMS_EXECUTABLES = $(SIMPLE_PROGRAMS) $(PROGRAM)
 PROGRAMS_DEST ?= $(FINAL_TARGET)
-PROGRAMS_TARGET := binaries libs
+PROGRAMS_TARGET := binaries libs target
 INSTALL_TARGETS += PROGRAMS
 endif
 
 ifdef LIBRARY
 ifdef DIST_INSTALL
 ifdef IS_COMPONENT
 $(error Shipping static component libs makes no sense.)
 else
 DIST_LIBRARY_FILES = $(LIBRARY)
 DIST_LIBRARY_DEST ?= $(DIST)/lib
-DIST_LIBRARY_TARGET = binaries libs
+DIST_LIBRARY_TARGET = binaries libs target
 INSTALL_TARGETS += DIST_LIBRARY
 endif
 endif # DIST_INSTALL
 endif # LIBRARY
 
 
 ifdef SHARED_LIBRARY
 ifndef IS_COMPONENT
 SHARED_LIBRARY_FILES = $(SHARED_LIBRARY)
 SHARED_LIBRARY_DEST ?= $(FINAL_TARGET)
-SHARED_LIBRARY_TARGET = binaries libs
+SHARED_LIBRARY_TARGET = binaries libs target
 INSTALL_TARGETS += SHARED_LIBRARY
 
 ifneq (,$(filter WINNT,$(OS_ARCH)))
 ifndef NO_INSTALL_IMPORT_LIBRARY
 IMPORT_LIB_FILES = $(IMPORT_LIBRARY)
 endif # NO_INSTALL_IMPORT_LIBRARY
 else
 IMPORT_LIB_FILES = $(SHARED_LIBRARY)
 endif
 
 IMPORT_LIB_DEST ?= $(DIST)/lib
-IMPORT_LIB_TARGET = binaries libs
+IMPORT_LIB_TARGET = binaries libs target
 ifdef IMPORT_LIB_FILES
 INSTALL_TARGETS += IMPORT_LIB
 endif
 
 endif # ! IS_COMPONENT
 endif # SHARED_LIBRARY
 
 ifneq (,$(strip $(HOST_SIMPLE_PROGRAMS)$(HOST_PROGRAM)))
 HOST_PROGRAMS_EXECUTABLES = $(HOST_SIMPLE_PROGRAMS) $(HOST_PROGRAM)
 HOST_PROGRAMS_DEST ?= $(DIST)/host/bin
-HOST_PROGRAMS_TARGET = binaries libs
+HOST_PROGRAMS_TARGET = binaries libs host
 INSTALL_TARGETS += HOST_PROGRAMS
 endif
 
 ifdef HOST_LIBRARY
 HOST_LIBRARY_FILES = $(HOST_LIBRARY)
 HOST_LIBRARY_DEST ?= $(DIST)/host/lib
-HOST_LIBRARY_TARGET = binaries libs
+HOST_LIBRARY_TARGET = binaries libs host
 INSTALL_TARGETS += HOST_LIBRARY
 endif
 
 endif # !NO_DIST_INSTALL
 
 BINARIES_INSTALL_TARGETS := $(foreach category,$(INSTALL_TARGETS),$(if $(filter binaries,$($(category)_TARGET)),$(category)))
 
 # Fill a dependency file with all the binaries installed somewhere in $(DIST)
--- a/config/nspr/Makefile.in
+++ b/config/nspr/Makefile.in
@@ -24,20 +24,21 @@ EXTRA_MAKE_FLAGS := SHARED_LIBRARY= IMPO
 # See bug #838566.
 EXTRA_MAKE_FLAGS += XP_DEFINE=-DlibVersionPoint='libVersionPoint$$(LIBRARY_NAME)'
 else
 # nspr's make export compiles and links everything, but linking can't happen
 # during export on platforms where nspr is linked against mozcrt/mozglue.
 export:: EXTRA_MAKE_FLAGS := SHARED_LIBRARY= IMPORT_LIBRARY= SHARED_LIB_PDB=
 endif
 
-libs export clean distclean::
+clean distclean export::
 	$(MAKE) -C $(DEPTH)/nsprpub $@ $(EXTRA_MAKE_FLAGS)
 
-libs::
+target::
+	$(MAKE) -C $(DEPTH)/nsprpub libs $(EXTRA_MAKE_FLAGS)
 	$(MAKE) -C $(DEPTH)/nsprpub install prefix=$(ABS_DIST)/sdk exec_prefix=$(ABS_DIST)/sdk bindir=$(ABS_DIST)/sdk/dummy includedir=$(ABS_DIST)/include/nspr libdir=$(ABS_DIST)/sdk/lib datadir=$(ABS_DIST)/sdk/dummy DESTDIR= $(EXTRA_MAKE_FLAGS)
 	$(INSTALL) $(DEPTH)/nsprpub/config/nspr-config $(DIST)/sdk/bin
 	$(RM) -rf $(DIST)/sdk/dummy
 ifneq (,$(filter WINNT,$(OS_ARCH))) # {
 	$(RM) -f $(DIST)/sdk/lib/$(DLL_PREFIX)nspr4$(DLL_SUFFIX) $(DIST)/sdk/lib/$(DLL_PREFIX)plc4$(DLL_SUFFIX) $(DIST)/sdk/lib/$(DLL_PREFIX)plds4$(DLL_SUFFIX)
 	$(RM) -f $(DIST)/sdk/lib/$(LIB_PREFIX)nspr4_s.$(LIB_SUFFIX) $(DIST)/sdk/lib/$(LIB_PREFIX)plc4_s.$(LIB_SUFFIX) $(DIST)/sdk/lib/$(LIB_PREFIX)plds4_s.$(LIB_SUFFIX)
 else # } {
 	$(RM) -f $(DIST)/sdk/lib/$(LIB_PREFIX)nspr4.$(LIB_SUFFIX) $(DIST)/sdk/lib/$(LIB_PREFIX)plc4.$(LIB_SUFFIX) $(DIST)/sdk/lib/$(LIB_PREFIX)plds4.$(LIB_SUFFIX)
--- a/config/recurse.mk
+++ b/config/recurse.mk
@@ -71,35 +71,62 @@ endif
 # TIERS (like for js/src).
 CURRENT_DIRS := $($(CURRENT_TIER)_dirs)
 
 ifneq (,$(filter binaries libs,$(CURRENT_TIER)))
 WANT_STAMPS = 1
 STAMP_TOUCH = $(TOUCH) $(@D)/binaries
 endif
 
+# The compile tier has different rules from other tiers.
+ifeq ($(CURRENT_TIER),compile)
+
+# Need a list of compile targets because we can't use pattern rules:
+# https://savannah.gnu.org/bugs/index.php?42833
+.PHONY: $(compile_targets)
+$(compile_targets):
+	$(call SUBMAKE,$(if $(filter $(@D),$(staticdirs)),,$(@F)),$(@D))
+
+else
+
 # Recursion rule for all directories traversed for all subtiers in the
 # current tier.
 $(addsuffix /$(CURRENT_TIER),$(CURRENT_DIRS)): %/$(CURRENT_TIER):
-	$(call SUBMAKE,$(if $(filter $*,$(staticdirs)),,$(CURRENT_TIER)),$*)
+	$(call SUBMAKE,$(CURRENT_TIER),$*)
 # Ensure existing stamps are up-to-date, but don't create one if submake didn't create one.
 	$(if $(wildcard $@),@$(STAMP_TOUCH))
 
 ifndef STAMP_TOUCH
 .PHONY: $(addsuffix /$(CURRENT_TIER),$(CURRENT_DIRS))
 endif
 
 # Dummy rules for possibly inexisting dependencies for the above tier targets
 $(addsuffix /Makefile,$(CURRENT_DIRS)) $(addsuffix /backend.mk,$(CURRENT_DIRS)):
 
+# At least build/export requires config/export for buildid, but who knows what
+# else, so keep this global dependency to make config/export first for now.
+$(addsuffix /$(CURRENT_TIER),$(filter-out config,$(CURRENT_DIRS))): config/$(CURRENT_TIER)
+
 # The export tier requires nsinstall, which is built from config. So every
-# subdirectory traversal needs to happen after traversing config.
+# subdirectory traversal needs to happen after building nsinstall in config, which
+# is done with the config/host target. Note the config/host target only exists if
+# nsinstall is actually built, which it is not on Windows, because we use
+# nsinstall.py there.
 ifeq ($(CURRENT_TIER),export)
-$(addsuffix /$(CURRENT_TIER),$(filter-out config,$(CURRENT_DIRS))): config/$(CURRENT_TIER)
+ifneq (,$(filter config/host, $(compile_targets)))
+$(addsuffix /$(CURRENT_TIER),$(CURRENT_DIRS)): config/host
+
+# Ensure rules for config/host and its possible dependencies.
+.PHONY: $(filter %/host, $(compile_targets))
+$(filter %/host, $(compile_targets)):
+	$(call SUBMAKE,host,$(@D))
 endif
+endif
+
+endif # ifeq ($(CURRENT_TIER),compile)
 
 ifdef COMPILE_ENVIRONMENT
 # Disable dependency aggregation on PGO builds because of bug 934166.
 ifeq (,$(MOZ_PGO)$(MOZ_PROFILE_USE)$(MOZ_PROFILE_GENERATE))
 ifneq (,$(filter libs binaries,$(CURRENT_TIER)))
 # When doing a "libs" build, target_libs.mk ensures the interesting dependency data
 # is available in the "binaries" stamp. Once recursion is done, aggregate all that
 # dependency info so that stamps depend on relevant files and relevant other stamps.
@@ -166,17 +193,17 @@ endif
 $(1):: $$(SUBMAKEFILES)
 ifdef PARALLEL_DIRS
 	+@$(MAKE) $$(PARALLEL_DIRS_$(1))
 endif
 	$$(LOOP_OVER_DIRS)
 
 endef
 
-$(foreach subtier,export compile binaries libs tools,$(eval $(call CREATE_SUBTIER_TRAVERSAL_RULE,$(subtier))))
+$(foreach subtier,export binaries libs tools,$(eval $(call CREATE_SUBTIER_TRAVERSAL_RULE,$(subtier))))
 
 tools export:: $(SUBMAKEFILES)
 	$(LOOP_OVER_TOOL_DIRS)
 
 endif # ifdef TIERS
 
 endif # ifeq ($(NO_RECURSE_MAKELEVEL),$(MAKELEVEL))
 
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -83,17 +83,17 @@ ifdef COMPILE_ENVIRONMENT
 # which stuff links.
 SIMPLE_PROGRAMS += $(CPP_UNIT_TESTS)
 INCLUDES += -I$(DIST)/include/testing
 LIBS += $(NSPR_LIBS)
 
 ifndef MOZ_PROFILE_GENERATE
 CPP_UNIT_TESTS_FILES = $(CPP_UNIT_TESTS)
 CPP_UNIT_TESTS_DEST = $(DIST)/cppunittests
-CPP_UNIT_TESTS_TARGET = libs
+CPP_UNIT_TESTS_TARGET = binaries libs target
 INSTALL_TARGETS += CPP_UNIT_TESTS
 endif
 
 run-cppunittests::
 	@$(PYTHON) $(topsrcdir)/testing/runcppunittests.py --xre-path=$(DIST)/bin --symbols-path=$(DIST)/crashreporter-symbols $(CPP_UNIT_TESTS)
 
 cppunittests-remote: DM_TRANS?=adb
 cppunittests-remote:
@@ -586,17 +586,21 @@ HOST_LIBS_DEPS = $(filter %.$(LIB_SUFFIX
 
 # Dependencies which, if modified, should cause everything to rebuild
 GLOBAL_DEPS += Makefile $(DEPTH)/config/autoconf.mk $(topsrcdir)/config/config.mk
 
 ##############################################
 ifdef COMPILE_ENVIRONMENT
 OBJ_TARGETS = $(OBJS) $(PROGOBJS) $(HOST_OBJS) $(HOST_PROGOBJS)
 
-compile:: $(OBJ_TARGETS)
+compile:: host target
+
+host:: $(HOST_LIBRARY) $(HOST_PROGRAM) $(HOST_SIMPLE_PROGRAMS)
+
+target:: $(LIBRARY) $(SHARED_LIBRARY) $(PROGRAM) $(SIMPLE_PROGRAMS)
 
 include $(topsrcdir)/config/makefiles/target_binaries.mk
 endif
 
 ifdef IS_TOOL_DIR
 # One would think "tools:: libs" would work, but it turns out that combined with
 # bug 907365, this makes make forget to run some rules sometimes.
 tools::
@@ -712,17 +716,17 @@ ifdef MSMANIFEST_TOOL
 	fi
 endif	# MSVC with manifest tool
 ifdef MOZ_PROFILE_GENERATE
 # touch it a few seconds into the future to work around FAT's
 # 2-second granularity
 	touch -t `date +%Y%m%d%H%M.%S -d 'now+5seconds'` pgo.relink
 endif
 else # !WINNT || GNU_CC
-	$(EXPAND_CCC) -o $@ $(CXXFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(LIBS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(EXE_DEF_FILE) $(STLPORT_LIBS)
+	$(EXPAND_CCC) -o $@ $(CXXFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(EXE_DEF_FILE) $(STLPORT_LIBS)
 	$(call CHECK_BINARY,$@)
 endif # WINNT && !GNU_CC
 
 ifdef ENABLE_STRIP
 	$(STRIP) $(STRIP_FLAGS) $@
 endif
 ifdef MOZ_POST_PROGRAM_COMMAND
 	$(MOZ_POST_PROGRAM_COMMAND) $@
@@ -768,17 +772,17 @@ ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
 	$(EXPAND_LD) -nologo -out:$@ -pdb:$(LINK_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(LIBS) $(EXTRA_LIBS) $(OS_LIBS)
 ifdef MSMANIFEST_TOOL
 	@if test -f $@.manifest; then \
 		mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \
 		rm -f $@.manifest; \
 	fi
 endif	# MSVC with manifest tool
 else
-	$(EXPAND_CCC) $(CXXFLAGS) -o $@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(LIBS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(STLPORT_LIBS)
+	$(EXPAND_CCC) $(CXXFLAGS) -o $@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(STLPORT_LIBS)
 	$(call CHECK_BINARY,$@)
 endif # WINNT && !GNU_CC
 
 ifdef ENABLE_STRIP
 	$(STRIP) $(STRIP_FLAGS) $@
 endif
 ifdef MOZ_POST_PROGRAM_COMMAND
 	$(MOZ_POST_PROGRAM_COMMAND) $@
@@ -1264,24 +1268,27 @@ endif
 
 ################################################################################
 # SDK
 
 ifneq (,$(SDK_LIBRARY))
 ifndef NO_DIST_INSTALL
 SDK_LIBRARY_FILES := $(SDK_LIBRARY)
 SDK_LIBRARY_DEST := $(SDK_LIB_DIR)
+SDK_LIBRARY_TARGET := binaries libs target
 INSTALL_TARGETS += SDK_LIBRARY
 endif
 endif # SDK_LIBRARY
 
 ifneq (,$(strip $(SDK_BINARY)))
 ifndef NO_DIST_INSTALL
 SDK_BINARY_FILES := $(SDK_BINARY)
 SDK_BINARY_DEST := $(SDK_BIN_DIR)
+# SDK_BINARY_TARGET is set in xpcom/idl-parser/Makefile.in
+SDK_BINARY_TARGET ?= binaries libs target
 INSTALL_TARGETS += SDK_BINARY
 endif
 endif # SDK_BINARY
 
 ################################################################################
 # CHROME PACKAGING
 
 chrome::
--- a/modules/libmar/tool/Makefile.in
+++ b/modules/libmar/tool/Makefile.in
@@ -13,16 +13,19 @@ MOZ_GLUE_LDFLAGS =
 MOZ_GLUE_PROGRAM_LDFLAGS =
 
 HOST_CFLAGS += \
   -DNO_SIGN_VERIFY \
   $(DEFINES) \
   $(NULL)
 
 ifdef MOZ_ENABLE_SIGNMAR
+# Please don't remove the following comment, because it does some magic:
+# We don't want to use NSS_LIBS, presumably to avoid useless dependencies
+# on parts of nss that don't matter.
 EXTRA_LIBS += \
   $(DIST)/lib/$(LIB_PREFIX)nss3.$(LIB_SUFFIX) \
   $(DIST)/lib/$(LIB_PREFIX)nssutil3.$(LIB_SUFFIX) \
   $(NSPR_LIBS) \
   $(NULL)
 endif
 
 ifeq ($(HOST_OS_ARCH),WINNT)
--- a/moz.build
+++ b/moz.build
@@ -37,24 +37,31 @@ if not CONFIG['LIBXUL_SDK']:
         add_tier_dir('base', ['mozglue', 'memory/mozalloc'])
 
 
 if not CONFIG['JS_STANDALONE']:
     add_tier_dir('precompile', 'xpcom/xpidl')
 
 if CONFIG['COMPILE_ENVIRONMENT'] and not CONFIG['LIBXUL_SDK']:
     if CONFIG['MOZ_BUILD_NSPR']:
-        add_tier_dir('nspr', 'config/nspr')
+        add_tier_dir('nspr', 'config/nspr', trigger='NSPR_LIBS')
 
     if not CONFIG['JS_STANDALONE']:
         add_tier_dir('external', 'config/external')
         if not CONFIG['MOZ_NATIVE_NSS']:
-             add_tier_dir('nss', 'security/build')
+            # We want security/build to be built before anything using
+            # NSPR_LIBS when MOZ_FOLD_LIBS is set, because that's where NSPR
+            # actually ends up being linked. All places using NSS_LIBS also
+            # use NSPR_LIBS so it's safe to use the latter.
+            add_tier_dir('nss', 'security/build',
+                trigger='NSPR_LIBS' if CONFIG['MOZ_FOLD_LIBS'] else 'NSS_LIBS')
 
     if CONFIG['BUILD_CTYPES'] and not CONFIG['MOZ_NATIVE_FFI']:
-        add_tier_dir('js', ['js/src/ctypes/libffi'], static=True)
-    add_tier_dir('js', ['intl/icu'], static=True)
-    CONFIGURE_SUBST_FILES += ['intl/icu/Makefile']
+        add_tier_dir('js', ['js/src/ctypes/libffi'], static=True,
+            trigger='MOZ_FFI_LIBS')
+    if CONFIG['ENABLE_INTL_API'] and not CONFIG['MOZ_NATIVE_ICU']:
+        add_tier_dir('js', ['intl/icu'], static=True, trigger='MOZ_ICU_LIBS')
+        CONFIGURE_SUBST_FILES += ['intl/icu/Makefile']
     add_tier_dir('js', ['js/src'])
 
 if not CONFIG['JS_STANDALONE']:
     # Bring in the configuration for the configured application.
     include('/' + CONFIG['MOZ_BUILD_APP'] + '/app.mozbuild')
--- a/mozglue/build/Makefile.in
+++ b/mozglue/build/Makefile.in
@@ -121,17 +121,17 @@ ifeq (WINNT,$(OS_TARGET))
 # back together with the patched crtdll.obj, glue it to the end of jemalloc's
 # import library and link the rest of Mozilla to that.
 #
 # The result?  A binary that uses jemalloc, doesn't crash, and leaks a tiny
 # amount of memory (32 words per DLL in the 2010 CRT) at shutdown.
 #
 ###############################################################################
 
-libs:: mozcrt.lib
+target:: mozcrt.lib
 	$(INSTALL) $(IFLAGS2) mozcrt.lib $(DIST)/lib
 
 # And finally combine that with the jemalloc import library to get an import
 # library that has our malloc/free/etc and the CRT's everything else
 mozcrt.lib: $(IMPORT_LIBRARY) msvc_modified.lib
 	lib -OUT:$@ $^
 
 # Put the fixed object file back in
--- a/python/mozbuild/mozbuild/backend/recursivemake.py
+++ b/python/mozbuild/mozbuild/backend/recursivemake.py
@@ -5,17 +5,20 @@
 from __future__ import unicode_literals
 
 import itertools
 import json
 import logging
 import os
 import types
 
-from collections import namedtuple
+from collections import (
+    defaultdict,
+    namedtuple,
+)
 
 import mozwebidlcodegen
 from reftest import ReftestManifest
 
 import mozbuild.makeutil as mozmakeutil
 from mozpack.copier import FilePurger
 from mozpack.manifests import (
     InstallManifest,
@@ -314,16 +317,19 @@ class RecursiveMakeBackend(CommonBackend
                 'dist_public',
                 'dist_private',
                 'dist_sdk',
                 'tests',
                 'xpidl',
             ]}
 
         self._traversal = RecursiveMakeTraversal()
+        self._compile_graph = defaultdict(set)
+        self._triggers = defaultdict(set)
+
         self._may_skip = {
             'export': set(),
             'compile': set(),
             'binaries': set(),
             'libs': set(),
             'tools': set(),
         }
 
@@ -500,28 +506,19 @@ class RecursiveMakeBackend(CommonBackend
 
         # Traverse directories in parallel, and skip static dirs
         def parallel_filter(current, subdirs):
             all_subdirs = subdirs.parallel + subdirs.dirs + \
                           subdirs.tests + subdirs.tools
             if current in self._may_skip[tier] \
                     or current.startswith('subtiers/'):
                 current = None
-            # subtiers/*_start and subtiers/*_finish, under subtiers/*, are
-            # kept sequential. Others are all forced parallel.
-            if current and current.startswith('subtiers/') and all_subdirs and \
-                    all_subdirs[0].startswith('subtiers/'):
-                return current, [], all_subdirs
             return current, all_subdirs, []
 
         # build everything in parallel, including static dirs
-        def compile_filter(current, subdirs):
-            current, parallel, sequential = parallel_filter(current, subdirs)
-            return current, subdirs.static + parallel, sequential
-
         # Skip tools dirs during libs traversal. Because of bug 925236 and
         # possible other unknown race conditions, don't parallelize the libs
         # tier.
         def libs_filter(current, subdirs):
             if current in self._may_skip[tier] \
                     or current.startswith('subtiers/'):
                 current = None
             return current, [], subdirs.parallel + \
@@ -532,45 +529,60 @@ class RecursiveMakeBackend(CommonBackend
         def tools_filter(current, subdirs):
             if current in self._may_skip[tier] \
                     or current.startswith('subtiers/'):
                 current = None
             return current, subdirs.parallel, \
                 subdirs.dirs + subdirs.tests + subdirs.tools
 
         # compile, binaries and tools tiers use the same traversal as export
-        filters = {
-            'export': parallel_filter,
-            'compile': compile_filter,
-            'binaries': parallel_filter,
-            'libs': libs_filter,
-            'tools': tools_filter,
-        }
+        filters = [
+            ('export', parallel_filter),
+            ('binaries', parallel_filter),
+            ('libs', libs_filter),
+            ('tools', tools_filter),
+        ]
 
         root_deps_mk = Makefile()
 
         # Fill the dependencies for traversal of each tier.
-        for tier, filter in filters.items():
+        for tier, filter in filters:
             main, all_deps = \
                 self._traversal.compute_dependencies(filter)
             for dir, deps in all_deps.items():
                 if deps is not None:
                     rule = root_deps_mk.create_rule(['%s/%s' % (dir, tier)])
                     rule.add_dependencies('%s/%s' % (d, tier) for d in deps if d)
             rule = root_deps_mk.create_rule(['recurse_%s' % tier])
             if main:
                 rule.add_dependencies('%s/%s' % (d, tier) for d in main)
 
+        all_compile_deps = reduce(lambda x,y: x|y,
+            self._compile_graph.values()) if self._compile_graph else set()
+        compile_roots = set(self._compile_graph.keys()) - all_compile_deps
+
+        rule = root_deps_mk.create_rule(['recurse_compile'])
+        rule.add_dependencies(compile_roots)
+        for target, deps in sorted(self._compile_graph.items()):
+            if deps:
+                rule = root_deps_mk.create_rule([target])
+                rule.add_dependencies(deps)
+
         root_mk = Makefile()
 
         # Fill root.mk with the convenience variables.
-        for tier, filter in filters.items():
+        for tier, filter in filters:
             all_dirs = self._traversal.traverse('', filter)
             root_mk.add_statement('%s_dirs := %s' % (tier, ' '.join(all_dirs)))
 
+        # Need a list of compile targets because we can't use pattern rules:
+        # https://savannah.gnu.org/bugs/index.php?42833
+        root_mk.add_statement('compile_targets := %s' % ' '.join(sorted(
+            set(self._compile_graph.keys()) | all_compile_deps)))
+
         root_mk.add_statement('$(call include_deps,root-deps.mk)')
 
         with self._write_file(
                 mozpath.join(self.environment.topobjdir, 'root.mk')) as root:
             root_mk.dump(root, removal_guard=False)
 
         with self._write_file(
                 mozpath.join(self.environment.topobjdir, 'root-deps.mk')) as root_deps:
@@ -697,16 +709,24 @@ class RecursiveMakeBackend(CommonBackend
 
                 obj = self.Substitution()
                 obj.output_path = makefile
                 obj.input_path = makefile_in
                 obj.topsrcdir = bf.environment.topsrcdir
                 obj.topobjdir = bf.environment.topobjdir
                 obj.config = bf.environment
                 self._create_makefile(obj, stub=stub)
+                with open(obj.output_path) as fh:
+                    content = fh.read()
+                    for trigger, targets in self._triggers.items():
+                        if trigger.encode('ascii') in content:
+                            for target in targets:
+                                t = '%s/target' % mozpath.relpath(objdir,
+                                    bf.environment.topobjdir)
+                                self._compile_graph[t].add(target)
 
         # Write out a master list of all IPDL source files.
         ipdl_dir = mozpath.join(self.environment.topobjdir, 'ipc', 'ipdl')
         mk = mozmakeutil.Makefile()
 
         sorted_ipdl_sources = list(sorted(self._ipdl_sources))
         mk.add_statement('ALL_IPDLSRCS := %s' % ' '.join(sorted_ipdl_sources))
 
@@ -804,16 +824,20 @@ class RecursiveMakeBackend(CommonBackend
             if obj.tier_static_dirs[tier]:
                 fh.write('staticdirs += %s\n' % (
                     ' '.join(obj.tier_static_dirs[tier])))
                 self._traversal.add('subtiers/%s' % tier,
                                     static=relativize(obj.tier_static_dirs[tier]))
 
             self._traversal.add('', dirs=['subtiers/%s' % tier])
 
+            for d in dirs + obj.tier_static_dirs[tier]:
+                if d.trigger:
+                    self._triggers[d.trigger].add('%s/target' % d)
+
         if obj.dirs:
             fh.write('DIRS := %s\n' % ' '.join(obj.dirs))
             self._traversal.add(backend_file.relobjdir, dirs=relativize(obj.dirs))
 
         if obj.parallel_dirs:
             fh.write('PARALLEL_DIRS := %s\n' % ' '.join(obj.parallel_dirs))
             self._traversal.add(backend_file.relobjdir,
                                 parallel=relativize(obj.parallel_dirs))
@@ -842,18 +866,16 @@ class RecursiveMakeBackend(CommonBackend
 
         if obj.is_tool_dir:
             fh.write('IS_TOOL_DIR := 1\n')
 
         affected_tiers = set(obj.affected_tiers)
         # Until all SOURCES are really in moz.build, consider all directories
         # building binaries to require a pass at compile, too.
         if 'binaries' in affected_tiers:
-            affected_tiers.add('compile')
-        if 'compile' in affected_tiers or 'binaries' in affected_tiers:
             affected_tiers.add('libs')
         if obj.is_tool_dir and 'libs' in affected_tiers:
             affected_tiers.remove('libs')
             affected_tiers.add('tools')
 
         for tier in set(self._may_skip.keys()) - affected_tiers:
             self._may_skip[tier].add(backend_file.relobjdir)
 
@@ -1015,16 +1037,21 @@ class RecursiveMakeBackend(CommonBackend
         backend_file.write('PROGRAM = %s\n' % program)
 
     def _process_host_program(self, program, backend_file):
         backend_file.write('HOST_PROGRAM = %s\n' % program)
 
     def _process_simple_program(self, obj, backend_file):
         if obj.is_unit_test:
             backend_file.write('CPP_UNIT_TESTS += %s\n' % obj.program)
+            # config.mk adds a dependency on NSPR_LIBS for CPP_UNIT_TESTS
+            # Add it here until moz.build land handles this.
+            if 'NSPR_LIBS' in self._triggers:
+                self._compile_graph[self._build_target_for_obj(obj)] |= \
+                    self._triggers['NSPR_LIBS']
         else:
             backend_file.write('SIMPLE_PROGRAMS += %s\n' % obj.program)
 
     def _process_host_simple_program(self, program, backend_file):
         backend_file.write('HOST_SIMPLE_PROGRAMS += %s\n' % program)
 
     def _process_test_manifest(self, obj, backend_file):
         # Much of the logic in this function could be moved to CommonBackend.
@@ -1139,35 +1166,62 @@ class RecursiveMakeBackend(CommonBackend
         backend_file.write('FORCE_STATIC_LIB := 1\n')
         backend_file.write('REAL_LIBRARY := %s\n' % libdef.lib_name)
         if libdef.is_sdk:
             backend_file.write('SDK_LIBRARY := %s\n' % libdef.import_name)
 
     def _process_host_library(self, libdef, backend_file):
         backend_file.write('HOST_LIBRARY_NAME = %s\n' % libdef.basename)
 
+    @staticmethod
+    def _build_target_for_obj(obj):
+        return '%s/%s' % (obj.relobjdir, obj.KIND)
+
     def _process_linked_libraries(self, obj, backend_file):
         def recurse_lib(lib):
             for l in lib.linked_libraries:
                 if isinstance(l, StaticLibrary):
                     for q in recurse_lib(l):
                         yield q
                 else:
                     yield l
 
         def pretty_relpath(lib):
             # If this is an external objdir (i.e., comm-central), use the other
             # directory instead of $(DEPTH).
             if lib.objdir.startswith(topobjdir + '/'):
-                return '$(DEPTH)/%s' % mozpath.relpath(lib.objdir, topobjdir)
+                return '$(DEPTH)/%s' % lib.relobjdir
             else:
-                return mozpath.relpath(lib.objdir, obj.objdir)
+                return lib.relobjdir
 
         topobjdir = mozpath.normsep(obj.topobjdir)
+        # This will create the node even if there aren't any linked libraries.
+        build_target = self._build_target_for_obj(obj)
+        self._compile_graph[build_target]
+
+        # Until MOZ_GLUE_LDFLAGS/MOZ_GLUE_PROGRAM_LDFLAGS are properly
+        # handled in moz.build world, assume any program or shared library
+        # we build depends on it.
+        if obj.KIND == 'target' and not isinstance(obj, StaticLibrary) and \
+                build_target != 'mozglue/build/target' and \
+                not obj.config.substs.get('JS_STANDALONE'):
+            self._compile_graph[build_target].add('mozglue/build/target')
+            if obj.config.substs.get('MOZ_MEMORY'):
+                self._compile_graph[build_target].add('memory/build/target')
+
+        # Until STLPORT_LIBS are properly handled in moz.build world, assume
+        # any program or shared library we build depends on it.
+        if obj.KIND == 'target' and not isinstance(obj, StaticLibrary) and \
+                build_target != 'build/stlport/target' and \
+                'stlport' in obj.config.substs.get('STLPORT_LIBS'):
+            self._compile_graph[build_target].add('build/stlport/target')
+
         for lib in obj.linked_libraries:
+            self._compile_graph[build_target].add(
+                self._build_target_for_obj(lib))
             relpath = pretty_relpath(lib)
             if isinstance(obj, Library):
                 if isinstance(lib, StaticLibrary):
                     backend_file.write_once('SHARED_LIBRARY_LIBS += %s/%s\n'
                                        % (relpath, lib.lib_name))
                     for l in recurse_lib(lib):
                         backend_file.write_once('EXTRA_DSO_LDOPTS += %s/%s\n'
                                         % (pretty_relpath(l), l.import_name))
--- a/python/mozbuild/mozbuild/frontend/emitter.py
+++ b/python/mozbuild/mozbuild/frontend/emitter.py
@@ -221,17 +221,28 @@ class TreeMetadataEmitter(LoggingMixin):
     LIBRARY_NAME_VAR = {
         'host': 'HOST_LIBRARY_NAME',
         'target': 'LIBRARY_NAME',
     }
 
     def _link_libraries(self, sandbox, obj, variable):
         """Add linkage declarations to a given object."""
         assert isinstance(obj, Linkable)
-        for path in sandbox.get(variable, []):
+
+        extra = []
+        # Add stdc++compat library when wanted and needed
+        compat_varname = 'MOZ_LIBSTDCXX_%s_VERSION' % obj.KIND.upper()
+        if sandbox.config.substs.get(compat_varname) \
+                and not isinstance(obj, (StaticLibrary, HostLibrary)):
+            extra.append({
+                'target': 'stdc++compat',
+                'host': 'host_stdc++compat',
+            }[obj.KIND])
+
+        for path in sandbox.get(variable, []) + extra:
             force_static = path.startswith('static:') and obj.KIND == 'target'
             if force_static:
                 path = path[7:]
             name = mozpath.basename(path)
             dir = mozpath.dirname(path)
             candidates = [l for l in self._libs[name] if l.KIND == obj.KIND]
             if dir:
                 if dir.startswith('/'):
--- a/python/mozbuild/mozbuild/frontend/reader.py
+++ b/python/mozbuild/mozbuild/frontend/reader.py
@@ -98,16 +98,20 @@ def is_read_allowed(path, config):
         external = mozpath.normpath(external)
 
         if path.startswith(external):
             return True
 
     return False
 
 
+class PathWithTrigger(unicode):
+    __slots__ = ('trigger',)
+
+
 class SandboxCalledError(SandboxError):
     """Represents an error resulting from calling the error() function."""
 
     def __init__(self, file_stack, message):
         SandboxError.__init__(self, file_stack)
         self.message = message
 
 
@@ -275,17 +279,18 @@ class MozbuildSandbox(Sandbox):
         return data
 
     def _add_android_eclipse_library_project(self, name):
         data = self.add_android_eclipse_project_helper(name)
         data.manifest = None
         data.is_library = True
         return data
 
-    def _add_tier_directory(self, tier, reldir, static=False, external=False):
+    def _add_tier_directory(self, tier, reldir, static=False, external=False,
+            trigger=None):
         """Register a tier directory with the build."""
         if isinstance(reldir, text_type):
             reldir = [reldir]
 
         if not tier in self['TIERS']:
             self['TIERS'][tier] = {
                 'regular': [],
                 'static': [],
@@ -297,16 +302,18 @@ class MozbuildSandbox(Sandbox):
             raise Exception('Only one of external or static can be set at the '
                 'same time')
 
         for path in reldir:
             if path in self['TIERS'][tier][key]:
                 raise Exception('Directory has already been registered with '
                     'tier: %s' % path)
 
+            path = PathWithTrigger(path)
+            path.trigger = trigger
             self['TIERS'][tier][key].append(path)
 
     def _export(self, varname):
         """Export the variable to all subdirectories of the current path."""
 
         exports = self.metadata.setdefault('exports', dict())
         if varname in exports:
             raise Exception('Variable has already been exported: %s' % varname)
--- a/python/mozbuild/mozbuild/frontend/sandbox_symbols.py
+++ b/python/mozbuild/mozbuild/frontend/sandbox_symbols.py
@@ -45,20 +45,19 @@ class FinalTargetValue(SandboxDerivedVal
 #
 # Each variable is a tuple of:
 #
 #   (storage_type, input_types, docs, tier)
 #
 # Tier says for which specific tier the variable has an effect.
 # Valid tiers are:
 # - 'export'
-# - 'compile': everything in relation with compiling objects.
 # - 'binaries': everything in relation with linking objects, producing
 #      programs and libraries.
-# - 'libs': everything that is not compile or binaries and that has
+# - 'libs': everything that is not binaries and that has
 #      traditionally been in the libs tier.
 # - 'tools'
 # A value of None means the variable has no direct effect on any tier.
 
 VARIABLES = {
     # Variables controlling reading of other frontend files.
     'ANDROID_GENERATED_RESFILES': (StrictOrderingOnAppendList, list,
         """Android resource files generated as part of the build.
@@ -84,47 +83,47 @@ VARIABLES = {
         populated by calling add_android_eclipse{_library}_project().
         """, 'export'),
 
     'SOURCES': (StrictOrderingOnAppendListWithFlagsFactory({'no_pgo': bool, 'flags': list}), list,
         """Source code files.
 
         This variable contains a list of source code files to compile.
         Accepts assembler, C, C++, Objective C/C++.
-        """, 'compile'),
+        """, None),
 
     'GENERATED_SOURCES': (StrictOrderingOnAppendList, list,
         """Generated source code files.
 
         This variable contains a list of generated source code files to
         compile. Accepts assembler, C, C++, Objective C/C++.
-        """, 'compile'),
+        """, None),
 
     'FILES_PER_UNIFIED_FILE': (int, int,
         """The number of source files to compile into each unified source file.
 
         """, 'None'),
 
     'UNIFIED_SOURCES': (StrictOrderingOnAppendList, list,
         """Source code files that can be compiled together.
 
         This variable contains a list of source code files to compile,
         that can be concatenated all together and built as a single source
         file. This can help make the build faster and reduce the debug info
         size.
-        """, 'compile'),
+        """, None),
 
     'GENERATED_UNIFIED_SOURCES': (StrictOrderingOnAppendList, list,
         """Generated source code files that can be compiled together.
 
         This variable contains a list of generated source code files to
         compile, that can be concatenated all together, with UNIFIED_SOURCES,
         and built as a single source file. This can help make the build faster
         and reduce the debug info size.
-        """, 'compile'),
+        """, None),
 
     'GENERATED_FILES': (StrictOrderingOnAppendList, list,
         """Generic generated files.
 
         This variable contains a list of generate files for the build system
         to generate at export time. The rules for those files still live in
         Makefile.in.
         """, 'export'),
@@ -268,17 +267,17 @@ VARIABLES = {
         files by the compiler.
         """, None),
 
     'HOST_SOURCES': (StrictOrderingOnAppendList, list,
         """Source code files to compile with the host compiler.
 
         This variable contains a list of source code files to compile.
         with the host compiler.
-        """, 'compile'),
+        """, None),
 
     'IS_COMPONENT': (bool, bool,
         """Whether the library contains a binary XPCOM component manifest.
 
         Implies FORCE_SHARED_LIB.
         """, None),
 
     'PARALLEL_DIRS': (list, list,
@@ -887,17 +886,17 @@ FUNCTIONS = {
 
         The parameters are:
         * name - project name.
 
         This returns a rich Android Eclipse project type, described at
         :py:class:`mozbuild.frontend.data.AndroidEclipseProjectData`.
         """),
 
-    'add_tier_dir': ('_add_tier_directory', (str, [str, list], bool, bool),
+    'add_tier_dir': ('_add_tier_directory', (str, [str, list], bool, bool, str),
         """Register a directory for tier traversal.
 
         This is the preferred way to populate the TIERS variable.
 
         Tiers are how the build system is organized. The build process is
         divided into major phases called tiers. The most important tiers are
         "platform" and "apps." The platform tier builds the Gecko platform
         (typically outputting libxul). The apps tier builds the configured
@@ -924,16 +923,21 @@ FUNCTIONS = {
         Register a directory as having static content (no dependencies)::
 
            add_tier_dir('base', 'foo', static=True)
 
         Register a directory as having external content (same as static
         content, but traversed with export, libs, and tools subtiers::
 
            add_tier_dir('base', 'bar', external=True)
+
+        Note there is a temporary ``trigger`` parameter that tells the build
+        system that if it sees the given string in a Makefile, then the compile
+        rules in that directory depend on the directories listed in the
+        add_tier_dir call.
         """),
 
     'export': ('_export', (str,),
         """Make the specified variable available to all child directories.
 
         The variable specified by the argument string is added to the
         environment of all directories specified in the DIRS, PARALLEL_DIRS,
         TOOL_DIRS, TEST_DIRS, and TEST_TOOL_DIRS variables. If those directories
--- a/security/build/Makefile.in
+++ b/security/build/Makefile.in
@@ -298,28 +298,30 @@ NSS_DIRS += nss/lib/freebl nss/lib/softo
 ifeq (WINNT,$(OS_TARGET))
 NSS_DIRS += nss/lib/zlib
 endif
 endif # MOZ_FOLD_LIBS
 
 # Filter-out $(LIBRARY_NAME) because it's already handled in config/rules.mk.
 NSS_DIST_DLL_FILES := $(addprefix $(DIST)/lib/$(DLL_PREFIX),$(addsuffix $(DLL_SUFFIX),$(filter-out $(LIBRARY_NAME),$(NSS_DLLS)) $(NSS_EXTRA_DLLS)))
 NSS_DIST_DLL_DEST := $(DIST)/bin
+NSS_DIST_DLL_TARGET := binaries libs target
 INSTALL_TARGETS += NSS_DIST_DLL
 
 ifeq ($(OS_ARCH)_$(1), SunOS_softokn3)
 # has to use copy mode on Solaris, see #665509
 $(DIST)/bin/$(DLL_PREFIX)softokn3$(DLL_SUFFIX): INSTALL := $(INSTALL) -t
 endif
 
 NSS_SDK_LIB_FILES := \
   $(addprefix $(DIST)/lib/$(LIB_PREFIX),$(addsuffix .$(LIB_SUFFIX),$(SDK_LIBS))) \
   $(addprefix $(DIST)/bin/$(DLL_PREFIX),$(addsuffix $(DLL_SUFFIX),$(NSS_DLLS))) \
   $(NULL)
 NSS_SDK_LIB_DEST := $(DIST)/sdk/lib
+NSS_SDK_LIB_TARGET := binaries libs target
 INSTALL_TARGETS += NSS_SDK_LIB
 
 ifdef MOZ_FOLD_LIBS
 ifeq (WINNT,$(OS_TARGET))
 SUFFIX = _s.$(LIB_SUFFIX)
 else
 SUFFIX = .$(LIB_SUFFIX)
 endif
@@ -448,17 +450,17 @@ DEFAULT_GMAKE_FLAGS += $(EXTRA_GMAKE_FLA
 export:: $(addprefix export-,$(NSS_DIRS))
 
 $(addprefix clean-,$(NSS_DIRS)): clean-%:
 	$(MAKE) -C $(NSS_SRCDIR)/security/$* $(DEFAULT_GMAKE_FLAGS) clean
 
 clean clobber clobber_all realclean distclean depend:: $(addprefix clean-,$(NSS_DIRS))
 
 NSS_CMD_TARGETS := $(addprefix libs-,$(filter-out nss/cmd/lib,$(filter nss/cmd/%,$(NSS_DIRS))))
-libs:: $(NSS_CMD_TARGETS)
+target:: $(NSS_CMD_TARGETS)
 
 ifdef MOZ_FOLD_LIBS
 $(NSS_CMD_TARGETS): $(addprefix $(DIST)/lib/$(IMPORT_PREFIX),$(addsuffix $(IMPORT_SUFFIX),$(NSS_LIBS)))
 libs-nss/cmd/modutil: libs-nss/lib/jar
 ifeq (WINNT,$(OS_TARGET))
 libs-nss/cmd/modutil: libs-nss/lib/zlib
 endif
 $(NSS_CMD_TARGETS): libs-nss/cmd/lib
--- a/toolkit/library/Makefile.in
+++ b/toolkit/library/Makefile.in
@@ -2,16 +2,19 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this file,
 # You can obtain one at http://mozilla.org/MPL/2.0/.
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 CXXFLAGS += $(TK_CFLAGS)
 endif
 
 include $(topsrcdir)/toolkit/library/libxul.mk
+# Please don't remove the following comment, because it does some magic:
+# libxul.mk adds FT2_LIBS, NSS_LIBS and NSPR_LIBS, but we want to have the
+# string in this file to trigger a dependency on freetype2, nss and nspr.
 
 ifeq (WINNT_1,$(OS_TARGET)_$(MOZ_PROFILE_USE))
 # Wrap linker to measure peak virtual memory usage.
 LD := $(PYTHON) $(topsrcdir)/build/link.py linker-vsize $(LD)
 endif
 
 include $(topsrcdir)/config/rules.mk
 
--- a/toolkit/toolkit.mozbuild
+++ b/toolkit/toolkit.mozbuild
@@ -22,17 +22,18 @@ if CONFIG['MOZ_UPDATER']:
 
 if CONFIG['NS_TRACE_MALLOC']:
     add_tier_dir('platform', 'tools/trace-malloc/lib')
 
 if CONFIG['MOZ_DMD']:
     add_tier_dir('platform', 'memory/replace/dmd')
 
 if CONFIG['MOZ_TREE_FREETYPE']:
-    add_tier_dir('platform', 'modules/freetype2', static=True)
+    add_tier_dir('platform', 'modules/freetype2', static=True,
+        trigger='FT2_LIBS')
 
 add_tier_dir('platform', 'xpcom')
 
 add_tier_dir('platform', [
     'modules/libpref',
     'intl',
     'netwerk',
 ])