Implement two-pass script parsing.

In preparation of future work. The NDK build script will now parse all
Android.mk and record LOCAL_XXX variables in the modules database.

After all parsing is done, it will populate the dependency graph with
targets and commands. This will allow us to implement "exported" module
variables like LOCAL_EXPORT_CFLAGS and others in a reliable way.

Change-Id: If1eb4ce68b62b5dfa146520a77cbcad401272428
diff --git a/build/core/build-binary.mk b/build/core/build-binary.mk
index 4152db5..6582b1f 100644
--- a/build/core/build-binary.mk
+++ b/build/core/build-binary.mk
@@ -13,11 +13,21 @@
 # limitations under the License.
 #
 
-# we expect the 'my' variable to be defined, either to
-# 'HOST_' or 'TARGET_', and this allows us to call the
-# appropriate compiler with $($(my)CC)
+# Check that LOCAL_MODULE is defined, then restore its LOCAL_XXXX values
+$(call assert-defined,LOCAL_MODULE)
+$(call module-restore-locals,$(LOCAL_MODULE))
+
+# Check LOCAL_IS_HOST_MODULE and define 'my' as either HOST_ or TARGET_
 #
-$(call assert-defined,my)
+LOCAL_IS_HOST_MODULE := $(strip $(LOCAL_IS_HOST_MODULE))
+ifdef LOCAL_IS_HOST_MODULE
+  ifneq ($(LOCAL_IS_HOST_MODULE),true)
+    $(call __ndk_log,$(LOCAL_PATH): LOCAL_IS_HOST_MODULE must be "true" or empty, not "$(LOCAL_IS_HOST_MODULE)")
+  endif
+  my := HOST_
+else
+  my := TARGET_
+endif
 
 # LOCAL_MAKEFILE must also exist and name the Android.mk that
 # included the module build script.
@@ -215,3 +225,56 @@
 $(LOCAL_BUILT_MODULE): PRIVATE_LDLIBS  := $(LOCAL_LDLIBS) $(TARGET_LDLIBS)
 
 $(LOCAL_BUILT_MODULE): PRIVATE_NAME := $(notdir $(LOCAL_BUILT_MODULE))
+
+#
+# If this is a static library module
+#
+ifeq ($(call module-is-static-library,$(LOCAL_MODULE)),$(true))
+$(LOCAL_BUILT_MODULE): $(LOCAL_OBJECTS)
+	@ mkdir -p $(dir $@)
+	@ echo "StaticLibrary  : $(PRIVATE_NAME)"
+	$(hide) rm -rf $@
+	$(hide) $(cmd-build-static-library)
+
+ALL_STATIC_LIBRARIES += $(LOCAL_BUILT_MODULE)
+endif
+
+#
+# If this is a shared library module
+#
+ifeq ($(call module-is-shared-library,$(LOCAL_MODULE)),$(true))
+$(LOCAL_BUILT_MODULE): $(LOCAL_OBJECTS)
+	@ mkdir -p $(dir $@)
+	@ echo "SharedLibrary  : $(PRIVATE_NAME)"
+	$(hide) $(cmd-build-shared-library)
+
+ALL_SHARED_LIBRARIES += $(LOCAL_BUILT_MODULE)
+endif
+
+#
+# If this is an executable module
+#
+ifeq ($(call module-is-executable,$(LOCAL_MODULE)),$(true))
+$(LOCAL_BUILT_MODULE): $(LOCAL_OBJECTS)
+	@ mkdir -p $(dir $@)
+	@ echo "Executable     : $(PRIVATE_NAME)"
+	$(hide) $(cmd-build-executable)
+
+ALL_EXECUTABLES += $(LOCAL_BUILT_MODULE)
+endif
+
+#
+# If this is an installable module
+#
+ifeq ($(call module-is-installable,$(LOCAL_MODULE)),$(true))
+$(LOCAL_INSTALLED): PRIVATE_NAME    := $(notdir $(LOCAL_BUILT_MODULE))
+$(LOCAL_INSTALLED): PRIVATE_SRC     := $(LOCAL_BUILT_MODULE)
+$(LOCAL_INSTALLED): PRIVATE_DST_DIR := $(NDK_APP_DST_DIR)
+$(LOCAL_INSTALLED): PRIVATE_DST     := $(LOCAL_INSTALLED)
+
+$(LOCAL_INSTALLED): $(LOCAL_BUILT_MODULE) clean-installed-binaries
+	@ echo "Install        : $(PRIVATE_NAME) => $(PRIVATE_DST_DIR)"
+	$(hide) mkdir -p $(PRIVATE_DST_DIR)
+	$(hide) install -p $(PRIVATE_SRC) $(PRIVATE_DST)
+	$(hide) $(call cmd-strip, $(PRIVATE_DST))
+endif
diff --git a/build/core/build-executable.mk b/build/core/build-executable.mk
index 9d08f22..8c67384 100644
--- a/build/core/build-executable.mk
+++ b/build/core/build-executable.mk
@@ -18,8 +18,8 @@
 #
 
 LOCAL_BUILD_SCRIPT := BUILD_EXECUTABLE
