Merge "Identify modules ready to be converted to Soong"
diff --git a/core/Makefile b/core/Makefile
index fa787b5..f9de658 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -395,6 +395,22 @@
$(call dist-for-goals,droidcore,$(BUILD_SYSTEM_STATS))
# -----------------------------------------------------------------
+# Modules ready to be converted to Soong, ordered by how many
+# modules depend on them.
+SOONG_CONV := $(sort $(SOONG_CONV))
+SOONG_CONV_DATA := $(call intermediates-dir-for,PACKAGING,soong_conversion)/soong_conv_data
+$(SOONG_CONV_DATA):
+ @rm -f $@
+ @$(foreach s,$(SOONG_CONV),echo "$(s),$(sort $(SOONG_CONV.$(s).PROBLEMS)),$(sort $(filter-out $(SOONG_ALREADY_CONV),$(SOONG_CONV.$(s).DEPS)))" >>$@;)
+
+SOONG_TO_CONVERT_SCRIPT := build/tools/soong_to_convert.py
+SOONG_TO_CONVERT := $(PRODUCT_OUT)/soong_to_convert.txt
+$(SOONG_TO_CONVERT): $(SOONG_CONV_DATA) $(SOONG_TO_CONVERT_SCRIPT)
+ @rm -f $@
+ $(hide) $(SOONG_TO_CONVERT_SCRIPT) $< >$@
+$(call dist-for-goals,droidcore,$(SOONG_TO_CONVERT))
+
+# -----------------------------------------------------------------
# The dev key is used to sign this package, and as the key required
# for future OTA packages installed by this system. Actual product
# deliverables will be re-signed by hand. We expect this file to
diff --git a/core/binary.mk b/core/binary.mk
index dc9fa4e..fb31890 100644
--- a/core/binary.mk
+++ b/core/binary.mk
@@ -30,6 +30,8 @@
endif
endif
+my_soong_problems :=
+
# The following LOCAL_ variables will be modified in this file.
# Because the same LOCAL_ variables may be used to define modules for both 1st arch and 2nd arch,
# we can't modify them in place.
@@ -416,6 +418,16 @@
endif
endif
+ifneq ($(filter ../%,$(my_src_files)),)
+my_soong_problems += dotdot_srcs
+endif
+ifneq ($(foreach i,$(my_c_includes),$(filter %/..,$(i))$(findstring /../,$(i))),)
+my_soong_problems += dotdot_incs
+endif
+ifneq ($(filter %.arm,$(my_src_files)),)
+my_soong_problems += srcs_dotarm
+endif
+
####################################################
## Add FDO flags if FDO is turned on and supported
## Please note that we will do option filtering during FDO build.
@@ -698,6 +710,7 @@
renderscript_sources := $(filter %.rs %.fs,$(my_src_files))
ifneq (,$(renderscript_sources))
+my_soong_problems += rs
renderscript_sources_fullpath := $(addprefix $(LOCAL_PATH)/, $(renderscript_sources))
RenderScript_file_stamp := $(intermediates)/RenderScriptCPP.stamp
@@ -777,6 +790,7 @@
###########################################################
proto_sources := $(filter %.proto,$(my_src_files))
ifneq ($(proto_sources),)
+my_soong_problems += proto
proto_gen_dir := $(generated_sources_dir)/proto
proto_sources_fullpath := $(addprefix $(LOCAL_PATH)/, $(proto_sources))
@@ -859,6 +873,7 @@
dbus_definitions := $(filter %.dbus-xml,$(my_src_files))
dbus_generated_headers :=
ifneq ($(dbus_definitions),)
+my_soong_problems += dbus
dbus_definition_paths := $(addprefix $(LOCAL_PATH)/,$(dbus_definitions))
dbus_service_config := $(filter %dbus-service-config.json,$(my_src_files))
@@ -914,6 +929,7 @@
aidl_src := $(strip $(filter %.aidl,$(my_src_files)))
aidl_gen_cpp :=
ifneq ($(aidl_src),)
+my_soong_problems += aidl
# Use the intermediates directory to avoid writing our own .cpp -> .o rules.
aidl_gen_cpp_root := $(intermediates)/aidl-generated/src
@@ -946,6 +962,7 @@
vts_src := $(strip $(filter %.vts,$(my_src_files)))
vts_gen_cpp :=
ifneq ($(vts_src),)
+my_soong_problems += vts
# Use the intermediates directory to avoid writing our own .cpp -> .o rules.
vts_gen_cpp_root := $(intermediates)/vts-generated/src
@@ -1208,6 +1225,7 @@
$(call track-src-file-obj,$(objc_sources),$(objc_objects))
ifneq ($(strip $(objc_objects)),)
+my_soong_problems += objc
$(objc_objects): $(intermediates)/%.o: $(TOPDIR)$(LOCAL_PATH)/%.m \
$(my_additional_dependencies)
$(transform-$(PRIVATE_HOST)m-to-o)
@@ -1223,6 +1241,7 @@
$(call track-src-file-obj,$(objcpp_sources),$(objcpp_objects))
ifneq ($(strip $(objcpp_objects)),)
+my_soong_problems += objc
$(objcpp_objects): $(intermediates)/%.o: $(TOPDIR)$(LOCAL_PATH)/%.mm \
$(my_additional_dependencies)
$(transform-$(PRIVATE_HOST)mm-to-o)
@@ -1737,3 +1756,15 @@
# Make sure export_includes gets generated when you are running mm/mmm
$(LOCAL_BUILT_MODULE) : | $(export_includes) $(my_link_type)
+
+ifneq ($(LOCAL_MODULE_MAKEFILE),$(SOONG_ANDROID_MK))
+SOONG_CONV.$(LOCAL_MODULE).PROBLEMS := \
+ $(SOONG_CONV.$(LOCAL_MODULE).PROBLEMS) $(my_soong_problems)
+SOONG_CONV.$(LOCAL_MODULE).DEPS := \
+ $(SOONG_CONV.$(LOCAL_MODULE).DEPS) \
+ $(my_static_libraries) \
+ $(my_whole_static_libraries) \
+ $(my_shared_libraries) \
+ $(my_system_shared_libraries)
+SOONG_CONV := $(SOONG_CONV) $(LOCAL_MODULE)
+endif
diff --git a/core/prebuilt_internal.mk b/core/prebuilt_internal.mk
index ea4e66b..997b9be 100644
--- a/core/prebuilt_internal.mk
+++ b/core/prebuilt_internal.mk
@@ -79,6 +79,12 @@
prebuilt_module_is_a_library :=
endif
+ifeq ($(LOCAL_MODULE_MAKEFILE),$(SOONG_ANDROID_MK))
+ifeq ($(prebuilt_module_is_a_library),true)
+SOONG_ALREADY_CONV := $(SOONG_ALREADY_CONV) $(LOCAL_MODULE)
+endif
+endif
+
# Don't install static libraries by default.
ifndef LOCAL_UNINSTALLABLE_MODULE
ifeq (STATIC_LIBRARIES,$(LOCAL_MODULE_CLASS))
diff --git a/tools/soong_to_convert.py b/tools/soong_to_convert.py
new file mode 100755
index 0000000..379a1ad
--- /dev/null
+++ b/tools/soong_to_convert.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 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.
+
+"""Tool to prioritize which modules to convert to Soong.
+
+Generally, you'd use this through the make integration, which automatically
+generates the CSV input file that this tool expects:
+
+ $ m $OUT/soong_to_convert.txt
+ $ less $OUT/soong_to_convert.txt
+
+The output is a list of modules that are probably ready to convert to Soong:
+
+ # Blocked on Module (potential problems)
+ 283 libEGL (srcs_dotarm)
+ 246 libicuuc (dotdot_incs dotdot_srcs)
+ 221 libspeexresampler
+ 215 libcamera_metadata
+ ...
+ 0 zram-perf (dotdot_incs)
+
+The number at the beginning of the line shows how many native modules depend
+on that module.
+
+All of their dependencies have been satisfied, and any potential problems
+that Make can detect are listed in parenthesis after the module:
+
+ dotdot_srcs: LOCAL_SRC_FILES contains paths outside $(LOCAL_PATH)
+ dotdot_incs: LOCAL_C_INCLUDES contains paths include '..'
+ srcs_dotarm: LOCAL_SRC_FILES contains source files like <...>.c.arm
+ aidl: LOCAL_SRC_FILES contains .aidl sources
+ dbus: LOCAL_SRC_FILES contains .dbus-xml sources
+ objc: LOCAL_SRC_FILES contains Objective-C sources
+ proto: LOCAL_SRC_FILES contains .proto sources
+ rs: LOCAL_SRC_FILES contains renderscript sources
+ vts: LOCAL_SRC_FILES contains .vts sources
+
+Not all problems can be discovered, but this is a starting point.
+
+"""
+
+from __future__ import print_function
+
+import csv
+import sys
+
+def count_deps(depsdb, module, seen):
+ """Based on the depsdb, count the number of transitive dependencies.
+
+ You can pass in an reversed dependency graph to conut the number of
+ modules that depend on the module."""
+ count = 0
+ seen.append(module)
+ if module in depsdb:
+ for dep in depsdb[module]:
+ if dep in seen:
+ continue
+ count += 1 + count_deps(depsdb, dep, seen)
+ return count
+
+def process(reader):
+ """Read the input file and produce a list of modules ready to move to Soong
+ """
+ problems = dict()
+ deps = dict()
+ reverse_deps = dict()
+
+ for (module, problem, dependencies) in reader:
+ problems[module] = problem
+ deps[module] = [d for d in dependencies.strip().split(' ') if d != ""]
+ for dep in deps[module]:
+ if not dep in reverse_deps:
+ reverse_deps[dep] = []
+ reverse_deps[dep].append(module)
+
+ results = []
+ for module in problems:
+ # Only display actionable conversions, ones without missing dependencies
+ if len(deps[module]) != 0:
+ continue
+
+ extra = ""
+ if len(problems[module]) > 0:
+ extra = " ({})".format(problems[module])
+ results.append((count_deps(reverse_deps, module, []), module + extra))
+
+ return sorted(results, key=lambda result: (-result[0], result[1]))
+
+def display(results):
+ """Displays the results"""
+ count_header = "# Blocked on"
+ count_width = len(count_header)
+ print("{} Module (potential problems)".format(count_header))
+ for (count, module) in results:
+ print("{:>{}} {}".format(count, count_width, module))
+
+def main(filename):
+ """Read the CSV file, print the results"""
+ with open(filename, 'rb') as csvfile:
+ results = process(csv.reader(csvfile))
+
+ display(results)
+
+if __name__ == "__main__":
+ if len(sys.argv) != 2:
+ print("usage: soong_conversion.py <file>", file=sys.stderr)
+ sys.exit(1)
+
+ main(sys.argv[1])