Merge "Enable plugin for GCC 4.6"
diff --git a/build/core/build-binary.mk b/build/core/build-binary.mk
index 66ff928..1fa3021 100644
--- a/build/core/build-binary.mk
+++ b/build/core/build-binary.mk
@@ -282,21 +282,6 @@
#
# Handle the static and shared libraries this module depends on
#
-LOCAL_STATIC_LIBRARIES := $(call strip-lib-prefix,$(LOCAL_STATIC_LIBRARIES))
-LOCAL_WHOLE_STATIC_LIBRARIES := $(call strip-lib-prefix,$(LOCAL_WHOLE_STATIC_LIBRARIES))
-LOCAL_SHARED_LIBRARIES := $(call strip-lib-prefix,$(LOCAL_SHARED_LIBRARIES))
-
-# Transitive closure of static libraries
-LOCAL_STATIC_LIBRARIES := $(call module-get-depends,$(LOCAL_STATIC_LIBRARIES),STATIC_LIBRARIES)
-LOCAL_WHOLE_STATIC_LIBRARIES := $(call module-get-depends,$(LOCAL_WHOLE_STATIC_LIBRARIES),WHOLE_STATIC_LIBRARIES)
-
-static_libraries := $(call map,module-get-built,$(LOCAL_STATIC_LIBRARIES))
-whole_static_libraries := $(call map,module-get-built,$(LOCAL_WHOLE_STATIC_LIBRARIES))
-
-shared_libraries := $(call map,module-get-built,$(LOCAL_SHARED_LIBRARIES))\
- $(TARGET_PREBUILT_SHARED_LIBRARIES)
-
-$(LOCAL_BUILT_MODULE): $(static_libraries) $(whole_static_libraries) $(shared_libraries)
# If LOCAL_LDLIBS contains anything like -l<library> then
# prepend a -L$(SYSROOT)/usr/lib to it to ensure that the linker
@@ -306,20 +291,6 @@
LOCAL_LDLIBS := -L$(call host-path,$(SYSROOT)/usr/lib) $(LOCAL_LDLIBS)
endif
-# The list of object/static/shared libraries passed to the linker when
-# building shared libraries and executables. order is important.
-#
-# Cannot use immediate evaluation because PRIVATE_LIBGCC may not be defined at this point.
-linker_objects_and_libraries = $(strip $(call TARGET-get-linker-objects-and-libraries,\
- $(LOCAL_OBJECTS), \
- $(static_libraries), \
- $(whole_static_libraries), \
- $(shared_libraries)))
-
-# The list of object files sent to 'ar' when building static libraries
-#
-ar_objects := $(call host-path,$(LOCAL_OBJECTS))
-
# When LOCAL_SHORT_COMMANDS is defined to 'true' we are going to write the
# list of all object files and/or static/shared libraries that appear on the
# command line to a file, then use the @<listfile> syntax to invoke it.
@@ -331,39 +302,10 @@
ifndef LOCAL_SHORT_COMMANDS
LOCAL_SHORT_COMMANDS := $(strip $(NDK_APP_SHORT_COMMANDS))
endif
-ifeq ($(LOCAL_SHORT_COMMANDS),true)
- # For static and whole static libraries
- ifneq (,$(filter STATIC_LIBRARY WHOLE_STATIC_LIBRARY,$(call module-get-class,$(LOCAL_MODULE))))
- $(call ndk_log,Building static library module '$(LOCAL_MODULE)' with linker list file)
- ar_options := $(ar_objects)
- ar_list_file := $(LOCAL_OBJS_DIR)/archiver.list
- ar_objects := @$(call host-path,$(ar_list_file))
- $(call generate-list-file,$(ar_options),$(ar_list_file))
-
- $(LOCAL_BUILT_MODULE): $(ar_list_file)
- endif
-
- # For shared libraries and executables
- ifneq (,$(filter SHARED_LIBRARY EXECUTABLE,$(call module-get-class,$(LOCAL_MODULE))))
- $(call ndk_log,Building ELF binary module '$(LOCAL_MODULE)' with linker list file)
- linker_options := $(linker_objects_and_libraries)
- linker_list_file := $(LOCAL_OBJS_DIR)/linker.list
- linker_objects_and_libraries := @$(call host-path,$(linker_list_file))
-
- $(call generate-list-file,$(linker_options),$(linker_list_file))
-
- $(LOCAL_BUILT_MODULE): $(linker_list_file)
- endif
-
-endif
$(call generate-file-dir,$(LOCAL_BUILT_MODULE))
-$(LOCAL_BUILT_MODULE): PRIVATE_STATIC_LIBRARIES := $(static_libraries)
-$(LOCAL_BUILT_MODULE): PRIVATE_WHOLE_STATIC_LIBRARIES := $(whole_static_libraries)
-$(LOCAL_BUILT_MODULE): PRIVATE_SHARED_LIBRARIES := $(shared_libraries)
-$(LOCAL_BUILT_MODULE): PRIVATE_OBJECTS := $(LOCAL_OBJECTS)
-$(LOCAL_BUILT_MODULE): PRIVATE_LINKER_OBJECTS_AND_LIBRARIES := $(linker_objects_and_libraries)
+$(LOCAL_BUILT_MODULE): PRIVATE_OBJECTS := $(LOCAL_OBJECTS)
$(LOCAL_BUILT_MODULE): PRIVATE_LIBGCC := $(TARGET_LIBGCC)
$(LOCAL_BUILT_MODULE): PRIVATE_LD := $(TARGET_LD)
@@ -373,29 +315,137 @@
$(LOCAL_BUILT_MODULE): PRIVATE_NAME := $(notdir $(LOCAL_BUILT_MODULE))
$(LOCAL_BUILT_MODULE): PRIVATE_CXX := $(TARGET_CXX)
$(LOCAL_BUILT_MODULE): PRIVATE_CC := $(TARGET_CC)
-$(LOCAL_BUILT_MODULE): PRIVATE_AR := $(TARGET_AR) $(TARGET_ARFLAGS)
-$(LOCAL_BUILT_MODULE): PRIVATE_AR_OBJECTS := $(ar_objects)
$(LOCAL_BUILT_MODULE): PRIVATE_SYSROOT := $(SYSROOT)
-$(LOCAL_BUILT_MODULE): PRIVATE_BUILD_SHARED_LIB := $(cmd-build-shared-library)
-$(LOCAL_BUILT_MODULE): PRIVATE_BUILD_STATIC_LIB := $(cmd-build-static-library)
-$(LOCAL_BUILT_MODULE): PRIVATE_BUILD_EXECUTABLE := $(cmd-build-executable)
+
+ifeq ($(call module-get-class,$(LOCAL_MODULE)),STATIC_LIBRARY)
#
-# If this is a static library module
+# This is a static library module, things are very easy. We only need
+# to build the object files and archive them with 'ar'. Note that module
+# dependencies can be ignored here, i.e. if the module depends on other
+# static or shared libraries, there is no need to actually build them
+# before, so don't add Make dependencies to them.
#
-ifeq ($(call module-get-class,$(LOCAL_MODULE)),STATIC_LIBRARY)
+# In other words, consider the following graph:
+#
+# libfoo.so -> libA.a ->libB.a
+#
+# then libA.a and libB.a can be built in parallel, only linking libfoo.so
+# depends on their completion.
+#
+
+ar_objects := $(call host-path,$(LOCAL_OBJECTS))
+
+ifeq ($(LOCAL_SHORT_COMMANDS),true)
+ $(call ndk_log,Building static library module '$(LOCAL_MODULE)' with linker list file)
+ ar_list_file := $(LOCAL_OBJS_DIR)/archiver.list
+ $(call generate-list-file,$(ar_objects),$(ar_list_file))
+ ar_objects := @$(call host-path,$(ar_list_file))
+ $(LOCAL_BUILT_MODULE): $(ar_list_file)
+endif
+
+$(LOCAL_BUILT_MODULE): PRIVATE_AR := $(TARGET_AR) $(TARGET_ARFLAGS)
+$(LOCAL_BUILT_MODULE): PRIVATE_AR_OBJECTS := $(ar_objects)
+$(LOCAL_BUILT_MODULE): PRIVATE_BUILD_STATIC_LIB := $(cmd-build-static-library)
+
$(LOCAL_BUILT_MODULE): $(LOCAL_OBJECTS)
@ $(HOST_ECHO) "StaticLibrary : $(PRIVATE_NAME)"
$(hide) $(call host-rm,$@)
$(hide) $(PRIVATE_BUILD_STATIC_LIB)
ALL_STATIC_LIBRARIES += $(LOCAL_BUILT_MODULE)
+
+endif
+
+ifneq (,$(filter SHARED_LIBRARY EXECUTABLE,$(call module-get-class,$(LOCAL_MODULE))))
+
+#
+# This is a shared library or an executable, so computing dependencies properly is
+# crucial. The general rule to apply is the following:
+#
+# - collect the list of all static libraries that need to be part
+# of the link, and in the right order. To do so, get the transitive
+# closure of LOCAL_STATIC_LIBRARIES and LOCAL_WHOLE_STATIC_LIBRARIES
+# and ensure they are ordered topologically.
+#
+# - collect the list of all shared libraries that need to be part of
+# the link. This is the transitive closure of the list of
+# LOCAL_SHARED_LIBRARIES for the module and all its dependent static
+# libraries identified in the step above. Of course, need to be
+# ordered topologically too.
+#
+# - add Make dependencies to ensure that all these libs are built
+# before the module itself too.
+#
+# A few quick examples:
+#
+# main.exe -> libA.a -> libB.a -> libfoo.so -> libC.a
+#
+# static_libs(main.exe) = libA.a libB.a (i.e. no libC.a)
+# shared_libs(main.exe) = libfoo.so
+# static_libs(libfoo.so) = libC.a
+#
+# main.exe -> libA.a ---> libB.a
+# | ^
+# v |
+# libC.a ------
+#
+# static_libs(main.exe) = libA.a libC.a libB.a
+# (i.e. libB.a must appear after all libraries that depend on it).
+#
+all_libs := $(call module-get-link-libs,$(LOCAL_MODULE))
+shared_libs := $(call module-filter-shared-libraries,$(all_libs))
+static_libs := $(call module-filter-static-libraries,$(all_libs))
+whole_static_libs := $(call module-extract-whole-static-libs,$(LOCAL_MODULE),$(static_libs))
+static_libs := $(filter-out $(whole_static_libs),$(static_libs))
+
+$(call -ndk-mod-debug,module $(LOCAL_MODULE) [$(LOCAL_BUILT_MODULE)])
+$(call -ndk-mod-debug,. all_libs='$(all_libs)')
+$(call -ndk-mod-debug,. shared_libs='$(shared_libs)')
+$(call -ndk-mod-debug,. static_libs='$(static_libs)')
+$(call -ndk-mod-debug,. whole_static_libs='$(whole_static_libs)')
+
+shared_libs := $(call map,module-get-built,$(shared_libs))\
+ $(TARGET_PREBUILT_SHARED_LIBRARIES)
+static_libs := $(call map,module-get-built,$(static_libs))
+whole_static_libs := $(call map,module-get-built,$(whole_static_libs))
+
+$(call -ndk-mod-debug,. built_shared_libs='$(shared_libs)')
+$(call -ndk-mod-debug,. built_static_libs='$(static_libs)')
+$(call -ndk-mod-debug,. built_whole_static_libs='$(whole_static_libs)')
+
+ifeq ($(LOCAL_SHORT_COMMANDS),true)
+ $(call ndk_log,Building ELF binary module '$(LOCAL_MODULE)' with linker list file)
+ linker_options := $(linker_objects_and_libraries)
+ linker_list_file := $(LOCAL_OBJS_DIR)/linker.list
+ linker_objects_and_libraries := @$(call host-path,$(linker_list_file))
+ $(call generate-list-file,$(linker_options),$(linker_list_file))
+ $(LOCAL_BUILT_MODULE): $(linker_list_file)
+endif
+
+# The list of object/static/shared libraries passed to the linker when
+# building shared libraries and executables. order is important.
+#
+# Cannot use immediate evaluation because PRIVATE_LIBGCC may not be defined at this point.
+linker_objects_and_libraries = $(strip $(call TARGET-get-linker-objects-and-libraries,\
+ $(LOCAL_OBJECTS), \
+ $(static_libs), \
+ $(whole_static_libs), \
+ $(shared_libs)))
+
+$(LOCAL_BUILT_MODULE): $(shared_libs) $(static_libs) $(whole_static_libs)
+$(LOCAL_BUILT_MODULE): PRIVATE_LINKER_OBJECTS_AND_LIBRARIES := $(linker_objects_and_libraries)
+$(LOCAL_BUILT_MODULE): PRIVATE_STATIC_LIBRARIES := $(static_libs)
+$(LOCAL_BUILT_MODULE): PRIVATE_WHOLE_STATIC_LIBRARIES := $(whole_static_libs))
+$(LOCAL_BUILT_MODULE): PRIVATE_SHARED_LIBRARIES := $(shared_libs))
+
endif
#
# If this is a shared library module
#
ifeq ($(call module-get-class,$(LOCAL_MODULE)),SHARED_LIBRARY)
+$(LOCAL_BUILT_MODULE): PRIVATE_BUILD_SHARED_LIB := $(cmd-build-shared-library)
$(LOCAL_BUILT_MODULE): $(LOCAL_OBJECTS)
@ $(HOST_ECHO) "SharedLibrary : $(PRIVATE_NAME)"
$(hide) $(PRIVATE_BUILD_SHARED_LIB)
@@ -407,6 +457,7 @@
# If this is an executable module
#
ifeq ($(call module-get-class,$(LOCAL_MODULE)),EXECUTABLE)
+$(LOCAL_BUILT_MODULE): PRIVATE_BUILD_EXECUTABLE := $(cmd-build-executable)
$(LOCAL_BUILT_MODULE): $(LOCAL_OBJECTS)
@ $(HOST_ECHO) "Executable : $(PRIVATE_NAME)"
$(hide) $(PRIVATE_BUILD_EXECUTABLE)
diff --git a/build/core/definitions-graph.mk b/build/core/definitions-graph.mk
new file mode 100644
index 0000000..6652a1f
--- /dev/null
+++ b/build/core/definitions-graph.mk
@@ -0,0 +1,523 @@
+# Copyright (C) 2012 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.
+#
+# Definitions of various graph-related generic functions, used by
+# ndk-build internally.
+#
+
+# Coding style note:
+#
+# All internal variables in this file begin with '_ndk_mod_'
+# All internal functions in this file begin with '-ndk-mod-'
+#
+
+# Set this to true if you want to debug the functions here.
+_ndk_mod_debug := $(if $(NDK_DEBUG_MODULES),true)
+_ndk_topo_debug := $(if $(NDK_DEBUG_TOPO),true)
+
+# Use $(call -ndk-mod-debug,<message>) to print a debug message only
+# if _ndk_mod_debug is set to 'true'. Useful for debugging the functions
+# available here.
+#
+ifeq (true,$(_ndk_mod_debug))
+-ndk-mod-debug = $(info $1)
+else
+-ndk-mod-debug := $(empty)
+endif
+
+ifeq (true,$(_ndk_topo_debug))
+-ndk-topo-debug = $(info $1)
+else
+-ndk-topo-debug = $(empty)
+endif
+
+#######################################################################
+# Filter a list of module with a predicate function
+# $1: list of module names.
+# $2: predicate function, will be called with $(call $2,<name>), if the
+# result is not empty, <name> will be added to the result.
+# Out: subset of input list, where each item passes the predicate.
+#######################################################################
+-ndk-mod-filter = $(strip \
+ $(foreach _ndk_mod_filter_n,$1,\
+ $(if $(call $2,$(_ndk_mod_filter_n)),$(_ndk_mod_filter_n))\
+ ))
+
+-test-ndk-mod-filter = \
+ $(eval -local-func = $$(call seq,foo,$$1))\
+ $(call test-expect,,$(call -ndk-mod-filter,,-local-func))\
+ $(call test-expect,foo,$(call -ndk-mod-filter,foo,-local-func))\
+ $(call test-expect,foo,$(call -ndk-mod-filter,foo bar,-local-func))\
+ $(call test-expect,foo foo,$(call -ndk-mod-filter,aaa foo bar foo,-local-func))\
+ $(eval -local-func = $$(call sne,foo,$$1))\
+ $(call test-expect,,$(call -ndk-mod-filter,,-local-func))\
+ $(call test-expect,,$(call -ndk-mod-filter,foo,-local-func))\
+ $(call test-expect,bar,$(call -ndk-mod-filter,foo bar,-local-func))\
+ $(call test-expect,aaa bar,$(call -ndk-mod-filter,aaa foo bar,-local-func))
+
+
+#######################################################################
+# Filter out a list of modules with a predicate function
+# $1: list of module names.
+# $2: predicate function, will be called with $(call $2,<name>), if the
+# result is not empty, <name> will be added to the result.
+# Out: subset of input list, where each item doesn't pass the predicate.
+#######################################################################
+-ndk-mod-filter-out = $(strip \
+ $(foreach _ndk_mod_filter_n,$1,\
+ $(if $(call $2,$(_ndk_mod_filter_n)),,$(_ndk_mod_filter_n))\
+ ))
+
+-test-ndk-mod-filter-out = \
+ $(eval -local-func = $$(call seq,foo,$$1))\
+ $(call test-expect,,$(call -ndk-mod-filter-out,,-local-func))\
+ $(call test-expect,,$(call -ndk-mod-filter-out,foo,-local-func))\
+ $(call test-expect,bar,$(call -ndk-mod-filter-out,foo bar,-local-func))\
+ $(call test-expect,aaa bar,$(call -ndk-mod-filter-out,aaa foo bar foo,-local-func))\
+ $(eval -local-func = $$(call sne,foo,$$1))\
+ $(call test-expect,,$(call -ndk-mod-filter-out,,-local-func))\
+ $(call test-expect,foo,$(call -ndk-mod-filter-out,foo,-local-func))\
+ $(call test-expect,foo,$(call -ndk-mod-filter-out,foo bar,-local-func))\
+ $(call test-expect,foo foo,$(call -ndk-mod-filter-out,aaa foo bar foo,-local-func))
+
+
+#######################################################################
+# Find the first item in a list that checks a valid predicate.
+# $1: list of names.
+# $2: predicate function, will be called with $(call $2,<name>), if the
+# result is not empty, <name> will be added to the result.
+# Out: subset of input list.
+#######################################################################
+-ndk-mod-find-first = $(firstword $(call -ndk-mod-filter,$1,$2))
+
+-test-ndk-mod-find-first.empty = \
+ $(eval -local-pred = $$(call seq,foo,$$1))\
+ $(call test-expect,,$(call -ndk-mod-find-first,,-local-pred))\
+ $(call test-expect,,$(call -ndk-mod-find-first,bar,-local-pred))
+
+-test-ndk-mod-find-first.simple = \
+ $(eval -local-pred = $$(call seq,foo,$$1))\
+ $(call test-expect,foo,$(call -ndk-mod-find-first,foo,-local-pred))\
+ $(call test-expect,foo,$(call -ndk-mod-find-first,aaa foo bar,-local-pred))\
+ $(call test-expect,foo,$(call -ndk-mod-find-first,aaa foo foo bar,-local-pred))
+
+########################################################################
+# Many tree walking operations require setting a 'visited' flag on
+# specific graph nodes. The following helper functions help implement
+# this while hiding details to the callers.
+#
+# Technical note:
+# _ndk_mod_tree_visited.<name> will be 'true' if the node was visited,
+# or empty otherwise.
+#
+# _ndk_mod_tree_visitors lists all visited nodes, used to clean all
+# _ndk_mod_tree_visited.<name> variables in -ndk-mod-tree-setup-visit.
+#
+#######################################################################
+
+# Call this before tree traversal.
+-ndk-mod-tree-setup-visit = \
+ $(foreach _ndk_mod_tree_visitor,$(_ndk_mod_tree_visitors),\
+ $(eval _ndk_mod_tree_visited.$$(_ndk_mod_tree_visitor) :=))\
+ $(eval _ndk_mod_tree_visitors :=)
+
+# Returns non-empty if a node was visited.
+-ndk-mod-tree-is-visited = \
+ $(_ndk_mod_tree_visited.$1)
+
+# Set the visited state of a node to 'true'
+-ndk-mod-tree-set-visited = \
+ $(eval _ndk_mod_tree_visited.$1 := true)\
+ $(eval _ndk_mod_tree_visitors += $1)
+
+########################################################################
+# Many graph walking operations require a work queue and computing
+# dependencies / children nodes. Here are a few helper functions that
+# can be used to make their code clearer. This uses a few global
+# variables that should be defined as follows during the operation:
+#
+# _ndk_mod_module current graph node name.
+# _ndk_mod_wq current node work queue.
+# _ndk_mod_list current result (list of nodes).
+# _ndk_mod_depends current graph node's children.
+# you must call -ndk-mod-get-depends to set this.
+#
+#######################################################################
+
+# Pop first item from work-queue into _ndk_mod_module.
+-ndk-mod-pop-first = \
+ $(eval _ndk_mod_module := $$(call first,$$(_ndk_mod_wq)))\
+ $(eval _ndk_mod_wq := $$(call rest,$$(_ndk_mod_wq)))
+
+-test-ndk-mod-pop-first = \
+ $(eval _ndk_mod_wq := A B C)\
+ $(call -ndk-mod-pop-first)\
+ $(call test-expect,A,$(_ndk_mod_module))\
+ $(call test-expect,B C,$(_ndk_mod_wq))\
+
+
+# Push list of items at the back of the work-queue.
+-ndk-mod-push-back = \
+ $(eval _ndk_mod_wq := $(strip $(_ndk_mod_wq) $1))
+
+-test-ndk-mod-push-back = \
+ $(eval _ndk_mod_wq := A B C)\
+ $(call -ndk-mod-push-back, D E)\
+ $(call test-expect,A B C D E,$(_ndk_mod_wq))
+
+# Set _ndk_mod_depends to the direct dependencies of _ndk_mod_module
+-ndk-mod-get-depends = \
+ $(eval _ndk_mod_depends := $$(call $$(_ndk_mod_deps_func),$$(_ndk_mod_module)))
+
+# Set _ndk_mod_depends to the direct dependencies of _ndk_mod_module that
+# are not already in _ndk_mod_list.
+-ndk-mod-get-new-depends = \
+ $(call -ndk-mod-get-depends)\
+ $(eval _ndk_mod_depends := $$(filter-out $$(_ndk_mod_list),$$(_ndk_mod_depends)))
+
+##########################################################################
+# Compute the transitive closure
+# $1: list of modules.
+# $2: dependency function, $(call $2,<module>) should return all the
+# module that <module> depends on.
+# Out: transitive closure of all modules from those in $1. Always includes
+# the modules in $1. Order is random.
+#
+# Implementation note:
+# we use the -ndk-mod-tree-xxx functions to flag 'visited' nodes
+# in the graph. A node is visited once it has been put into the work
+# queue. For each item in the work queue, get the dependencies and
+# append all those that were not visited yet.
+#######################################################################
+-ndk-mod-get-closure = $(strip \
+ $(eval _ndk_mod_wq :=)\
+ $(eval _ndk_mod_list :=)\
+ $(eval _ndk_mod_deps_func := $2)\
+ $(call -ndk-mod-tree-setup-visit)\
+ $(foreach _ndk_mod_module,$1,\
+ $(call -ndk-mod-closure-visit,$(_ndk_mod_module))\
+ )\
+ $(call -ndk-mod-closure-recursive)\
+ $(eval _ndk_mod_deps :=)\
+ $(_ndk_mod_list)\
+ )
+
+# Used internally to visit a new node during -ndk-mod-get-closure.
+# This appends the node to the work queue, and set its 'visit' flag.
+-ndk-mod-closure-visit = \
+ $(call -ndk-mod-push-back,$1)\
+ $(call -ndk-mod-tree-set-visited,$1)
+
+-ndk-mod-closure-recursive = \
+ $(call -ndk-mod-pop-first)\
+ $(eval _ndk_mod_list += $$(_ndk_mod_module))\
+ $(call -ndk-mod-get-depends)\
+ $(foreach _ndk_mod_dep,$(_ndk_mod_depends),\
+ $(if $(call -ndk-mod-tree-is-visited,$(_ndk_mod_dep)),,\
+ $(call -ndk-mod-closure-visit,$(_ndk_mod_dep))\
+ )\
+ )\
+ $(if $(_ndk_mod_wq),$(call -ndk-mod-closure-recursive))
+
+-test-ndk-mod-get-closure.empty = \
+ $(eval -local-deps = $$($$1_depends))\
+ $(call test-expect,,$(call -ndk-mod-get-closure,,-local-deps))
+
+-test-ndk-mod-get-closure.single = \
+ $(eval -local-deps = $$($$1_depends))\
+ $(eval A_depends :=)\
+ $(call test-expect,A,$(call -ndk-mod-get-closure,A,-local-deps))
+
+-test-ndk-mod-get-closure.double = \
+ $(eval -local-deps = $$($$1_depends))\
+ $(eval A_depends := B)\
+ $(eval B_depends :=)\
+ $(call test-expect,A B,$(call -ndk-mod-get-closure,A,-local-deps))
+
+-test-ndk-mod-get-closure.circular-deps = \
+ $(eval -local-deps = $$($$1_depends))\
+ $(eval A_depends := B)\
+ $(eval B_depends := C)\
+ $(eval C_depends := A)\
+ $(call test-expect,A B C,$(call -ndk-mod-get-closure,A,-local-deps))
+
+-test-ndk-mod-get-closure.ABCDE = \
+ $(eval -local-deps = $$($$1_depends))\
+ $(eval A_depends := B C)\
+ $(eval B_depends := D)\
+ $(eval C_depends := D E)\
+ $(eval D_depends :=)\
+ $(eval E_depends :=)\
+ $(call test-expect,A B C D E,$(call -ndk-mod-get-closure,A,-local-deps))
+
+
+#########################################################################
+# For topological sort, we need to count the number of incoming edges
+# in each graph node. The following helper functions implement this and
+# hide implementation details.
+#
+# Count the number of incoming edges for each node during topological
+# sort with a string of xxxxs. I.e.:
+# 0 edge -> ''
+# 1 edge -> 'x'
+# 2 edges -> 'xx'
+# 3 edges -> 'xxx'
+# etc.
+#########################################################################
+
+# zero the incoming edge counter for module $1
+-ndk-mod-topo-zero-incoming = \
+ $(eval _ndk_mod_topo_incoming.$1 :=)
+
+# increment the incoming edge counter for module $1
+-ndk-mod-topo-increment-incoming = \
+ $(eval _ndk_mod_topo_incoming.$1 := $$(_ndk_mod_topo_incoming.$1)x)
+
+# decrement the incoming edge counter for module $1
+-ndk-mod-topo-decrement-incoming = \
+ $(eval _ndk_mod_topo_incoming.$1 := $$(_ndk_mod_topo_incoming.$1:%x=%))
+
+# return non-empty if the module $1's incoming edge counter is > 0
+-ndk-mod-topo-has-incoming = $(_ndk_mod_topo_incoming.$1)
+
+# Find first node in a list that has zero incoming edges.
+# $1: list of nodes
+# Out: first node that has zero incoming edges, or empty.
+-ndk-mod-topo-find-first-zero-incoming = $(firstword $(call -ndk-mod-filter-out,$1,-ndk-mod-topo-has-incoming))
+
+# Only use for debugging:
+-ndk-mod-topo-dump-count = \
+ $(foreach _ndk_mod_module,$1,\
+ $(info .. $(_ndk_mod_module) incoming='$(_ndk_mod_topo_incoming.$(_ndk_mod_module))'))
+
+
+
+#########################################################################
+# Return the topologically ordered closure of all nodes from a top-level
+# one. This means that a node A, in the result, will always appear after
+# node B if A depends on B. Assumes that the graph is a DAG (if there are
+# circular dependencies, this property cannot be guaranteed, but at least
+# the function should not loop infinitely).
+#
+# $1: top-level node name.
+# $2: dependency function, i.e. $(call $2,<name>) returns the children
+# nodes for <name>.
+# Return: list of nodes, include $1, which will always be the first.
+#########################################################################
+-ndk-mod-get-topo-list = $(strip \
+ $(eval _ndk_mod_top_module := $1)\
+ $(eval _ndk_mod_deps_func := $2)\
+ $(eval _ndk_mod_nodes := $(call -ndk-mod-get-closure,$1,$2))\
+ $(call -ndk-mod-topo-count,$(_ndk_mod_nodes))\
+ $(eval _ndk_mod_list :=)\
+ $(eval _ndk_mod_wq := $(call -ndk-mod-topo-find-first-zero-incoming,$(_ndk_mod_nodes)))\
+ $(if $(_ndk_mod_wq),\
+ $(call -ndk-mod-topo-sort)\
+ $(_ndk_mod_list)\
+ ,\
+ $(_ndk_mod_nodes)\
+ ))
+
+# Given a closure list of nodes, count their incoming edges.
+# $1: list of nodes, must be a graph closure.
+-ndk-mod-topo-count = \
+ $(foreach _ndk_mod_module,$1,\
+ $(call -ndk-mod-topo-zero-incoming,$(_ndk_mod_module)))\
+ $(foreach _ndk_mod_module,$1,\
+ $(call -ndk-mod-get-depends)\
+ $(foreach _ndk_mod_dep,$(_ndk_mod_depends),\
+ $(call -ndk-mod-topo-increment-incoming,$(_ndk_mod_dep))\
+ )\
+ )
+
+-ndk-mod-topo-sort = \
+ $(call -ndk-topo-debug,-ndk-mod-topo-sort: wq='$(_ndk_mod_wq)' list='$(_ndk_mod_list)')\
+ $(call -ndk-mod-pop-first)\
+ $(if $(_ndk_mod_module),\
+ $(eval _ndk_mod_list += $(_ndk_mod_module))\
+ $(call -ndk-mod-topo-decrement-incoming,$(_ndk_mod_module))\
+ $(call -ndk-mod-get-depends)\
+ $(call -ndk-topo-debug,-ndk-mod-topo-sort: deps='$(_ndk_mod_depends)')\
+ $(foreach _ndk_mod_dep,$(_ndk_mod_depends),\
+ $(call -ndk-mod-topo-decrement-incoming,$(_ndk_mod_dep))\
+ $(if $(call -ndk-mod-topo-has-incoming,$(_ndk_mod_dep)),,\
+ $(call -ndk-mod-push-back,$(_ndk_mod_dep))\
+ )\
+ )\
+ $(call -ndk-mod-topo-sort)\
+ )
+
+
+-test-ndk-mod-get-topo-list.empty = \
+ $(eval -local-deps = $$($$1_depends))\
+ $(call test-expect,,$(call -ndk-mod-get-topo-list,,-local-deps))
+
+-test-ndk-mod-get-topo-list.single = \
+ $(eval -local-deps = $$($$1_depends))\
+ $(eval A_depends :=)\
+ $(call test-expect,A,$(call -ndk-mod-get-topo-list,A,-local-deps))
+
+-test-ndk-mod-get-topo-list.no-infinite-loop = \
+ $(eval -local-deps = $$($$1_depends))\
+ $(eval A_depends := B)\
+ $(eval B_depends := C)\
+ $(eval C_depends := A)\
+ $(call test-expect,A B C,$(call -ndk-mod-get-topo-list,A,-local-deps))
+
+-test-ndk-mod-get-topo-list.ABC = \
+ $(eval -local-deps = $$($$1_depends))\
+ $(eval A_depends := B C)\
+ $(eval B_depends :=)\
+ $(eval C_depends := B)\
+ $(call test-expect,A C B,$(call -ndk-mod-get-topo-list,A,-local-deps))
+
+-test-ndk-mod-get-topo-list.ABCD = \
+ $(eval -local-deps = $$($$1_depends))\
+ $(eval A_depends := B C)\
+ $(eval B_depends := D)\
+ $(eval C_depends := B)\
+ $(eval D_depends :=)\
+ $(call test-expect,A C B D,$(call -ndk-mod-get-topo-list,A,-local-deps))
+
+#########################################################################
+# Return the topologically ordered closure of all dependencies from a
+# top-level node.
+#
+# $1: top-level node name.
+# $2: dependency function, i.e. $(call $2,<name>) returns the children
+# nodes for <name>.
+# Return: list of nodes, include $1, which will never be included.
+#########################################################################
+-ndk-mod-get-topological-depends = $(call rest,$(call -ndk-mod-get-topo-list,$1,$2))
+
+-test-ndk-mod-get-topological-depends.simple = \
+ $(eval -local-get-deps = $$($$1_depends))\
+ $(eval A_depends := B)\
+ $(eval B_depends :=)\
+ $(eval topo_deps := $$(call -ndk-mod-get-topological-depends,A,-local-get-deps))\
+ $(call test-expect,B,$(topo_deps),topo dependencies)
+
+-test-ndk-mod-get-topological-depends.ABC = \
+ $(eval -local-get-deps = $$($$1_depends))\
+ $(eval A_depends := B C)\
+ $(eval B_depends :=)\
+ $(eval C_depends := B)\
+ $(eval bfs_deps := $$(call -ndk-mod-get-bfs-depends,A,-local-get-deps))\
+ $(eval topo_deps := $$(call -ndk-mod-get-topological-depends,A,-local-get-deps))\
+ $(call test-expect,B C,$(bfs_deps),dfs dependencies)\
+ $(call test-expect,C B,$(topo_deps),topo dependencies)
+
+#########################################################################
+# Return breadth-first walk of a graph, starting from an arbitrary
+# node.
+#
+# This performs a breadth-first walk of the graph and will return a
+# list of nodes. Note that $1 will always be the first in the list.
+#
+# $1: root node name.
+# $2: dependency function, i.e. $(call $2,<name>) returns the nodes
+# that <name> depends on.
+# Result: list of dependent modules, $1 will be part of it.
+#########################################################################
+-ndk-mod-get-bfs-list = $(strip \
+ $(eval _ndk_mod_wq := $(call strip-lib-prefix,$1)) \
+ $(eval _ndk_mod_deps_func := $2)\
+ $(eval _ndk_mod_list :=)\
+ $(call -ndk-mod-tree-setup-visit)\
+ $(call -ndk-mod-tree-set-visited,$(_ndk_mod_wq))\
+ $(call -ndk-mod-bfs-recursive) \
+ $(_ndk_mod_list))
+
+# Recursive function used to perform a depth-first scan.
+# Must initialize _ndk_mod_list, _ndk_mod_field, _ndk_mod_wq
+# before calling this.
+-ndk-mod-bfs-recursive = \
+ $(call -ndk-mod-debug,-ndk-mod-bfs-recursive wq='$(_ndk_mod_wq)' list='$(_ndk_mod_list)' visited='$(_ndk_mod_tree_visitors)')\
+ $(call -ndk-mod-pop-first)\
+ $(eval _ndk_mod_list += $$(_ndk_mod_module))\
+ $(call -ndk-mod-get-depends)\
+ $(call -ndk-mod-debug,. node='$(_ndk_mod_module)' deps='$(_ndk_mod_depends)')\
+ $(foreach _ndk_mod_child,$(_ndk_mod_depends),\
+ $(if $(call -ndk-mod-tree-is-visited,$(_ndk_mod_child)),,\
+ $(call -ndk-mod-tree-set-visited,$(_ndk_mod_child))\
+ $(call -ndk-mod-push-back,$(_ndk_mod_child))\
+ )\
+ )\
+ $(if $(_ndk_mod_wq),$(call -ndk-mod-bfs-recursive))
+
+-test-ndk-mod-get-bfs-list.empty = \
+ $(eval -local-deps = $$($$1_depends))\
+ $(call test-expect,,$(call -ndk-mod-get-bfs-list,,-local-deps))
+
+-test-ndk-mod-get-bfs-list.A = \
+ $(eval -local-deps = $$($$1_depends))\
+ $(eval A_depends :=)\
+ $(call test-expect,A,$(call -ndk-mod-get-bfs-list,A,-local-deps))
+
+-test-ndk-mod-get-bfs-list.ABCDEF = \
+ $(eval -local-deps = $$($$1_depends))\
+ $(eval A_depends := B C)\
+ $(eval B_depends := D E)\
+ $(eval C_depends := F E)\
+ $(eval D_depends :=)\
+ $(eval E_depends :=)\
+ $(eval F_depends :=)\
+ $(call test-expect,A B C D E F,$(call -ndk-mod-get-bfs-list,A,-local-deps))
+
+#########################################################################
+# Return breadth-first walk of a graph, starting from an arbitrary
+# node.
+#
+# This performs a breadth-first walk of the graph and will return a
+# list of nodes. Note that $1 will _not_ be part of the list.
+#
+# $1: root node name.
+# $2: dependency function, i.e. $(call $2,<name>) returns the nodes
+# that <name> depends on.
+# Result: list of dependent modules, $1 will not be part of it.
+#########################################################################
+-ndk-mod-get-bfs-depends = $(call rest,$(call -ndk-mod-get-bfs-list,$1,$2))
+
+-test-ndk-mod-get-bfs-depends.simple = \
+ $(eval -local-deps-func = $$($$1_depends))\
+ $(eval A_depends := B)\
+ $(eval B_depends :=)\
+ $(eval deps := $$(call -ndk-mod-get-bfs-depends,A,-local-deps-func))\
+ $(call test-expect,B,$(deps))
+
+-test-ndk-mod-get-bfs-depends.ABC = \
+ $(eval -local-deps-func = $$($$1_depends))\
+ $(eval A_depends := B C)\
+ $(eval B_depends :=)\
+ $(eval C_depends := B)\
+ $(eval deps := $$(call -ndk-mod-get-bfs-depends,A,-local-deps-func))\
+ $(call test-expect,B C,$(deps))\
+
+-test-ndk-mod-get-bfs-depends.ABCDE = \
+ $(eval -local-deps-func = $$($$1_depends))\
+ $(eval A_depends := B C)\
+ $(eval B_depends := D)\
+ $(eval C_depends := D E F)\
+ $(eval D_depends :=)\
+ $(eval E_depends :=)\
+ $(eval F_depends :=)\
+ $(eval deps := $$(call -ndk-mod-get-bfs-depends,A,-local-deps-func))\
+ $(call test-expect,B C D E F,$(deps))\
+
+-test-ndk-mod-get-bfs-depends.loop = \
+ $(eval -local-deps-func = $$($$1_depends))\
+ $(eval A_depends := B)\
+ $(eval B_depends := A)\
+ $(eval deps := $$(call -ndk-mod-get-bfs-depends,A,-local-deps-func))\
+ $(call test-expect,B,$(deps))
diff --git a/build/core/definitions-host.mk b/build/core/definitions-host.mk
new file mode 100644
index 0000000..c215687
--- /dev/null
+++ b/build/core/definitions-host.mk
@@ -0,0 +1,136 @@
+# 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.
+#
+
+# These definitions contain a few host-specific functions. I.e. they are
+# typically used to generate shell commands during the build and their
+# implementation will depend on the value of the HOST_OS variable.
+#
+
+# -----------------------------------------------------------------------------
+# Function : host-path
+# Arguments: 1: file path
+# Returns : file path, as understood by the host file system
+# Usage : $(call host-path,<path>)
+# Rationale: This function is used to translate Cygwin paths into
+# Cygwin-specific ones. On other platforms, it will just
+# return its argument.
+# -----------------------------------------------------------------------------
+ifeq ($(HOST_OS),cygwin)
+host-path = $(if $(strip $1),$(call cygwin-to-host-path,$1))
+else
+host-path = $1
+endif
+
+# -----------------------------------------------------------------------------
+# Function : host-rm
+# Arguments: 1: list of files
+# Usage : $(call host-rm,<files>)
+# Rationale: This function expands to the host-specific shell command used
+# to remove some files.
+# -----------------------------------------------------------------------------
+ifeq ($(HOST_OS),windows)
+host-rm = \
+ $(eval __host_rm_files := $(foreach __host_rm_file,$1,$(subst /,\,$(wildcard $(__host_rm_file)))))\
+ $(if $(__host_rm_files),del /f/q $(__host_rm_files) >NUL 2>NUL)
+else
+host-rm = rm -f $1
+endif
+
+# -----------------------------------------------------------------------------
+# Function : host-rmdir
+# Arguments: 1: list of files or directories
+# Usage : $(call host-rm,<files>)
+# Rationale: This function expands to the host-specific shell command used
+# to remove some files _and_ directories.
+# -----------------------------------------------------------------------------
+ifeq ($(HOST_OS),windows)
+host-rmdir = \
+ $(eval __host_rmdir_files := $(foreach __host_rmdir_file,$1,$(subst /,\,$(wildcard $(__host_rmdir_file)))))\
+ $(if $(__host_rmdir_files),del /f/s/q $(__host_rmdir_files) >NUL 2>NUL)
+else
+host-rmdir = rm -rf $1
+endif
+
+# -----------------------------------------------------------------------------
+# Function : host-mkdir
+# Arguments: 1: directory path
+# Usage : $(call host-mkdir,<path>
+# Rationale: This function expands to the host-specific shell command used
+# to create a path if it doesn't exist.
+# -----------------------------------------------------------------------------
+ifeq ($(HOST_OS),windows)
+host-mkdir = md $(subst /,\,"$1") >NUL 2>NUL || rem
+else
+host-mkdir = mkdir -p $1
+endif
+
+# -----------------------------------------------------------------------------
+# Function : host-cp
+# Arguments: 1: source file
+# 2: target file
+# Usage : $(call host-cp,<src-file>,<dst-file>)
+# Rationale: This function expands to the host-specific shell command used
+# to copy a single file
+# -----------------------------------------------------------------------------
+ifeq ($(HOST_OS),windows)
+host-cp = copy /b/y $(subst /,\,"$1" "$2") > NUL
+else
+host-cp = cp -f $1 $2
+endif
+
+# -----------------------------------------------------------------------------
+# Function : host-install
+# Arguments: 1: source file
+# 2: target file
+# Usage : $(call host-install,<src-file>,<dst-file>)
+# Rationale: This function expands to the host-specific shell command used
+# to install a file or directory, while preserving its timestamps
+# (if possible).
+# -----------------------------------------------------------------------------
+ifeq ($(HOST_OS),windows)
+host-install = copy /b/y $(subst /,\,"$1" "$2") > NUL
+else
+host-install = install -p $1 $2
+endif
+
+# -----------------------------------------------------------------------------
+# Function : host-c-includes
+# Arguments: 1: list of file paths (e.g. "foo bar")
+# Returns : list of include compiler options (e.g. "-Ifoo -Ibar")
+# Usage : $(call host-c-includes,<paths>)
+# Rationale: This function is used to translate Cygwin paths into
+# Cygwin-specific ones. On other platforms, it will just
+# return its argument.
+# -----------------------------------------------------------------------------
+ifeq ($(HOST_OS),cygwin)
+host-c-includes = $(patsubst %,-I%,$(call host-path,$1))
+else
+host-c-includes = $(1:%=-I%)
+endif
+
+# -----------------------------------------------------------------------------
+# Function : host-copy-if-differ
+# Arguments: 1: source file
+# 2: destination file
+# Usage : $(call host-copy-if-differ,<src-file>,<dst-file>)
+# Rationale: This function copy source file to destination file if contents are
+# different.
+# -----------------------------------------------------------------------------
+ifeq ($(HOST_OS),windows)
+host-copy-if-differ = $(HOST_CMP) -s $1 $2 > NUL || copy /b/y $(subst /,\,"$1" "$2") > NUL
+else
+host-copy-if-differ = $(HOST_CMP) -s $1 $2 > /dev/null 2>&1 || cp -f $1 $2
+endif
+
diff --git a/build/core/definitions-tests.mk b/build/core/definitions-tests.mk
new file mode 100644
index 0000000..074036b
--- /dev/null
+++ b/build/core/definitions-tests.mk
@@ -0,0 +1,106 @@
+# Copyright (C) 2012 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.
+#
+# Definitions for the Android NDK build system's internal unit tests.
+#
+
+#
+# A function which names begin with -test- (e.g. -test-foo) is assumed
+# to be an internal unit test. It will be run automatically by ndk-build
+# if NDK_UNIT_TESTS is defined in your environment.
+#
+# Each test should call one of the following functions that will
+# register a failure:
+#
+# $(call test-expect,<expected-value>,<actual-value>)
+#
+# This will check that <actual-value> is equal to <expected-value>.
+# If not, this will print an error message and increment the failure
+# counter.
+#
+# $(call test-assert,<expected-value>,<actual-value>)
+#
+# This is similar to test-expect, though it will abort the program
+# immediately after displaying an error message.
+#
+# Here's an example that checks that the 'filter' function works correctly:
+#
+# -test-filter = \
+# $(call test-expect,foo,$(filter bar,foo bar))
+#
+#
+
+-ndk-test-start = \
+ $(eval _test_name := $1)\
+ $(eval _test_list += $1)\
+ $(eval _test_failed :=)\
+ $(info [$1 RUN])
+
+# End current unit test.
+#
+-ndk-test-end = \
+ $(if $(_test_failed),\
+ $(info [$(_test_name) FAIL])$(error Aborting)\
+ $(eval _test_failures += $$(_test_name))\
+ ,\
+ $(info [$(_test_name) OK])\
+ )
+
+# Define NDK_UNIT_TESTS to 2 to dump each test-expect/assert check.
+#
+ifeq (2,$(NDK_UNIT_TESTS))
+-ndk-test-log = $(info . $(_test_name): $1)
+else
+-ndk-test-log = $(empty)
+endif
+
+test-expect = \
+ $(call -ndk-test-log,expect '$2' == '$1')\
+ $(if $(call sne,$1,$2),\
+ $(info ERROR <$(_test_name)>:$3)\
+ $(info . expected value:'$1')\
+ $(info . actual value: '$2')\
+ $(eval _test_failed := true)\
+ )
+
+test-assert = \
+ $(call -ndk-test-log,assert '$2' == '$1')\
+ $(if $(call sne,$1,$2),\
+ $(info ASSERT <$(_test_name)>:$3)\
+ $(info . expected value:'$1')\
+ $(info . actual value: '$2')\
+ $(eval _test_failed := true)\
+ $(error Aborting.)\
+ )
+
+# Run all the tests, i.e. all functions that are defined with a -test-
+# prefix will be called now in succession.
+ndk-run-all-tests = \
+ $(info ================= STARTING NDK-BUILD UNIT TESTS =================)\
+ $(eval _test_list :=)\
+ $(eval _test_failures :=)\
+ $(foreach _test,$(filter -test-%,$(.VARIABLES)),\
+ $(call -ndk-test-start,$(_test))\
+ $(call $(_test))\
+ $(call -ndk-test-end)\
+ )\
+ $(eval _test_count := $$(words $$(_test_list)))\
+ $(eval _test_fail_count := $$(words $$(_test_failures)))\
+ $(if $(_test_failures),\
+ $(info @@@@@@@@@@@ FAILED $(_test_fail_count) of $(_test_count) NDK-BUILD UNIT TESTS @@@@@@@)\
+ $(foreach _test_name,$(_test_failures),\
+ $(info . $(_test_name)))\
+ ,\
+ $(info =================== PASSED $(_test_count) NDK-BUILD UNIT TESTS =================)\
+ )
diff --git a/build/core/definitions-utils.mk b/build/core/definitions-utils.mk
new file mode 100644
index 0000000..0f24404
--- /dev/null
+++ b/build/core/definitions-utils.mk
@@ -0,0 +1,170 @@
+# 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.
+#
+
+# Common utility functions.
+#
+# NOTE: All the functions here should be purely functional, i.e. avoid
+# using global variables or depend on the file system / environment
+# variables. This makes testing easier.
+
+# -----------------------------------------------------------------------------
+# Macro : empty
+# Returns : an empty macro
+# Usage : $(empty)
+# -----------------------------------------------------------------------------
+empty :=
+
+# -----------------------------------------------------------------------------
+# Macro : space
+# Returns : a single space
+# Usage : $(space)
+# -----------------------------------------------------------------------------
+space := $(empty) $(empty)
+
+space4 := $(space)$(space)$(space)$(space)
+
+# -----------------------------------------------------------------------------
+# Function : remove-duplicates
+# Arguments: a list
+# Returns : the list with duplicate items removed, order is preserved.
+# Usage : $(call remove-duplicates, <LIST>)
+# Note : This is equivalent to the 'uniq' function provided by GMSL,
+# however this implementation is non-recursive and *much*
+# faster. It will also not explode the stack with a lot of
+# items like 'uniq' does.
+# -----------------------------------------------------------------------------
+remove-duplicates = $(strip \
+ $(eval __uniq_ret :=) \
+ $(foreach __uniq_item,$1,\
+ $(if $(findstring $(__uniq_item),$(__uniq_ret)),,\
+ $(eval __uniq_ret += $(__uniq_item))\
+ )\
+ )\
+ $(__uniq_ret))
+
+-test-remove-duplicates = \
+ $(call test-expect,,$(call remove-duplicates))\
+ $(call test-expect,foo bar,$(call remove-duplicates,foo bar))\
+ $(call test-expect,foo bar,$(call remove-duplicates,foo bar foo bar))\
+ $(call test-expect,foo bar,$(call remove-duplicates,foo foo bar bar bar))
+
+# -----------------------------------------------------------------------------
+# Function : clear-vars
+# Arguments: 1: list of variable names
+# 2: file where the variable should be defined
+# Returns : None
+# Usage : $(call clear-vars, VAR1 VAR2 VAR3...)
+# Rationale: Clears/undefines all variables in argument list
+# -----------------------------------------------------------------------------
+clear-vars = $(foreach __varname,$1,$(eval $(__varname) := $(empty)))
+
+# -----------------------------------------------------------------------------
+# Function : filter-by
+# Arguments: 1: list
+# 2: predicate function, will be called as $(call $2,<name>)
+# and it this returns a non-empty value, then <name>
+# will be appended to the result.
+# Returns : elements of $1 that satisfy the predicate function $2
+# -----------------------------------------------------------------------------
+filter-by = $(strip \
+ $(foreach __filter_by_n,$1,\
+ $(if $(call $2,$(__filter_by_n)),$(__filter_by_n))))
+
+-test-filter-by = \
+ $(eval -local-func = $$(call seq,foo,$$1))\
+ $(call test-expect,,$(call filter-by,,-local-func))\
+ $(call test-expect,foo,$(call filter-by,foo,-local-func))\
+ $(call test-expect,foo,$(call filter-by,foo bar,-local-func))\
+ $(call test-expect,foo foo,$(call filter-by,aaa foo bar foo,-local-func))\
+ $(eval -local-func = $$(call sne,foo,$$1))\
+ $(call test-expect,,$(call filter-by,,-local-func))\
+ $(call test-expect,,$(call filter-by,foo,-local-func))\
+ $(call test-expect,bar,$(call filter-by,foo bar,-local-func))\
+ $(call test-expect,aaa bar,$(call filter-by,aaa foo bar,-local-func))
+
+# -----------------------------------------------------------------------------
+# Function : filter-out-by
+# Arguments: 1: list
+# 2: predicate function, will be called as $(call $2,<name>)
+# and it this returns an empty value, then <name>
+# will be appended to the result.
+# Returns : elements of $1 that do not satisfy the predicate function $2
+# -----------------------------------------------------------------------------
+filter-out-by = $(strip \
+ $(foreach __filter_out_by_n,$1,\
+ $(if $(call $2,$(__filter_out_by_n)),,$(__filter_out_by_n))))
+
+-test-filter-out-by = \
+ $(eval -local-func = $$(call seq,foo,$$1))\
+ $(call test-expect,,$(call filter-out-by,,-local-func))\
+ $(call test-expect,,$(call filter-out-by,foo,-local-func))\
+ $(call test-expect,bar,$(call filter-out-by,foo bar,-local-func))\
+ $(call test-expect,aaa bar,$(call filter-out-by,aaa foo bar foo,-local-func))\
+ $(eval -local-func = $$(call sne,foo,$$1))\
+ $(call test-expect,,$(call filter-out-by,,-local-func))\
+ $(call test-expect,foo,$(call filter-out-by,foo,-local-func))\
+ $(call test-expect,foo,$(call filter-out-by,foo bar,-local-func))\
+ $(call test-expect,foo foo,$(call filter-out-by,aaa foo bar foo,-local-func))
+
+# -----------------------------------------------------------------------------
+# Function : find-first
+# Arguments: 1: list
+# 2: predicate function, will be called as $(call $2,<name>).
+# Returns : the first item of $1 that satisfies the predicate.
+# -----------------------------------------------------------------------------
+find-first = $(firstword $(call filter-by,$1,$2))
+
+-testfind-first.empty = \
+ $(eval -local-pred = $$(call seq,foo,$$1))\
+ $(call test-expect,,$(call find-first,,-local-pred))\
+ $(call test-expect,,$(call find-first,bar,-local-pred))
+
+-testfind-first.simple = \
+ $(eval -local-pred = $$(call seq,foo,$$1))\
+ $(call test-expect,foo,$(call find-first,foo,-local-pred))\
+ $(call test-expect,foo,$(call find-first,aaa foo bar,-local-pred))\
+ $(call test-expect,foo,$(call find-first,aaa foo foo bar,-local-pred))
+
+# -----------------------------------------------------------------------------
+# Function : parent-dir
+# Arguments: 1: path
+# Returns : Parent dir or path of $1, with final separator removed.
+# -----------------------------------------------------------------------------
+parent-dir = $(patsubst %/,%,$(dir $(1:%/=%)))
+
+-test-parent-dir = \
+ $(call test-expect,,$(call parent-dir))\
+ $(call test-expect,.,$(call parent-dir,foo))\
+ $(call test-expect,foo,$(call parent-dir,foo/bar))\
+ $(call test-expect,foo,$(call parent-dir,foo/bar/))
+
+# -----------------------------------------------------------------------------
+# Strip any 'lib' prefix in front of a given string.
+#
+# Function : strip-lib-prefix
+# Arguments: 1: module name
+# Returns : module name, without any 'lib' prefix if any
+# Usage : $(call strip-lib-prefix,$(LOCAL_MODULE))
+# -----------------------------------------------------------------------------
+strip-lib-prefix = $(1:lib%=%)
+
+-test-strip-lib-prefix = \
+ $(call test-expect,,$(call strip-lib-prefix,))\
+ $(call test-expect,foo,$(call strip-lib-prefix,foo))\
+ $(call test-expect,foo,$(call strip-lib-prefix,libfoo))\
+ $(call test-expect,nolibfoo,$(call strip-lib-prefix,nolibfoo))\
+ $(call test-expect,foolib,$(call strip-lib-prefix,foolib))\
+ $(call test-expect,foo bar,$(call strip-lib-prefix,libfoo libbar))
+
diff --git a/build/core/definitions.mk b/build/core/definitions.mk
index 8e3aaf0..f139aea 100644
--- a/build/core/definitions.mk
+++ b/build/core/definitions.mk
@@ -18,69 +18,10 @@
# We use the GNU Make Standard Library
include $(NDK_ROOT)/build/gmsl/gmsl
-# If NDK_TRACE is enabled then calls to the library functions are
-# traced to stdout using warning messages with their arguments
-
-ifdef NDK_TRACE
-__ndk_tr1 = $(warning $0('$1'))
-__ndk_tr2 = $(warning $0('$1','$2'))
-__ndk_tr3 = $(warning $0('$1','$2','$3'))
-else
-__ndk_tr1 :=
-__ndk_tr2 :=
-__ndk_tr3 :=
-endif
-
-# -----------------------------------------------------------------------------
-# Macro : empty
-# Returns : an empty macro
-# Usage : $(empty)
-# -----------------------------------------------------------------------------
-empty :=
-
-# -----------------------------------------------------------------------------
-# Macro : space
-# Returns : a single space
-# Usage : $(space)
-# -----------------------------------------------------------------------------
-space := $(empty) $(empty)
-
-space4 := $(space)$(space)$(space)$(space)
-
-# -----------------------------------------------------------------------------
-# Function : last2
-# Arguments: a list
-# Returns : the penultimate (next-to-last) element of a list
-# Usage : $(call last2, <LIST>)
-# -----------------------------------------------------------------------------
-last2 = $(word $(words $1), x $1)
-
-# -----------------------------------------------------------------------------
-# Function : last3
-# Arguments: a list
-# Returns : the antepenultimate (second-next-to-last) element of a list
-# Usage : $(call last3, <LIST>)
-# -----------------------------------------------------------------------------
-last3 = $(word $(words $1), x x $1)
-
-# -----------------------------------------------------------------------------
-# Function : remove-duplicates
-# Arguments: a list
-# Returns : the list with duplicate items removed, order is preserved.
-# Usage : $(call remove-duplicates, <LIST>)
-# Note : This is equivalent to the 'uniq' function provided by GMSL,
-# however this implementation is non-recursive and *much*
-# faster. It will also not explode the stack with a lot of
-# items like 'uniq' does.
-# -----------------------------------------------------------------------------
-remove-duplicates = $(strip \
- $(eval __uniq_ret :=) \
- $(foreach __uniq_item,$1,\
- $(if $(findstring $(__uniq_item),$(__uniq_ret)),,\
- $(eval __uniq_ret += $(__uniq_item))\
- )\
- )\
- $(__uniq_ret))
+include $(BUILD_SYSTEM)/definitions-tests.mk
+include $(BUILD_SYSTEM)/definitions-utils.mk
+include $(BUILD_SYSTEM)/definitions-host.mk
+include $(BUILD_SYSTEM)/definitions-graph.mk
# -----------------------------------------------------------------------------
# Macro : this-makefile
@@ -111,16 +52,6 @@
)
# -----------------------------------------------------------------------------
-# Function : clear-vars
-# Arguments: 1: list of variable names
-# 2: file where the variable should be defined
-# Returns : None
-# Usage : $(call clear-vars, VAR1 VAR2 VAR3...)
-# Rationale: Clears/undefines all variables in argument list
-# -----------------------------------------------------------------------------
-clear-vars = $(foreach __varname,$1,$(eval $(__varname) := $(empty)))
-
-# -----------------------------------------------------------------------------
# Function : check-required-vars
# Arguments: 1: list of variable names
# 2: file where the variable(s) should be defined
@@ -140,122 +71,6 @@
default-c++-extensions := .cc .cp .cxx .cpp .CPP .c++ .C
# -----------------------------------------------------------------------------
-# Function : host-path
-# Arguments: 1: file path
-# Returns : file path, as understood by the host file system
-# Usage : $(call host-path,<path>)
-# Rationale: This function is used to translate Cygwin paths into
-# Cygwin-specific ones. On other platforms, it will just
-# return its argument.
-# -----------------------------------------------------------------------------
-ifeq ($(HOST_OS),cygwin)
-host-path = $(if $(strip $1),$(call cygwin-to-host-path,$1))
-else
-host-path = $1
-endif
-
-# -----------------------------------------------------------------------------
-# Function : host-rm
-# Arguments: 1: list of files
-# Usage : $(call host-rm,<files>)
-# Rationale: This function expands to the host-specific shell command used
-# to remove some files.
-# -----------------------------------------------------------------------------
-ifeq ($(HOST_OS),windows)
-host-rm = \
- $(eval __host_rm_files := $(foreach __host_rm_file,$1,$(subst /,\,$(wildcard $(__host_rm_file)))))\
- $(if $(__host_rm_files),del /f/q $(__host_rm_files) >NUL 2>NUL)
-else
-host-rm = rm -f $1
-endif
-
-# -----------------------------------------------------------------------------
-# Function : host-rmdir
-# Arguments: 1: list of files or directories
-# Usage : $(call host-rm,<files>)
-# Rationale: This function expands to the host-specific shell command used
-# to remove some files _and_ directories.
-# -----------------------------------------------------------------------------
-ifeq ($(HOST_OS),windows)
-host-rmdir = \
- $(eval __host_rmdir_files := $(foreach __host_rmdir_file,$1,$(subst /,\,$(wildcard $(__host_rmdir_file)))))\
- $(if $(__host_rmdir_files),del /f/s/q $(__host_rmdir_files) >NUL 2>NUL)
-else
-host-rmdir = rm -rf $1
-endif
-
-# -----------------------------------------------------------------------------
-# Function : host-mkdir
-# Arguments: 1: directory path
-# Usage : $(call host-mkdir,<path>
-# Rationale: This function expands to the host-specific shell command used
-# to create a path if it doesn't exist.
-# -----------------------------------------------------------------------------
-ifeq ($(HOST_OS),windows)
-host-mkdir = md $(subst /,\,"$1") >NUL 2>NUL || rem
-else
-host-mkdir = mkdir -p $1
-endif
-
-# -----------------------------------------------------------------------------
-# Function : host-cp
-# Arguments: 1: source file
-# 2: target file
-# Usage : $(call host-cp,<src-file>,<dst-file>)
-# Rationale: This function expands to the host-specific shell command used
-# to copy a single file
-# -----------------------------------------------------------------------------
-ifeq ($(HOST_OS),windows)
-host-cp = copy /b/y $(subst /,\,"$1" "$2") > NUL
-else
-host-cp = cp -f $1 $2
-endif
-
-# -----------------------------------------------------------------------------
-# Function : host-install
-# Arguments: 1: source file
-# 2: target file
-# Usage : $(call host-install,<src-file>,<dst-file>)
-# Rationale: This function expands to the host-specific shell command used
-# to install a file or directory, while preserving its timestamps
-# (if possible).
-# -----------------------------------------------------------------------------
-ifeq ($(HOST_OS),windows)
-host-install = copy /b/y $(subst /,\,"$1" "$2") > NUL
-else
-host-install = install -p $1 $2
-endif
-
-# -----------------------------------------------------------------------------
-# Function : host-c-includes
-# Arguments: 1: list of file paths (e.g. "foo bar")
-# Returns : list of include compiler options (e.g. "-Ifoo -Ibar")
-# Usage : $(call host-c-includes,<paths>)
-# Rationale: This function is used to translate Cygwin paths into
-# Cygwin-specific ones. On other platforms, it will just
-# return its argument.
-# -----------------------------------------------------------------------------
-ifeq ($(HOST_OS),cygwin)
-host-c-includes = $(patsubst %,-I%,$(call host-path,$1))
-else
-host-c-includes = $(1:%=-I%)
-endif
-
-# -----------------------------------------------------------------------------
-# Function : copy-if-differ
-# Arguments: 1: source file
-# 2: destination file
-# Usage : $(call copy-if-differ,<src-file>,<dst-file>)
-# Rationale: This function copy source file to destination file if contents are
-# different.
-# -----------------------------------------------------------------------------
-ifeq ($(HOST_OS),windows)
-copy-if-differ = $(HOST_CMP) -s $1 $2 > NUL || copy /b/y $(subst /,\,"$1" "$2") > NUL
-else
-copy-if-differ = $(HOST_CMP) -s $1 $2 > /dev/null 2>&1 || cp -f $1 $2
-endif
-
-# -----------------------------------------------------------------------------
# Function : generate-dir
# Arguments: 1: directory path
# Returns : Generate a rule, but not dependency, to create a directory with
@@ -320,9 +135,27 @@
index-is-zero = $(filter 0 00 000 0000 00000 000000 0000000,$1)
bump-0-to-1 = $(if $(call index-is-zero,$1),1,$1)
+-test-bump-0-to-1 = \
+ $(call test-expect,$(call bump-0-to-1))\
+ $(call test-expect,1,$(call bump-0-to-1,0))\
+ $(call test-expect,1,$(call bump-0-to-1,1))\
+ $(call test-expect,2,$(call bump-0-to-1,2))\
+ $(call test-expect,1,$(call bump-0-to-1,00))\
+ $(call test-expect,1,$(call bump-0-to-1,000))\
+ $(call test-expect,1,$(call bump-0-to-1,0000))\
+ $(call test-expect,1,$(call bump-0-to-1,00000))\
+ $(call test-expect,1,$(call bump-0-to-1,000000))\
+ $(call test-expect,10,$(call bump-0-to-1,10))\
+ $(call test-expect,100,$(call bump-0-to-1,100))
+
# Same as $(wordlist ...) except the start index, if 0, is bumped to 1
index-word-list = $(wordlist $(call bump-0-to-1,$1),$2,$3)
+-test-index-word-list = \
+ $(call test-expect,,$(call index-word-list,1,1))\
+ $(call test-expect,a b,$(call index-word-list,0,2,a b c d))\
+ $(call test-expect,b c,$(call index-word-list,2,3,a b c d))\
+
# NOTE: With GNU Make $1 and $(1) are equivalent, which means
# that $10 is equivalent to $(1)0, and *not* $(10).
@@ -466,7 +299,7 @@
$(call list-file-maybe-gen-1000,5,$1)
$$(__list_file): $$(__list_file).tmp
- $$(hide) $$(call copy-if-differ,$$@.tmp,$$@)
+ $$(hide) $$(call host-copy-if-differ,$$@.tmp,$$@)
$$(hide) $$(call host-rm,$$@.tmp)
endef
@@ -487,6 +320,13 @@
link-whole-archives = $(if $(strip $1),$(call link-whole-archive-flags,$1))
link-whole-archive-flags = -Wl,--whole-archive $(call host-path,$1) -Wl,--no-whole-archive
+-test-link-whole-archive = \
+ $(call test-expect,,$(call link-whole-archives))\
+ $(eval _start := -Wl,--whole-archive)\
+ $(eval _end := -Wl,--no-whole-archive)\
+ $(call test-expect,$(_start) foo $(_end),$(call link-whole-archives,foo))\
+ $(call test-expect,$(_start) foo bar $(_end),$(call link-whole-archives,foo bar))
+
# =============================================================================
#
# Modules database
@@ -641,6 +481,8 @@
$(if $(call module-class-is-installable,$(LOCAL_MODULE_CLASS)),\
$(eval LOCAL_INSTALLED := $(NDK_APP_DST_DIR)/$(notdir $(LOCAL_BUILT_MODULE)))\
)\
+ $(foreach __field,STATIC_LIBRARIES WHOLE_STATIC_LIBRARIES SHARED_LIBRARIES,\
+ $(eval LOCAL_$(__field) := $(call strip-lib-prefix,$(LOCAL_$(__field)))))\
$(foreach __local,$(modules-LOCALS),\
$(eval __ndk_modules.$1.$(__local) := $(LOCAL_$(__local)))\
)\
@@ -704,7 +546,7 @@
# Dump all module information. Only use this for debugging
modules-dump-database = \
- $(info Modules: $(__ndk_modules)) \
+ $(info Modules [$(TARGET_ARCH_ABI)]: $(__ndk_modules)) \
$(foreach __mod,$(__ndk_modules),\
$(info $(space4)$(__mod):)\
$(foreach __field,$(modules-fields),\
@@ -751,7 +593,146 @@
# NOTE: this function must not modify the existing dependency order when new depends are added.
#
module-add-depends-any = \
- $(eval __ndk_modules.$1.$3 += $(filter-out $(__ndk_modules.$1.$3),$(call strip-lib-prefix,$2)))
+ $(eval __ndk_modules.$1.$3 += $(filter-out $(__ndk_modules.$1.$3),$2))
+
+
+# -----------------------------------------------------------------------------
+# Returns non-empty if a module is a static library
+# Arguments: 1: module name
+# Returns : non-empty iff the module is a static library.
+# Usage : $(if $(call module-is-static-library,<name>),...)
+# -----------------------------------------------------------------------------
+module-is-static-library = $(strip \
+ $(filter STATIC_LIBRARY PREBUILT_STATIC_LIBRARY,\
+ $(call module-get-class,$1)))
+
+# -----------------------------------------------------------------------------
+# Returns non-empty if a module is a shared library
+# Arguments: 1: module name
+# Returns : non-empty iff the module is a shared library.
+# Usage : $(if $(call module-is-shared-library,<name>),...)
+# -----------------------------------------------------------------------------
+module-is-shared-library = $(strip \
+ $(filter SHARED_LIBRARY PREBUILT_SHARED_LIBRARY,\
+ $(call module-get-class,$1)))
+
+# -----------------------------------------------------------------------------
+# Filter a list of module names to retain only the static libraries.
+# Arguments: 1: module name list
+# Returns : input list modules which are static libraries.
+# -----------------------------------------------------------------------------
+module-filter-static-libraries = $(call filter-by,$1,module-is-static-library)
+
+# -----------------------------------------------------------------------------
+# Filter a list of module names to retain only the shared libraries.
+# Arguments: 1: module name list
+# Returns : input list modules which are shared libraries.
+# -----------------------------------------------------------------------------
+module-filter-shared-libraries = $(call filter-by,$1,module-is-shared-library)
+
+# -----------------------------------------------------------------------------
+# Return the LOCAL_STATIC_LIBRARIES for a given module.
+# Arguments: 1: module name
+# Returns : List of static library modules.
+# -----------------------------------------------------------------------------
+module-get-static-libs = $(__ndk_modules.$1.STATIC_LIBRARIES)
+
+# -----------------------------------------------------------------------------
+# Return the LOCAL_WHOLE_STATIC_LIBRARIES for a given module.
+# Arguments: 1: module name
+# Returns : List of whole static library modules.
+# -----------------------------------------------------------------------------
+module-get-whole-static-libs = $(__ndk_modules.$1.WHOLE_STATIC_LIBRARIES)
+
+# -----------------------------------------------------------------------------
+# Return all static libraries for a given module.
+# Arguments: 1: module name
+# Returns : List of static library modules (whole or not).
+# -----------------------------------------------------------------------------
+module-get-all-static-libs = $(strip \
+ $(__ndk_modules.$1.STATIC_LIBRARIES) \
+ $(__ndk_modules.$1.WHOLE_STATIC_LIBRARIES))
+
+# -----------------------------------------------------------------------------
+# Return the list of LOCAL_SHARED_LIBRARIES for a given module.
+# Arguments: 1: module name
+# Returns : List of shared library modules.
+# -----------------------------------------------------------------------------
+module-get-shared-libs = $(__ndk_modules.$1.SHARED_LIBRARIES)
+
+# -----------------------------------------------------------------------------
+# Return the list of all libraries a modules depends directly on.
+# This is the concatenation of its LOCAL_STATIC_LIBRARIES,
+# LOCAL_WHOLE_STATIC_LIBRARIES, and LOCAL_SHARED_LIBRARIES variables.
+# Arguments: 1: module name
+# Returns : List of library modules (static or shared).
+# -----------------------------------------------------------------------------
+module-get-direct-libs = $(strip \
+ $(__ndk_modules.$1.STATIC_LIBRARIES) \
+ $(__ndk_modules.$1.WHOLE_STATIC_LIBRARIES) \
+ $(__ndk_modules.$1.SHARED_LIBRARIES))
+
+
+# -----------------------------------------------------------------------------
+# Computes the full closure of a module and its dependencies. Order is
+# defined by a breadth-first walk of the graph.
+# $1 will be the first item in the result.
+#
+# Arguments: 1: module name
+# Returns : List of all modules $1 depends on.
+#
+# Note: Do not use this to determine build dependencies. The returned list
+# is much too large for this. For example consider the following
+# dependency graph:
+#
+# main.exe -> libA.a -> libfoo.so -> libB.a
+#
+# This function will return all four modules in the result, while
+# at link time building main.exe only requires the first three.
+#
+# -----------------------------------------------------------------------------
+module-get-all-dependencies = $(call -ndk-mod-get-closure,$1,module-get-depends)
+
+# -----------------------------------------------------------------------------
+# Compute the list of all static and shared libraries required to link a
+# given module.
+#
+# Note that the result is topologically ordered, i.e. if library A depends
+# on library B, then A will always appear after B in the result.
+#
+# Arguments: 1: module name
+# Returns : List of all library $1 depends at link time.
+#
+# Note: This doesn't differentiate between regular and whole static
+# libraries. Use module-extract-whole-static-libs to filter the
+# result returned by this function.
+# -----------------------------------------------------------------------------
+module-get-link-libs = $(strip \
+ $(eval _ndk_mod_link_module := $1) \
+ $(call -ndk-mod-get-topological-depends,$1,-ndk-mod-link-deps))
+
+# Special dependency function used by nodule-get-link-libs.
+# The rules to follow are the following:
+# - if $1 is the link module, or if it is a static library, then all
+# direct dependencies.
+# - otherwise, the module is a shared library, don't add build deps.
+-ndk-mod-link-deps = \
+ $(if $(call seq,$1,$(_ndk_mod_link_module))$(call module-is-static-library,$1),\
+ $(call module-get-direct-libs,$1))
+
+# -----------------------------------------------------------------------------
+# This function is used to extract the list of static libraries that need
+# to be linked as whole, i.e. placed in a special section on the final
+# link command.
+# Arguments: $1: module name.
+# $2: list of all static link-time libraries (regular or whole).
+# Returns : list of static libraries from '$2' that need to be linked
+# as whole.
+# -----------------------------------------------------------------------------
+module-extract-whole-static-libs = $(strip \
+ $(eval _ndk_mod_whole_all := $(call map,module-get-whole-static-libs,$1 $2))\
+ $(eval _ndk_mod_whole_result := $(filter $(_ndk_mod_whole_all),$2))\
+ $(_ndk_mod_whole_result))
# Used to recompute all dependencies once all module information has been recorded.
#
@@ -767,47 +748,7 @@
module-get-installed = $(__ndk_modules.$1.INSTALLED)
-# -----------------------------------------------------------------------------
-# Function : modules-get-all-dependencies
-# Arguments: 1: list of module names
-# Returns : List of all the modules $1 depends on transitively.
-# Usage : $(call modules-all-get-dependencies,<list of module names>)
-# Rationale: This computes the closure of all module dependencies starting from $1
-# -----------------------------------------------------------------------------
-module-get-all-dependencies = $(strip \
- $(call modules-get-closure,$1,depends))
-
-modules-get-closure = \
- $(eval __closure_deps := $(strip $(call strip-lib-prefix,$1))) \
- $(eval __closure_wq := $(__closure_deps)) \
- $(eval __closure_field := $(strip $2)) \
- $(call modules-closure)\
- $(__closure_deps)
-
-# Used internally by modules-get-all-dependencies
-# Note the tricky use of conditional recursion to work around the fact that
-# the GNU Make language does not have any conditional looping construct
-# like 'while'.
-#
-modules-closure = \
- $(eval __closure_mod := $(call first,$(__closure_wq))) \
- $(eval __closure_wq := $(call rest,$(__closure_wq))) \
- $(eval __closure_val := $(call strip-lib-prefix,$(__ndk_modules.$(__closure_mod).$(__closure_field)))) \
- $(eval __closure_new := $(filter-out $(__closure_deps),$(__closure_val)))\
- $(eval __closure_deps += $(__closure_new)) \
- $(eval __closure_wq := $(strip $(__closure_wq) $(__closure_new)))\
- $(if $(__closure_wq),$(call modules-closure)) \
-
-# -----------------------------------------------------------------------------
-# Function : module-get-depends
-# Arguments: 1: list of module names
-# 2: local module type (e.g. SHARED_LIBRARIES)
-# Returns : List all the <local-type> modules $1 depends on transitively.
-# Usage : $(call module-get-depends,<list of module names>,<local-type>)
-# Rationale: This computes the closure of all local module dependencies starting from $1
-# -----------------------------------------------------------------------------
-module-get-depends = $(strip $(call modules-get-closure,$1,$2))
-
+module-get-depends = $(__ndk_modules.$1.depends)
# -----------------------------------------------------------------------------
# Function : modules-get-all-installable
@@ -818,7 +759,7 @@
# -----------------------------------------------------------------------------
# For now, only the closure of LOCAL_SHARED_LIBRARIES is enough
modules-get-all-installable = $(strip \
- $(foreach __alldep,$(call module-get-depends,$1,depends),\
+ $(foreach __alldep,$(call module-get-all-dependencies,$1),\
$(if $(call module-is-installable,$(__alldep)),$(__alldep))\
))
@@ -945,14 +886,6 @@
# =============================================================================
# -----------------------------------------------------------------------------
-# Function : parent-dir
-# Arguments: 1: path
-# Returns : Parent dir or path of $1, with final separator removed.
-# -----------------------------------------------------------------------------
-parent-dir = $(patsubst %/,%,$(dir $1))
-
-
-# -----------------------------------------------------------------------------
# Function : pretty-dir
# Arguments: 1: path
# Returns : Remove NDK_PROJECT_PATH prefix from a given path. This can be
@@ -961,6 +894,15 @@
pretty-dir = $(patsubst $(NDK_ROOT)/%,<NDK>/%,\
$(patsubst $(NDK_PROJECT_PATH)/%,%,$1))
+# Note: NDK_PROJECT_PATH is typically defined after this test is run.
+-test-pretty-dir = \
+ $(eval NDK_PROJECT_PATH ?= .)\
+ $(call test-expect,foo,$(call pretty-dir,foo))\
+ $(call test-expect,foo,$(call pretty-dir,$(NDK_PROJECT_PATH)/foo))\
+ $(call test-expect,foo/bar,$(call pretty-dir,$(NDK_PROJECT_PATH)/foo/bar))\
+ $(call test-expect,<NDK>/foo,$(call pretty-dir,$(NDK_ROOT)/foo))\
+ $(call test-expect,<NDK>/foo/bar,$(call pretty-dir,$(NDK_ROOT)/foo/bar))
+
# -----------------------------------------------------------------------------
# Function : check-user-define
# Arguments: 1: name of variable that must be defined by the user
@@ -1087,16 +1029,6 @@
$(eval LOCAL_OBJS_DIR := $(TARGET_OBJS)/$(LOCAL_MODULE))
# -----------------------------------------------------------------------------
-# Strip any 'lib' prefix in front of a given string.
-#
-# Function : strip-lib-prefix
-# Arguments: 1: module name
-# Returns : module name, without any 'lib' prefix if any
-# Usage : $(call strip-lib-prefix,$(LOCAL_MODULE))
-# -----------------------------------------------------------------------------
-strip-lib-prefix = $(1:lib%=%)
-
-# -----------------------------------------------------------------------------
# Compute the real path of a prebuilt file.
#
# Function : local-prebuilt-path
@@ -1338,6 +1270,13 @@
$(__obj)\
))
+-test-get-object-name = \
+ $(eval LOCAL_CPP_EXTENSION ?= .cpp)\
+ $(call test-expect,foo.o,$(call get-object-name,foo.c))\
+ $(call test-expect,bar.o,$(call get-object-name,bar.s))\
+ $(call test-expect,zoo.o,$(call get-object-name,zoo.S))\
+ $(call test-expect,tot.o,$(call get-object-name,tot.cpp))
+
# -----------------------------------------------------------------------------
# Macro : hide
# Returns : nothing
@@ -1762,8 +1701,8 @@
$(eval __ndk_stl := $(strip $1)) \
$(eval NDK_STL_LIST += $(__ndk_stl)) \
$(eval NDK_STL.$(__ndk_stl).IMPORT_MODULE := $(strip $2)) \
- $(eval NDK_STL.$(__ndk_stl).STATIC_LIBS := $(strip $3)) \
- $(eval NDK_STL.$(__ndk_stl).SHARED_LIBS := $(strip $4))
+ $(eval NDK_STL.$(__ndk_stl).STATIC_LIBS := $(strip $(call strip-lib-prefix,$3))) \
+ $(eval NDK_STL.$(__ndk_stl).SHARED_LIBS := $(strip $(call strip-lib-prefix,$4)))
# Called to check that the value of APP_STL is a valid one.
# $1: STL name as it apperas in APP_STL (e.g. 'system')
@@ -1857,3 +1796,7 @@
none,\
cxx-stl/system,\
)
+
+ifneq (,$(NDK_UNIT_TESTS))
+$(call ndk-run-all-tests)
+endif
diff --git a/tests/build/ndk-build-unit-tests/build.sh b/tests/build/ndk-build-unit-tests/build.sh
new file mode 100755
index 0000000..a1f0bb9
--- /dev/null
+++ b/tests/build/ndk-build-unit-tests/build.sh
@@ -0,0 +1,5 @@
+# This is used to check that the internal unit tests of ndk-build
+# work properly. Note that these only check internal Make functions
+# within the build system, not anything that tries to build something.
+cd $(dirname "$0")
+$NDK/ndk-build NDK_UNIT_TESTS=1 clean
diff --git a/tests/build/topological-sort/BROKEN_BUILD b/tests/build/ndk-build-unit-tests/jni/Android.mk
similarity index 100%
rename from tests/build/topological-sort/BROKEN_BUILD
rename to tests/build/ndk-build-unit-tests/jni/Android.mk
diff --git a/tests/build/topological-sort/jni/main.c b/tests/build/topological-sort/jni/main.c
index dcc85dc..3f20987 100644
--- a/tests/build/topological-sort/jni/main.c
+++ b/tests/build/topological-sort/jni/main.c
@@ -1,3 +1,5 @@
+#include <stdio.h>
+
#include "foo.h"
#include "bar.h"