-LOCAL_MODULE_CLASS := EXECUTABLE
 LOCAL_MAKEFILE     := $(local-makefile)
+LOCAL_IS_HOST_MODULE := false
 
 $(call check-defined-LOCAL_MODULE,$(LOCAL_BUILD_SCRIPT))
 $(call check-LOCAL_MODULE,$(LOCAL_MAKEFILE))
@@ -30,15 +30,4 @@
 LOCAL_BUILT_MODULE := $(call executable-path,$(LOCAL_MODULE))
 LOCAL_OBJS_DIR     := $(TARGET_OBJS)/$(LOCAL_MODULE)
 
-$(call module-add-executable,$(LOCAL_MODULE),$(LOCAL_BUILT_MODULE),$(LOCAL_MAKEFILE))
-
-include $(BUILD_SYSTEM)/build-binary.mk
-
-$(LOCAL_BUILT_MODULE): $(LOCAL_OBJECTS)
-	@ mkdir -p $(dir $@)
-	@ echo "Executable     : $(PRIVATE_NAME)"
-	$(hide) $(cmd-build-executable)
-
-ALL_EXECUTABLES += $(LOCAL_BUILT_MODULE)
-
-include $(BUILD_SYSTEM)/install-binary.mk
+$(call module-add-executable,$(LOCAL_MODULE))
diff --git a/build/core/build-module.mk b/build/core/build-module.mk
index 42db9ba..fca1371 100644
--- a/build/core/build-module.mk
+++ b/build/core/build-module.mk
@@ -18,19 +18,7 @@
 # This should be included from build-binary.mk
 #
 
-$(call assert-defined,LOCAL_MODULE_CLASS LOCAL_BUILD_SCRIPT LOCAL_BUILT_MODULE)
-
-# Check LOCAL_IS_HOST_MODULE and define 'my' as either HOST_ or TARGET_
-#
-LOCAL_IS_HOST_MODULE := $(strip $(LOCAL_IS_HOST_MODULE))
-ifdef LOCAL_IS_HOST_MODULE
-  ifneq ($(LOCAL_IS_HOST_MODULE),true)
-    $(call __ndk_log,$(LOCAL_PATH): LOCAL_IS_HOST_MODULE must be "true" or empty, not "$(LOCAL_IS_HOST_MODULE)")
-  endif
-  my := HOST_
-else
-  my := TARGET_
-endif
+$(call assert-defined,my LOCAL_BUILD_SCRIPT LOCAL_BUILT_MODULE)
 
 # Compute 'intermediates' which is the location where we're going to store
 # intermediate generated files like object (.o) files.
diff --git a/build/core/build-shared-library.mk b/build/core/build-shared-library.mk
index bb4a4b4..65de48e 100644
--- a/build/core/build-shared-library.mk
+++ b/build/core/build-shared-library.mk
@@ -18,7 +18,6 @@
 #
 
 LOCAL_BUILD_SCRIPT := BUILD_SHARED_LIBRARY
