Bug 979388 - Make aapt invocation rebuild R.java. r=glandium

This commit adds an empty recipe to dependencies of .aapt.deps, which
forces the appropriate gecko-R.jar rebuild.  This is because Make treats
targets with no recipe at all differently than targets with an empty
recipe, in a way that defeats our dependencies.

What appeared to be happening is the following:

Touch a resource.  On the next build, .aapt.deps is stale, so aapt is
invoked, which generates R.java, and we touch .aapt.deps.

Now R.java depends on .aapt.deps, but this does not appear to force Make
to consider targets that depend on R.java to be stale.  A target that
depends on R.java (such as gecko-R.jar) itself compares timestamps and
finds that gecko-R.jar is newer than R.java (from the previous build),
and this comparison appears to happen before aapt is invoked.  So even
though .aapt.deps is seen to be stale, and by transitivity R.java is
stale, this does not mark gecko-R.jar as stale.  The timestamp check
between R.java and gecko-R.jar appears to happen *before* aapt is
invoked.

On the second build following the update, the R.java generated in the
previous build is newer than gecko-R.jar, triggering the observed
rebuild of gecko-R.jar.
This commit is contained in:
Nick Alexander 2014-03-12 17:22:27 -07:00
parent fbd080396b
commit 28663ebee3
2 changed files with 27 additions and 13 deletions

View File

@ -33,20 +33,23 @@ classes.dex: $(JAVAFILES)
$(DX) --dex --output=$@ classes $(ANDROID_EXTRA_JARS)
# R.java and $(ANDROID_APK_NAME).ap_ are both produced by aapt. To
# save an aapt invocation, we produce them both at the same time.
# save an aapt invocation, we produce them both at the same time. The
# trailing semi-colon defines an empty recipe; defining no recipe at
# all causes Make to treat the target differently, in a way that
# defeats our dependencies.
R.java: .aapt.deps
$(ANDROID_APK_NAME).ap_: .aapt.deps
R.java: .aapt.deps ;
$(ANDROID_APK_NAME).ap_: .aapt.deps ;
# This uses the fact that Android resource directories list all
# resource files one subdirectory below the parent resource directory.
android_res_files := $(wildcard $(addsuffix /*,$(wildcard $(addsuffix /*,$(android_res_dirs)))))
.aapt.deps: $(android_manifest) $(android_res_files) $(wildcard $(ANDROID_ASSETS_DIR))
@$(TOUCH) $@
$(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar $(_ANDROID_RES_FLAG) $(_ANDROID_ASSETS_FLAG) \
-J ${@D} \
-F $(ANDROID_APK_NAME).ap_
@$(TOUCH) $@
$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex
cp $< $@

View File

@ -96,15 +96,19 @@ else
endif
endif
# We touch the target file before invoking Proguard so that Proguard's
# outputs are fresher than the target, preventing a subsequent
# invocation from thinking Proguard's outputs are stale. This is safe
# because Make removes the target file if any recipe command fails.
.proguard.deps: $(ALL_JARS)
$(REPORT_BUILD)
@$(TOUCH) $@
java -jar $(ANDROID_SDK_ROOT)/tools/proguard/lib/proguard.jar \
@$(topsrcdir)/mobile/android/config/proguard.cfg \
-optimizationpasses $(PROGUARD_PASSES) \
-injars $(subst ::,:,$(subst $(NULL) ,:,$(strip $(ALL_JARS)))) \
-outjars jars-proguarded \
-libraryjars $(ANDROID_SDK)/android.jar:$(ANDROID_COMPAT_LIB)
@$(TOUCH) $@
CLASSES_WITH_JNI= \
org.mozilla.gecko.GeckoAppShell \
@ -228,20 +232,23 @@ all_resources = \
$(NULL)
# All of generated/org/mozilla/gecko/R.java, gecko.ap_, and R.txt are
# produced by aapt; this saves aapt invocations.
# produced by aapt; this saves aapt invocations. The trailing
# semi-colon defines an empty recipe; defining no recipe at all causes
# Make to treat the target differently, in a way that defeats our
# dependencies.
$(gecko_package_dir)/R.java: .aapt.deps
gecko.ap_: .aapt.deps
R.txt: .aapt.deps
$(gecko_package_dir)/R.java: .aapt.deps ;
gecko.ap_: .aapt.deps ;
R.txt: .aapt.deps ;
# [Comment 2/3] This tom-foolery provides a target that forces a
# rebuild of gecko.ap_. This is used during packaging to ensure that
# resources are fresh. The alternative would be complicated; see
# [Comment 1/3].
gecko-nodeps/R.java: .aapt.nodeps
gecko-nodeps.ap_: .aapt.nodeps
gecko-nodeps/R.txt: .aapt.nodeps
gecko-nodeps/R.java: .aapt.nodeps ;
gecko-nodeps.ap_: .aapt.nodeps ;
gecko-nodeps/R.txt: .aapt.nodeps ;
# This ignores the default set of resources ignored by aapt, plus
# files starting with '#'. (Emacs produces temp files named #temp#.)
@ -255,8 +262,13 @@ ANDROID_AAPT_IGNORE := !.svn:!.git:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*.scc
# 3: name of ap_ file to write.
# 4: directory to write R.java into.
# 5: directory to write R.txt into.
# We touch the target file before invoking aapt so that aapt's outputs
# are fresher than the target, preventing a subsequent invocation from
# thinking aapt's outputs are stale. This is safe because Make
# removes the target file if any recipe command fails.
define aapt_command
$(1): $$(call mkdir_deps,$(filter-out ./,$(dir $(3) $(4) $(5)))) $(2)
@$$(TOUCH) $$@
$$(AAPT) package -f -M AndroidManifest.xml -I $$(ANDROID_SDK)/android.jar \
--auto-add-overlay \
$$(addprefix -S ,$$(ANDROID_RES_DIRS)) \
@ -265,7 +277,6 @@ $(1): $$(call mkdir_deps,$(filter-out ./,$(dir $(3) $(4) $(5)))) $(2)
-J $(4) \
--output-text-symbols $(5) \
--ignore-assets "$$(ANDROID_AAPT_IGNORE)"
@$$(TOUCH) $$@
endef
# [Comment 3/3] The first of these rules is used during regular