From 3213cd54b76bc80a6f0516aac75a48ff3b2ad67c Mon Sep 17 00:00:00 2001 From: Michael Stahl Date: Mon, 8 Apr 2013 10:59:59 +0200 Subject: [PATCH] gbuild: LinkTarget: only re-link libraries if exported symbols change Write out the exported symbols of a Library to a "libfoo.so.exports" file, which is only touched when linking if the exported symbols actually change, and let dependent LinkTargets depend on this exports file instead of the library itself, for faster rebuilds. This is currently supposed to work on ELF and MacOSX platforms. Thanks to Ami Fischman of Chromium for the idea. Change-Id: Ie4b5da0853140709e517028b514800b044527e61 --- solenv/gbuild/LinkTarget.mk | 14 +++++++++++++- solenv/gbuild/platform/com_GCC_class.mk | 4 ++++ solenv/gbuild/platform/com_MSC_class.mk | 5 +++++ solenv/gbuild/platform/macosx.mk | 8 ++++++++ solenv/gbuild/platform/solaris.mk | 8 ++++++++ solenv/gbuild/platform/unxgcc.mk | 9 +++++++++ 6 files changed, 47 insertions(+), 1 deletion(-) diff --git a/solenv/gbuild/LinkTarget.mk b/solenv/gbuild/LinkTarget.mk index 98964d764ff5..f5c16f3722c5 100644 --- a/solenv/gbuild/LinkTarget.mk +++ b/solenv/gbuild/LinkTarget.mk @@ -402,6 +402,7 @@ $(call gb_LinkTarget_get_clean_target,%) : $(call gb_LinkTarget_get_headers_target,$*) \ $(call gb_LinkTarget_get_external_headers_target,$*) \ $(call gb_LinkTarget_get_objects_list,$*) \ + $(call gb_LinkTarget_get_target,$*).exports \ $(DLLTARGET) \ $(AUXTARGETS)) && \ cat $${RESPONSEFILE} /dev/null | xargs -n 200 rm -fr && \ @@ -442,6 +443,14 @@ mv $${TEMPFILE} $(call gb_LinkTarget_get_objects_list,$(2)) endef +# Target for the .exports of the shared library, to speed up incremental build. +# This deliberately does nothing if the file exists; the file is actually +# written in gb_LinkTarget__command_dynamiclink. +# Put this pattern rule here so it overrides the one below. +# (this is rather ugly: because of % the functions cannot be used) +$(call gb_LinkTarget_get_target,Library/%.exports) : $(gb_Library_OUTDIRLOCATION)/% + $(if $(wildcard $@),true,touch $@) + $(call gb_LinkTarget_get_target,%) : $(call gb_LinkTarget_get_headers_target,%) $(gb_Helper_MISCDUMMY) $(call gb_LinkTarget__command,$@,$*) $(call gb_LinkTarget__command_objectlist,$@,$*) @@ -830,7 +839,10 @@ endif $(call gb_LinkTarget_get_target,$(1)) : LINKED_LIBS += $(3) -$(call gb_LinkTarget_get_target,$(1)) : $(foreach lib,$(3),$(call gb_Library_get_target,$(lib))) +# depend on the exports of the library, not on the library itself +# for faster incremental builds when the ABI is unchanged +$(call gb_LinkTarget_get_target,$(1)) : \ + $(foreach lib,$(3),$(call gb_Library_get_exports_target,$(lib))) $(call gb_LinkTarget_get_external_headers_target,$(1)) : \ $(foreach lib,$(2),$(call gb_Library_get_headers_target,$(lib))) diff --git a/solenv/gbuild/platform/com_GCC_class.mk b/solenv/gbuild/platform/com_GCC_class.mk index c8a8d3366dd2..4f30a5082404 100644 --- a/solenv/gbuild/platform/com_GCC_class.mk +++ b/solenv/gbuild/platform/com_GCC_class.mk @@ -240,6 +240,10 @@ $(call gb_Helper_abbreviate_dirs,\ ) endef +define gb_Library_get_exports_target +$(call gb_LinkTarget_get_target,$(call gb_Library_get_linktargetname,$(1))).exports +endef + # YaccTarget class ifeq ($(ANCIENT_BISON),YES) diff --git a/solenv/gbuild/platform/com_MSC_class.mk b/solenv/gbuild/platform/com_MSC_class.mk index a14a871a337b..861626bd7e2f 100755 --- a/solenv/gbuild/platform/com_MSC_class.mk +++ b/solenv/gbuild/platform/com_MSC_class.mk @@ -351,6 +351,11 @@ define gb_Library_get_dllname $(patsubst $(1):%,%,$(filter $(1):%,$(gb_Library_DLLFILENAMES))) endef +# this is nerfed, it just points to the library to disable the .exports +define gb_Library_get_exports_target +$(call gb_LinkTarget_get_target,$(call gb_Library_get_linktargetname,$(1))) +endef + # StaticLibrary class diff --git a/solenv/gbuild/platform/macosx.mk b/solenv/gbuild/platform/macosx.mk index a780c598e9a2..011aaaeec407 100644 --- a/solenv/gbuild/platform/macosx.mk +++ b/solenv/gbuild/platform/macosx.mk @@ -163,6 +163,14 @@ $(call gb_Helper_abbreviate_dirs,\ $(if $(MACOSX_CODESIGNING_IDENTITY), \ $(if $(filter Executable,$(TARGETTYPE)), \ codesign --timestamp=none --identifier=$(MACOSX_BUNDLE_IDENTIFIER).$(notdir $(1)) --sign $(MACOSX_CODESIGNING_IDENTITY) $(1) &&)) \ + $(if $(filter Library,$(TARGETTYPE)),\ + otool -l $(1) | grep -A 5 LC_ID_DYLIB > $(1).exports.tmp && \ + $(NM) -g -P $(1) | cut -d' ' -f1-2 | grep -v U$$ \ + >> $(1).exports.tmp && \ + if cmp -s $(1).exports.tmp $(1).exports; \ + then rm $(1).exports.tmp; \ + else mv $(1).exports.tmp $(1).exports; touch -r $(1) $(1).exports; \ + fi &&) \ :) endef diff --git a/solenv/gbuild/platform/solaris.mk b/solenv/gbuild/platform/solaris.mk index d4780aebdf37..cfcca9e0a470 100644 --- a/solenv/gbuild/platform/solaris.mk +++ b/solenv/gbuild/platform/solaris.mk @@ -199,6 +199,14 @@ $(call gb_Helper_abbreviate_dirs,\ $(LIBS) \ $(patsubst lib%.a,-l%,$(patsubst lib%.so,-l%,$(foreach lib,$(LINKED_LIBS),$(call gb_Library_get_filename,$(lib))))) \ -o $(1)) + $(if $(filter Library,$(TARGETTYPE)),\ + $(NM) --extern-only --dynamic --format=posix $(1) \ + | cut -d' ' -f1-2 | grep -v U$$ \ + > $(1).exports.tmp && \ + if cmp -s $(1).exports.tmp $(1).exports; \ + then rm $(1).exports.tmp; \ + else mv $(1).exports.tmp $(1).exports; touch -r $(1) $(1).exports; \ + fi) endef define gb_LinkTarget__command_staticlink diff --git a/solenv/gbuild/platform/unxgcc.mk b/solenv/gbuild/platform/unxgcc.mk index 01b07901ddc8..a32759395eb8 100644 --- a/solenv/gbuild/platform/unxgcc.mk +++ b/solenv/gbuild/platform/unxgcc.mk @@ -202,6 +202,15 @@ $(call gb_Helper_abbreviate_dirs,\ $(patsubst lib%.a,-l%,$(patsubst lib%.so,-l%,$(foreach lib,$(LINKED_LIBS),$(call gb_Library_get_filename,$(lib))))) \ -o $(if $(SOVERSION),$(1).$(SOVERSION),$(1))) $(if $(SOVERSION),ln -sf $(notdir $(1)).$(SOVERSION) $(1)) + $(if $(filter Library,$(TARGETTYPE)),\ + readelf -d $(1) | grep SONAME > $(1).exports.tmp ; \ + $(NM) --dynamic --extern-only --defined-only --format=posix $(1) \ + | cut -d' ' -f1-2 \ + >> $(1).exports.tmp && \ + if cmp -s $(1).exports.tmp $(1).exports; \ + then rm $(1).exports.tmp; \ + else mv $(1).exports.tmp $(1).exports; touch -r $(1) $(1).exports; \ + fi) endef define gb_LinkTarget__command_staticlink