-LOCAL_MODULE_CLASS := SHARED_LIBRARY
 LOCAL_MAKEFILE     := $(local-makefile)
 
 $(call check-defined-LOCAL_MODULE,$(LOCAL_BUILD_SCRIPT))
@@ -30,15 +29,4 @@
 LOCAL_BUILT_MODULE := $(call shared-library-path,$(LOCAL_MODULE))
 LOCAL_OBJS_DIR     := $(TARGET_OBJS)/$(LOCAL_MODULE)
 
-$(call module-add-shared-library,$(LOCAL_MODULE),$(LOCAL_BUILT_MODULE),$(LOCAL_MAKEFILE))
-
-include $(BUILD_SYSTEM)/build-binary.mk
-
-$(LOCAL_BUILT_MODULE): $(LOCAL_OBJECTS)
-	@ mkdir -p $(dir $@)
-	@ echo "SharedLibrary  : $(PRIVATE_NAME)"
-	$(hide) $(cmd-build-shared-library)
-
-ALL_SHARED_LIBRARIES += $(LOCAL_BUILT_MODULE)
-
-include $(BUILD_SYSTEM)/install-binary.mk
+$(call module-add-shared-library,$(LOCAL_MODULE))
diff --git a/build/core/build-static-library.mk b/build/core/build-static-library.mk
index 157350a..c6c4b8b 100644
--- a/build/core/build-static-library.mk
+++ b/build/core/build-static-library.mk
@@ -18,7 +18,6 @@
 #
 
 LOCAL_BUILD_SCRIPT := BUILD_STATIC_LIBRARY
-LOCAL_MODULE_CLASS := STATIC_LIBRARY
 LOCAL_MAKEFILE     := $(local-makefile)
 
 $(call check-defined-LOCAL_MODULE,$(LOCAL_BUILD_SCRIPT))
@@ -30,14 +29,5 @@
 LOCAL_BUILT_MODULE := $(call static-library-path,$(LOCAL_MODULE))
 LOCAL_OBJS_DIR     := $(TARGET_OBJS)/$(LOCAL_MODULE)
 
-$(call module-add-static-library,$(LOCAL_MODULE),$(LOCAL_BUILT_MODULE),$(LOCAL_MAKEFILE))
+$(call module-add-static-library,$(LOCAL_MODULE))
 
-include $(BUILD_SYSTEM)/build-binary.mk
-
-$(LOCAL_BUILT_MODULE): $(LOCAL_OBJECTS)
-	@ mkdir -p $(dir $@)
-	@ echo "StaticLibrary  : $(PRIVATE_NAME)"
-	$(hide) rm -rf $@
-	$(hide) $(cmd-build-static-library)
-
-ALL_STATIC_LIBRARIES += $(LOCAL_BUILT_MODULE)
diff --git a/build/core/clear-vars.mk b/build/core/clear-vars.mk
index d093a13..e9ad319 100644
--- a/build/core/clear-vars.mk
+++ b/build/core/clear-vars.mk
@@ -16,26 +16,7 @@
 # this file is included repeatedly from Android.mk files in order to clean
 # the module-specific variables from the environment,
 
-NDK_LOCAL_VARS := \
-  LOCAL_MODULE \
-  LOCAL_SRC_FILES \
-  LOCAL_C_INCLUDES \
-  LOCAL_CFLAGS \
-  LOCAL_CXXFLAGS \
-  LOCAL_CPPFLAGS \
-  LOCAL_LDFLAGS \
-  LOCAL_LDLIBS \
-  LOCAL_ARFLAGS \
-  LOCAL_CPP_EXTENSION \
-  LOCAL_STATIC_LIBRARIES \
-  LOCAL_STATIC_WHOLE_LIBRARIES \
-  LOCAL_SHARED_LIBRARIES \
-  LOCAL_MAKEFILE \
-  LOCAL_ALLOW_UNDEFINED_SYMBOLS \
-  LOCAL_ARM_MODE \
-  LOCAL_ARM_NEON \
-  LOCAL_DISABLE_NO_EXECUTE \
-
 $(call clear-src-tags)
