diff --git a/core/Makefile b/core/Makefile index 919a45801..033c79de2 100644 --- a/core/Makefile +++ b/core/Makefile @@ -394,6 +394,22 @@ $(BUILD_SYSTEM_STATS): @$(foreach s,$(STATS.SOONG_MODULE_TYPE),echo "modules_type_soong,$(s),$(STATS.SOONG_MODULE_TYPE.$(s))" >>$@;) $(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 diff --git a/core/binary.mk b/core/binary.mk index dc9fa4e52..fb3189074 100644 --- a/core/binary.mk +++ b/core/binary.mk @@ -30,6 +30,8 @@ else 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 @@ ifeq (,$(LOCAL_SDK_VERSION)$(WITHOUT_LIBCOMPILER_RT)) 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 @@ ALL_GENERATED_SOURCES += $(my_generated_sources) 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 @@ endif ########################################################### 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 @@ endif # $(proto_sources) non-empty 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 @@ endif # $(dbus_definitions) non-empty 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 @@ endif # $(aidl_src) non-empty 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 @@ objc_objects := $(addprefix $(intermediates)/,$(objc_sources:.m=.o)) $(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 @@ objcpp_objects := $(addprefix $(intermediates)/,$(objcpp_sources:.mm=.o)) $(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 @@ endif # 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 64ce31a78..0c856ffd3 100644 --- a/core/prebuilt_internal.mk +++ b/core/prebuilt_internal.mk @@ -79,6 +79,12 @@ else 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 000000000..379a1add8 --- /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=sys.stderr) + sys.exit(1) + + main(sys.argv[1])