You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
316 lines
11 KiB
316 lines
11 KiB
#!/usr/bin/env python3
|
|
#
|
|
# Copyright 2019 - 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.
|
|
|
|
"""native_module_info
|
|
|
|
Module Info class used to hold cached module_bp_cc_deps.json.
|
|
"""
|
|
|
|
import logging
|
|
import os
|
|
import re
|
|
|
|
from aidegen import constant
|
|
from aidegen.lib import common_util
|
|
from aidegen.lib import module_info
|
|
|
|
_CLANG = 'clang'
|
|
_CPPLANG = 'clang++'
|
|
_MODULES = 'modules'
|
|
_INCLUDE_TAIL = '_genc++_headers'
|
|
_SRC_GEN_CHECK = r'^out/soong/.intermediates/.+/gen/.+\.(c|cc|cpp)'
|
|
_INC_GEN_CHECK = r'^out/soong/.intermediates/.+/gen($|/.+)'
|
|
|
|
|
|
class NativeModuleInfo(module_info.AidegenModuleInfo):
|
|
"""Class that offers fast/easy lookup for module related details.
|
|
|
|
Class Attributes:
|
|
c_lang_path: Make C files compiler path.
|
|
cpp_lang_path: Make C++ files compiler path.
|
|
"""
|
|
|
|
c_lang_path = ''
|
|
cpp_lang_path = ''
|
|
|
|
def __init__(self, force_build=False, module_file=None):
|
|
"""Initialize the NativeModuleInfo object.
|
|
|
|
Load up the module_bp_cc_deps.json file and initialize the helper vars.
|
|
"""
|
|
if not module_file:
|
|
module_file = common_util.get_blueprint_json_path(
|
|
constant.BLUEPRINT_CC_JSONFILE_NAME)
|
|
if not os.path.isfile(module_file):
|
|
force_build = True
|
|
super().__init__(force_build, module_file)
|
|
|
|
def _load_module_info_file(self, force_build, module_file):
|
|
"""Load the module file.
|
|
|
|
Args:
|
|
force_build: Boolean to indicate if we should rebuild the
|
|
module_info file regardless if it's created or not.
|
|
module_file: String of path to file to load up. Used for testing.
|
|
|
|
Returns:
|
|
Tuple of module_info_target and dict of json.
|
|
"""
|
|
if force_build:
|
|
self._discover_mod_file_and_target(True)
|
|
mod_info = common_util.get_json_dict(module_file)
|
|
NativeModuleInfo.c_lang_path = mod_info.get(_CLANG, '')
|
|
NativeModuleInfo.cpp_lang_path = mod_info.get(_CPPLANG, '')
|
|
name_to_module_info = mod_info.get(_MODULES, {})
|
|
root_dir = common_util.get_android_root_dir()
|
|
module_info_target = os.path.relpath(module_file, root_dir)
|
|
return module_info_target, name_to_module_info
|
|
|
|
def get_module_names_in_targets_paths(self, targets):
|
|
"""Gets module names exist in native_module_info.
|
|
|
|
Args:
|
|
targets: A list of build targets to be checked.
|
|
|
|
Returns:
|
|
A list of native projects' names if native projects exist otherwise
|
|
return None.
|
|
"""
|
|
projects = []
|
|
for target in targets:
|
|
if target == constant.WHOLE_ANDROID_TREE_TARGET:
|
|
print('Do not deal with whole source tree in native projects.')
|
|
continue
|
|
rel_path, _ = common_util.get_related_paths(self, target)
|
|
for path in self.path_to_module_info:
|
|
if common_util.is_source_under_relative_path(path, rel_path):
|
|
projects.extend(self.get_module_names(path))
|
|
return projects
|
|
|
|
def get_module_includes(self, mod_name):
|
|
"""Gets module's include paths from module name.
|
|
|
|
The include paths contain in 'header_search_path' and
|
|
'system_search_path' of all flags in native module info.
|
|
|
|
Args:
|
|
mod_name: A string of module name.
|
|
|
|
Returns:
|
|
A set of module include paths relative to android root.
|
|
"""
|
|
includes = set()
|
|
mod_info = self.name_to_module_info.get(mod_name, {})
|
|
if not mod_info:
|
|
logging.warning('%s module name %s does not exist.',
|
|
common_util.COLORED_INFO('Warning:'), mod_name)
|
|
return includes
|
|
for flag in mod_info:
|
|
for header in (constant.KEY_HEADER, constant.KEY_SYSTEM):
|
|
if header in mod_info[flag]:
|
|
includes.update(set(mod_info[flag][header]))
|
|
return includes
|
|
|
|
def is_module_need_build(self, mod_name):
|
|
"""Checks if a module need to be built by its module name.
|
|
|
|
If a module's source files or include files contain a path looks like,
|
|
'out/soong/.intermediates/../gen/sysprop/charger.sysprop.cpp' or
|
|
'out/soong/.intermediates/../android.bufferhub@1.0_genc++_headers/gen'
|
|
and the paths do not exist, that means the module needs to be built to
|
|
generate relative source or include files.
|
|
|
|
Args:
|
|
mod_name: A string of module name.
|
|
|
|
Returns:
|
|
A boolean, True if it needs to be generated else False.
|
|
"""
|
|
mod_info = self.name_to_module_info.get(mod_name, {})
|
|
if not mod_info:
|
|
logging.warning('%s module name %s does not exist.',
|
|
common_util.COLORED_INFO('Warning:'), mod_name)
|
|
return False
|
|
if self._is_source_need_build(mod_info):
|
|
return True
|
|
if self._is_include_need_build(mod_info):
|
|
return True
|
|
return False
|
|
|
|
def _is_source_need_build(self, mod_info):
|
|
"""Checks if a module's source files need to be built.
|
|
|
|
If a module's source files contain a path looks like,
|
|
'out/soong/.intermediates/../gen/sysprop/charger.sysprop.cpp'
|
|
and the paths do not exist, that means the module needs to be built to
|
|
generate relative source files.
|
|
|
|
Args:
|
|
mod_info: A dictionary of module info to check.
|
|
|
|
Returns:
|
|
A boolean, True if it needs to be generated else False.
|
|
"""
|
|
if constant.KEY_SRCS not in mod_info:
|
|
return False
|
|
for src in mod_info[constant.KEY_SRCS]:
|
|
if re.search(_INC_GEN_CHECK, src) and not os.path.isfile(src):
|
|
return True
|
|
return False
|
|
|
|
def _is_include_need_build(self, mod_info):
|
|
"""Checks if a module needs to be built by its module name.
|
|
|
|
If a module's include files contain a path looks like,
|
|
'out/soong/.intermediates/../android.bufferhub@1.0_genc++_headers/gen'
|
|
and the paths do not exist, that means the module needs to be built to
|
|
generate relative include files.
|
|
|
|
Args:
|
|
mod_info: A dictionary of module info to check.
|
|
|
|
Returns:
|
|
A boolean, True if it needs to be generated else False.
|
|
"""
|
|
for flag in mod_info:
|
|
for header in (constant.KEY_HEADER, constant.KEY_SYSTEM):
|
|
if header not in mod_info[flag]:
|
|
continue
|
|
for include in mod_info[flag][header]:
|
|
match = re.search(_INC_GEN_CHECK, include)
|
|
if match and not os.path.isdir(include):
|
|
return True
|
|
return False
|
|
|
|
def is_suite_in_compatibility_suites(self, suite, mod_info):
|
|
"""Check if suite exists in the compatibility_suites of module-info.
|
|
|
|
Args:
|
|
suite: A string of suite name.
|
|
mod_info: Dict of module info to check.
|
|
|
|
Returns:
|
|
True if it exists in mod_info, False otherwise.
|
|
"""
|
|
raise NotImplementedError()
|
|
|
|
def get_testable_modules(self, suite=None):
|
|
"""Return the testable modules of the given suite name.
|
|
|
|
Args:
|
|
suite: A string of suite name. Set to None to return all testable
|
|
modules.
|
|
|
|
Returns:
|
|
List of testable modules. Empty list if non-existent.
|
|
If suite is None, return all the testable modules in module-info.
|
|
"""
|
|
raise NotImplementedError()
|
|
|
|
def is_testable_module(self, mod_info):
|
|
"""Check if module is something we can test.
|
|
|
|
A module is testable if:
|
|
- it's installed, or
|
|
- it's a robolectric module (or shares path with one).
|
|
|
|
Args:
|
|
mod_info: Dict of module info to check.
|
|
|
|
Returns:
|
|
True if we can test this module, False otherwise.
|
|
"""
|
|
raise NotImplementedError()
|
|
|
|
def has_test_config(self, mod_info):
|
|
"""Validate if this module has a test config.
|
|
|
|
A module can have a test config in the following manner:
|
|
- AndroidTest.xml at the module path.
|
|
- test_config be set in module-info.json.
|
|
- Auto-generated config via the auto_test_config key in
|
|
module-info.json.
|
|
|
|
Args:
|
|
mod_info: Dict of module info to check.
|
|
|
|
Returns:
|
|
True if this module has a test config, False otherwise.
|
|
"""
|
|
raise NotImplementedError()
|
|
|
|
def get_robolectric_test_name(self, module_name):
|
|
"""Returns runnable robolectric module name.
|
|
|
|
There are at least 2 modules in every robolectric module path, return
|
|
the module that we can run as a build target.
|
|
|
|
Arg:
|
|
module_name: String of module.
|
|
|
|
Returns:
|
|
String of module that is the runnable robolectric module, None if
|
|
none could be found.
|
|
"""
|
|
raise NotImplementedError()
|
|
|
|
def is_robolectric_test(self, module_name):
|
|
"""Check if module is a robolectric test.
|
|
|
|
A module can be a robolectric test if the specified module has their
|
|
class set as ROBOLECTRIC (or shares their path with a module that does).
|
|
|
|
Args:
|
|
module_name: String of module to check.
|
|
|
|
Returns:
|
|
True if the module is a robolectric module, else False.
|
|
"""
|
|
raise NotImplementedError()
|
|
|
|
def is_auto_gen_test_config(self, module_name):
|
|
"""Check if the test config file will be generated automatically.
|
|
|
|
Args:
|
|
module_name: A string of the module name.
|
|
|
|
Returns:
|
|
True if the test config file will be generated automatically.
|
|
"""
|
|
raise NotImplementedError()
|
|
|
|
def is_robolectric_module(self, mod_info):
|
|
"""Check if a module is a robolectric module.
|
|
|
|
Args:
|
|
mod_info: ModuleInfo to check.
|
|
|
|
Returns:
|
|
True if module is a robolectric module, False otherwise.
|
|
"""
|
|
raise NotImplementedError()
|
|
|
|
def is_native_test(self, module_name):
|
|
"""Check if the input module is a native test.
|
|
|
|
Args:
|
|
module_name: A string of the module name.
|
|
|
|
Returns:
|
|
True if the test is a native test, False otherwise.
|
|
"""
|
|
raise NotImplementedError()
|