-$(call clear-vars, $(NDK_LOCAL_VARS))
 
+# Note: As a special exception, we don't want to clear LOCAL_PATH
+$(call clear-vars, $(filter-out LOCAL_PATH,$(modules-LOCALS:%=LOCAL_%)))
diff --git a/build/core/definitions.mk b/build/core/definitions.mk
index 0c9ad42..0d8ce50 100644
--- a/build/core/definitions.mk
+++ b/build/core/definitions.mk
@@ -129,18 +129,63 @@
 #    For each module 'foo', __ndk_modules.foo.<field> is used
 #    to store module-specific information.
 #
-#        android_mk   -> points to the Android.mk where the module is defined
 #        type         -> type of module (e.g. 'static', 'shared', ...)
-#        built        -> location of module built file (e.g. out/apps/<app>/<abi>/libfoo.so)
-#        installed    -> location of module installation (e.g. $PROJECT/libs/<abi>/libfoo.so)
 #        depends      -> list of other modules this module depends on
 #
+#    Also, LOCAL_XXXX values defined for a module are recorded in XXXX, e.g.:
+#
+#        PATH   -> recorded LOCAL_PATH for the module
+#        CFLAGS -> recorded LOCAL_CFLAGS for the module
+#        ...
+#
+#    Some of these are created by build scripts like BUILD_STATIC_LIBRARY:
+#
+#        MAKEFILE -> The Android.mk where the module is defined.
+#        LDFLAGS  -> Final linker flags
+#        OBJECTS  -> List of module objects
+#        BUILT_MODULE -> location of module built file (e.g. obj/<app>/<abi>/libfoo.so)
+#
 #    Note that some modules are never installed (e.g. static libraries).
 #
 # =============================================================================
 
+# The list of LOCAL_XXXX variables that are recorded for each module definition
+# These are documented by docs/ANDROID-MK.TXT. Exception is LOCAL_MODULE
+#
+modules-LOCALS := \
+    MODULE \
+    PATH \
+    SRC_FILES \
+    CPP_EXTENSION \
+    C_INCLUDES \
+    CFLAGS \
+    CXXFLAGS \
+    CPPFLAGS \
+    STATIC_LIBRARIES \
+    SHARED_LIBRARIES \
+    LDLIBS \
+    ALLOW_UNDEFINED_SYMBOLS \
+    ARM_MODE \
+    ARM_NEON \
+    DISABLE_NO_EXECUTE \
+    EXPORT_CFLAGS \
+    EXPORT_CPPFLAGS \
+    EXPORT_LDLIBS \
+    EXPORT_C_INCLUDES
+
+# The following are generated by the build scripts themselves
+modules-LOCALS += \
+    MAKEFILE \
+    LDFLAGS \
+    OBJECTS \
+    BUILT_MODULE \
+    OBJS_DIR \
+    IS_HOST_MODULE \
+    INSTALLED
+
 # the list of managed fields per module
-modules-fields = type android_mk built installed depends
+modules-fields = type depends \
+                 $(modules-LOCALS)
 
 # -----------------------------------------------------------------------------
 # Function : modules-clear
@@ -168,40 +213,58 @@
 # -----------------------------------------------------------------------------
 # Function : modules-add
 # Arguments: 1: module name
-#            2: built module path
-#            3: path to Android.mk where the module is defined
-#            4: type of module (e.g. 'static')
+#            2: type of module (e.g. 'static')
 # Returns  : None
 # Usage    : $(call modules-add,<modulename>,<Android.mk path>)
 # Rationale: add a new module. If it is already defined, print an error message
-#            and abort.
+#            and abort. This will record all LOCAL_XXX variables for the module.
 # -----------------------------------------------------------------------------
 module-add = \
+  $(call assert-defined,LOCAL_MAKEFILE LOCAL_BUILT_MODULE LOCAL_OBJS_DIR)\
   $(if $(call set_is_member,$(__ndk_modules),$1),\
-       $(call __ndk_info,Trying to define local module '$1' in $3.)\
-       $(call __ndk_info,But this module was already defined by $(__ndk_modules.$1.android_mk).)\
+       $(call __ndk_info,Trying to define local module '$1' in $(LOCAL_MAKEFILE).)\
+       $(call __ndk_info,But this module was already defined by $(__ndk_modules.$1.MAKEFILE).)\
        $(call __ndk_error,Aborting.)\
   )\
   $(eval __ndk_modules := $(call set_insert,$(__ndk_modules),$1))\
-  $(eval __ndk_modules.$1.android_mk := $3)\
-  $(eval __ndk_modules.$1.type       := $4)\
-  $(eval __ndk_modules.$1.built      := $2)\
+  $(eval __ndk_modules.$1.type := $2)\
+  $(foreach __local,$(modules-LOCALS),\
+    $(eval __ndk_modules.$1.$(__local) := $(LOCAL_$(__local)))\
+  )
 
-module-add-static-library = $(call module-add,$1,$2,$3,static)
-module-add-shared-library = $(call module-add,$1,$2,$3,shared)
-module-add-executable     = $(call module-add,$1,$2,$3,executable)
+module-add-static-library = $(call module-add,$1,static-library)
+
+module-add-shared-library = \
+    $(eval LOCAL_INSTALLED := $(NDK_APP_DST_DIR)/$(notdir $(LOCAL_BUILT_MODULE)))\
+    $(call module-add,$1,shared-library)
+
+module-add-executable = \
+    $(eval LOCAL_INSTALLED := $(NDK_APP_DST_DIR)/$(notdir $(LOCAL_BUILT_MODULE)))\
+    $(call module-add,$1,executable)
 
 # Returns $(true) iff module $1 is of type $2
 module-is-type = $(call seq,$(__ndk_modules.$1.type),$2)
 
 # Retrieve built location of module $1
-module-get-built = $(__ndk_modules.$1.built)
+module-get-built = $(__ndk_modules.$1.BUILT_MODULE)
 
 # Returns $(true) is module $1 is of a given type
-module-is-static-library = $(call module-is-type,$1,static)
-module-is-shared-library = $(call module-is-type,$1,shared)
+module-is-static-library = $(call module-is-type,$1,static-library)
+module-is-shared-library = $(call module-is-type,$1,shared-library)
 module-is-exectuable     = $(call module-is-type,$1,executable)
-module-is-installable    = $(call or,$(call module-is-type,$1,shared),$(call module-is-type,$1,executable))
+module-is-installable    = $(call or,$(call module-is-type,$1,shared-library),$(call module-is-type,$1,executable))
+
+# -----------------------------------------------------------------------------
+# Function : modules-restore-locals
+# Arguments: 1: module name
+# Returns  : None
+# Usage    : $(call module-restore-locals,<modulename>)
+# Rationale: Restore the recorded LOCAL_XXX definitions for a given module.
+# -----------------------------------------------------------------------------
+module-restore-locals = \
+    $(foreach __local,$(modules-LOCALS),\
+        $(eval LOCAL_$(__local) := $(__ndk_modules.$1.$(__local)))\
+    )
 
 # Dump all module information. Only use this for debugging
 modules-dump-database = \
@@ -245,25 +308,18 @@
 modules-add-depends-any = \
     $(eval __ndk_modules.$1.$3 += $(filter-out $(__ndk_modules.$1.$3),$(call strip-lib-prefix,$2)))
 
-# -----------------------------------------------------------------------------
-# Function : module-set-installed
-# Arguments: 1: module name
-#            2: installation path for the module
-# Returns  : None
-# Usage    : $(call module-set-installed,<module>,<installed>)
-# Rationale: Records the installed path of a given module. Can later be retrieved
-#            with module-get-installed.
-# -----------------------------------------------------------------------------
-module-set-installed = \
-    $(eval __ndk_modules.$1.installed := $2)
+# Used to recompute all dependencies once all module information has been recorded.
+#
+modules-compute-dependencies = \
+    $(foreach __module,$(__ndk_modules),\
+        $(call module-compute-depends,$(__module))\
+    )
 
-# -----------------------------------------------------------------------------
-# Function : module-get-installed
-# Arguments: 1: module name
-# Returns  : Path of installed locaiton
-# Usage    : $(call module-get-installed,<module>)
-# -----------------------------------------------------------------------------
-module-get-installed = $(__ndk_modules.$1.installed)
+module-compute-depends = \
+    $(call modules-add-static-depends,$1,$(call strip-lib-prefix,$(__ndk_modules.$1.STATIC_LIBRARIES)))\
+    $(call modules-add-shared-depends,$1,$(call strip-lib-prefix,$(__ndk_modules.$1.SHARED_LIBRARIES)))
+
+module-get-installed = $(__ndk_modules.$1.INSTALLED)
 
 # -----------------------------------------------------------------------------
 # Function : modules-get-all-dependencies
diff --git a/build/core/install-binary.mk b/build/core/install-binary.mk
deleted file mode 100644
index 0bc761a..0000000
--- a/build/core/install-binary.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2009 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# Installed module handling
-#
-LOCAL_INSTALLED_MODULE := $(NDK_APP_DST_DIR)/$(notdir $(LOCAL_BUILT_MODULE))
-
-$(LOCAL_INSTALLED_MODULE): PRIVATE_NAME    := $(notdir $(LOCAL_BUILT_MODULE))
-$(LOCAL_INSTALLED_MODULE): PRIVATE_SRC     := $(LOCAL_BUILT_MODULE)
-$(LOCAL_INSTALLED_MODULE): PRIVATE_DST_DIR := $(NDK_APP_DST_DIR)
-$(LOCAL_INSTALLED_MODULE): PRIVATE_DST     := $(LOCAL_INSTALLED_MODULE)
-
-$(LOCAL_INSTALLED_MODULE): $(LOCAL_BUILT_MODULE) clean-installed-binaries
-	@ echo "Install        : $(PRIVATE_NAME) => $(PRIVATE_DST_DIR)"
-	$(hide) mkdir -p $(PRIVATE_DST_DIR)
-	$(hide) install -p $(PRIVATE_SRC) $(PRIVATE_DST)
-	$(hide) $(call cmd-strip, $(PRIVATE_DST))
-
-# Record installation location for the module.
-$(call module-set-installed,$(LOCAL_MODULE),$(LOCAL_INSTALLED_MODULE))
diff --git a/build/core/setup-toolchain.mk b/build/core/setup-toolchain.mk
index 2dbeb73..1b73a33 100644
--- a/build/core/setup-toolchain.mk
+++ b/build/core/setup-toolchain.mk
@@ -110,9 +110,25 @@
 # free the dictionary of LOCAL_MODULE definitions
 $(call modules-clear)
 
-# now parse the Android.mk for the application
+# now parse the Android.mk for the application, this records all
+# module declarations, but does not populate the dependency graph yet.
 include $(NDK_APP_BUILD_SCRIPT)
 
+# recompute all dependencies between modules
+$(call modules-compute-dependencies)
+
+# for debugging purpose
+ifdef NDK_DEBUG_MODULES
+$(call modules-dump-database)
+endif
+
+# now, really build the modules, the second pass allows one to deal
+# with exported values
+$(foreach __pass2_module,$(__ndk_modules),\
+    $(eval LOCAL_MODULE := $(__pass2_module))\
+    $(eval include $(BUILD_SYSTEM)/build-binary.mk)\
+)
+
 # Now compute the closure of all module dependencies.
 #
 # If APP_MODULES is not defined in the Application.mk, we