1*105f6285SAndroid Build Coastguard Worker# Copyright (C) 2020 The Android Open Source Project 2*105f6285SAndroid Build Coastguard Worker# 3*105f6285SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 4*105f6285SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 5*105f6285SAndroid Build Coastguard Worker# You may obtain a copy of the License at 6*105f6285SAndroid Build Coastguard Worker# 7*105f6285SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 8*105f6285SAndroid Build Coastguard Worker# 9*105f6285SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 10*105f6285SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 11*105f6285SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*105f6285SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 13*105f6285SAndroid Build Coastguard Worker# limitations under the License. 14*105f6285SAndroid Build Coastguard Worker"""Splits a manifest to the minimum set of projects needed to build the targets. 15*105f6285SAndroid Build Coastguard Worker 16*105f6285SAndroid Build Coastguard WorkerUsage: manifest_split [options] targets 17*105f6285SAndroid Build Coastguard Worker 18*105f6285SAndroid Build Coastguard Workertargets: Space-separated list of targets that should be buildable 19*105f6285SAndroid Build Coastguard Worker using the split manifest. 20*105f6285SAndroid Build Coastguard Worker 21*105f6285SAndroid Build Coastguard Workeroptions: 22*105f6285SAndroid Build Coastguard Worker --manifest <path> 23*105f6285SAndroid Build Coastguard Worker Path to the repo manifest to split. [Required] 24*105f6285SAndroid Build Coastguard Worker --split-manifest <path> 25*105f6285SAndroid Build Coastguard Worker Path to write the resulting split manifest. [Required] 26*105f6285SAndroid Build Coastguard Worker --config <path> 27*105f6285SAndroid Build Coastguard Worker Optional path(s) to a config XML file containing projects to add or 28*105f6285SAndroid Build Coastguard Worker remove. See default_config.xml for an example. This flag can be passed 29*105f6285SAndroid Build Coastguard Worker more than once to use multiple config files. 30*105f6285SAndroid Build Coastguard Worker Sample file my_config.xml: 31*105f6285SAndroid Build Coastguard Worker <config> 32*105f6285SAndroid Build Coastguard Worker <add_project name="vendor/my/needed/project" /> 33*105f6285SAndroid Build Coastguard Worker <remove_project name="vendor/my/unused/project" /> 34*105f6285SAndroid Build Coastguard Worker </config> 35*105f6285SAndroid Build Coastguard Worker --ignore-default-config 36*105f6285SAndroid Build Coastguard Worker If provided, don't include default_config.xml. 37*105f6285SAndroid Build Coastguard Worker --installed-prebuilt 38*105f6285SAndroid Build Coastguard Worker Specify the directory containing an installed prebuilt Android.bp file. 39*105f6285SAndroid Build Coastguard Worker Supply this option zero or more times, once for each installed prebuilt 40*105f6285SAndroid Build Coastguard Worker directory. 41*105f6285SAndroid Build Coastguard Worker --repo-list <path> 42*105f6285SAndroid Build Coastguard Worker Optional path to the output of the 'repo list' command. Used if the 43*105f6285SAndroid Build Coastguard Worker output of 'repo list' needs pre-processing before being used by 44*105f6285SAndroid Build Coastguard Worker this tool. 45*105f6285SAndroid Build Coastguard Worker --ninja-build <path> 46*105f6285SAndroid Build Coastguard Worker Optional path to the combined-<target>.ninja file found in an out dir. 47*105f6285SAndroid Build Coastguard Worker If not provided, the default file is used based on the lunch environment. 48*105f6285SAndroid Build Coastguard Worker --ninja-binary <path> 49*105f6285SAndroid Build Coastguard Worker Optional path to the ninja binary. Uses the standard binary by default. 50*105f6285SAndroid Build Coastguard Worker --module-info <path> 51*105f6285SAndroid Build Coastguard Worker Optional path to the module-info.json file found in an out dir. 52*105f6285SAndroid Build Coastguard Worker If not provided, the default file is used based on the lunch environment. 53*105f6285SAndroid Build Coastguard Worker --skip-module-info 54*105f6285SAndroid Build Coastguard Worker If provided, skip parsing module-info.json for direct and adjacent 55*105f6285SAndroid Build Coastguard Worker dependencies. Overrides --module-info option. 56*105f6285SAndroid Build Coastguard Worker --kati-stamp <path> 57*105f6285SAndroid Build Coastguard Worker Optional path to the .kati_stamp file found in an out dir. 58*105f6285SAndroid Build Coastguard Worker If not provided, the default file is used based on the lunch environment. 59*105f6285SAndroid Build Coastguard Worker --skip-kati 60*105f6285SAndroid Build Coastguard Worker If provided, skip Kati makefiles projects. Overrides --kati-stamp option. 61*105f6285SAndroid Build Coastguard Worker --overlay <path> 62*105f6285SAndroid Build Coastguard Worker Optional path(s) to treat as overlays when parsing the kati stamp file 63*105f6285SAndroid Build Coastguard Worker and scanning for makefiles. See the tools/treble/build/sandbox directory 64*105f6285SAndroid Build Coastguard Worker for more info about overlays. This flag can be passed more than once. 65*105f6285SAndroid Build Coastguard Worker --debug-file <path> 66*105f6285SAndroid Build Coastguard Worker If provided, debug info will be written to a JSON file at this path. 67*105f6285SAndroid Build Coastguard Worker -h (--help) 68*105f6285SAndroid Build Coastguard Worker Display this usage message and exit. 69*105f6285SAndroid Build Coastguard Worker""" 70*105f6285SAndroid Build Coastguard Worker 71*105f6285SAndroid Build Coastguard Workerfrom __future__ import print_function 72*105f6285SAndroid Build Coastguard Worker 73*105f6285SAndroid Build Coastguard Workerimport getopt 74*105f6285SAndroid Build Coastguard Workerimport json 75*105f6285SAndroid Build Coastguard Workerimport logging 76*105f6285SAndroid Build Coastguard Workerimport os 77*105f6285SAndroid Build Coastguard Workerimport pkgutil 78*105f6285SAndroid Build Coastguard Workerimport re 79*105f6285SAndroid Build Coastguard Workerimport subprocess 80*105f6285SAndroid Build Coastguard Workerimport sys 81*105f6285SAndroid Build Coastguard Workerimport tempfile 82*105f6285SAndroid Build Coastguard Workerfrom typing import Dict, List, Pattern, Set, Tuple 83*105f6285SAndroid Build Coastguard Workerimport xml.etree.ElementTree as ET 84*105f6285SAndroid Build Coastguard Worker 85*105f6285SAndroid Build Coastguard Workerimport dataclasses 86*105f6285SAndroid Build Coastguard Worker 87*105f6285SAndroid Build Coastguard Worker 88*105f6285SAndroid Build Coastguard Workerlogging.basicConfig( 89*105f6285SAndroid Build Coastguard Worker stream=sys.stdout, 90*105f6285SAndroid Build Coastguard Worker level=logging.INFO, 91*105f6285SAndroid Build Coastguard Worker format="%(asctime)s - %(filename)s - %(levelname)-8s: %(message)s", 92*105f6285SAndroid Build Coastguard Worker datefmt="%Y-%m-%d %H:%M:%S") 93*105f6285SAndroid Build Coastguard Workerlogger = logging.getLogger(os.path.basename(__file__)) 94*105f6285SAndroid Build Coastguard Worker 95*105f6285SAndroid Build Coastguard Worker# Projects determined to be needed despite the dependency not being visible 96*105f6285SAndroid Build Coastguard Worker# to ninja. 97*105f6285SAndroid Build Coastguard WorkerDEFAULT_CONFIG_XML = "default_config.xml" 98*105f6285SAndroid Build Coastguard Worker 99*105f6285SAndroid Build Coastguard Worker# Pattern that matches a java dependency. 100*105f6285SAndroid Build Coastguard Worker_JAVA_LIB_PATTERN = re.compile( 101*105f6285SAndroid Build Coastguard Worker # pylint: disable=line-too-long 102*105f6285SAndroid Build Coastguard Worker '^out/target/common/obj/JAVA_LIBRARIES/(.+)_intermediates/classes-header.jar$' 103*105f6285SAndroid Build Coastguard Worker) 104*105f6285SAndroid Build Coastguard Worker 105*105f6285SAndroid Build Coastguard Worker 106*105f6285SAndroid Build Coastguard Worker@dataclasses.dataclass 107*105f6285SAndroid Build Coastguard Workerclass PathMappingConfig: 108*105f6285SAndroid Build Coastguard Worker pattern: Pattern[str] 109*105f6285SAndroid Build Coastguard Worker sub: str 110*105f6285SAndroid Build Coastguard Worker 111*105f6285SAndroid Build Coastguard Worker 112*105f6285SAndroid Build Coastguard Worker@dataclasses.dataclass 113*105f6285SAndroid Build Coastguard Workerclass ManifestSplitConfig: 114*105f6285SAndroid Build Coastguard Worker """Holds the configuration for the split manifest tool. 115*105f6285SAndroid Build Coastguard Worker 116*105f6285SAndroid Build Coastguard Worker Attributes: 117*105f6285SAndroid Build Coastguard Worker remove_projects: A Dict of project name to the config file that specified 118*105f6285SAndroid Build Coastguard Worker this project, for projects that should be removed from the resulting 119*105f6285SAndroid Build Coastguard Worker manifest. 120*105f6285SAndroid Build Coastguard Worker add_projects: A Dict of project name to the config file that specified 121*105f6285SAndroid Build Coastguard Worker this project, for projects that should be added to the resulting manifest. 122*105f6285SAndroid Build Coastguard Worker path_mappings: A list of PathMappingConfigs to modify a path in the build 123*105f6285SAndroid Build Coastguard Worker sandbox to the path in the manifest. 124*105f6285SAndroid Build Coastguard Worker ignore_paths: Set of paths to ignore when parsing module_info_file 125*105f6285SAndroid Build Coastguard Worker """ 126*105f6285SAndroid Build Coastguard Worker remove_projects: Dict[str, str] 127*105f6285SAndroid Build Coastguard Worker add_projects: Dict[str, str] 128*105f6285SAndroid Build Coastguard Worker path_mappings: List[PathMappingConfig] 129*105f6285SAndroid Build Coastguard Worker ignore_paths: Set[str] 130*105f6285SAndroid Build Coastguard Worker 131*105f6285SAndroid Build Coastguard Worker @classmethod 132*105f6285SAndroid Build Coastguard Worker def from_config_files(cls, config_files: List[str]): 133*105f6285SAndroid Build Coastguard Worker """Reads from a list of config XML files. 134*105f6285SAndroid Build Coastguard Worker 135*105f6285SAndroid Build Coastguard Worker Args: 136*105f6285SAndroid Build Coastguard Worker config_files: A list of config XML filenames. 137*105f6285SAndroid Build Coastguard Worker 138*105f6285SAndroid Build Coastguard Worker Returns: 139*105f6285SAndroid Build Coastguard Worker A ManifestSplitConfig from the files. 140*105f6285SAndroid Build Coastguard Worker """ 141*105f6285SAndroid Build Coastguard Worker remove_projects: Dict[str, str] = {} 142*105f6285SAndroid Build Coastguard Worker add_projects: Dict[str, str] = {} 143*105f6285SAndroid Build Coastguard Worker path_mappings = [] 144*105f6285SAndroid Build Coastguard Worker """ Always ignore paths in out/ directory. """ 145*105f6285SAndroid Build Coastguard Worker ignore_paths = set(["out/"]) 146*105f6285SAndroid Build Coastguard Worker for config_file in config_files: 147*105f6285SAndroid Build Coastguard Worker root = ET.parse(config_file).getroot() 148*105f6285SAndroid Build Coastguard Worker 149*105f6285SAndroid Build Coastguard Worker remove_projects.update({ 150*105f6285SAndroid Build Coastguard Worker c.attrib["name"]: config_file for c in root.findall("remove_project") 151*105f6285SAndroid Build Coastguard Worker }) 152*105f6285SAndroid Build Coastguard Worker 153*105f6285SAndroid Build Coastguard Worker add_projects.update( 154*105f6285SAndroid Build Coastguard Worker {c.attrib["name"]: config_file for c in root.findall("add_project")}) 155*105f6285SAndroid Build Coastguard Worker 156*105f6285SAndroid Build Coastguard Worker path_mappings.extend([ 157*105f6285SAndroid Build Coastguard Worker PathMappingConfig( 158*105f6285SAndroid Build Coastguard Worker re.compile(child.attrib["pattern"]), child.attrib["sub"]) 159*105f6285SAndroid Build Coastguard Worker for child in root.findall("path_mapping") 160*105f6285SAndroid Build Coastguard Worker ]) 161*105f6285SAndroid Build Coastguard Worker 162*105f6285SAndroid Build Coastguard Worker ignore_paths.update( 163*105f6285SAndroid Build Coastguard Worker {c.attrib["name"]: config_file for c in root.findall("ignore_path")}) 164*105f6285SAndroid Build Coastguard Worker 165*105f6285SAndroid Build Coastguard Worker return cls(remove_projects, add_projects, path_mappings, ignore_paths) 166*105f6285SAndroid Build Coastguard Worker 167*105f6285SAndroid Build Coastguard Worker 168*105f6285SAndroid Build Coastguard Workerdef get_repo_projects(repo_list_file, manifest, path_mappings): 169*105f6285SAndroid Build Coastguard Worker """Returns a dict of { project path : project name } using the manifest. 170*105f6285SAndroid Build Coastguard Worker 171*105f6285SAndroid Build Coastguard Worker The path_mappings stop on the first match mapping. If the mapping results in 172*105f6285SAndroid Build Coastguard Worker an empty string, that entry is removed. 173*105f6285SAndroid Build Coastguard Worker 174*105f6285SAndroid Build Coastguard Worker Args: 175*105f6285SAndroid Build Coastguard Worker repo_list_file: An optional filename to read instead of parsing the manifest. 176*105f6285SAndroid Build Coastguard Worker manifest: The manifest object to scan for projects. 177*105f6285SAndroid Build Coastguard Worker path_mappings: A list of PathMappingConfigs to modify a path in the build 178*105f6285SAndroid Build Coastguard Worker sandbox to the path in the manifest. 179*105f6285SAndroid Build Coastguard Worker """ 180*105f6285SAndroid Build Coastguard Worker repo_list = [] 181*105f6285SAndroid Build Coastguard Worker 182*105f6285SAndroid Build Coastguard Worker if repo_list_file: 183*105f6285SAndroid Build Coastguard Worker with open(repo_list_file) as repo_list_lines: 184*105f6285SAndroid Build Coastguard Worker repo_list = [line.strip().split(" : ") for line in repo_list_lines if line.strip()] 185*105f6285SAndroid Build Coastguard Worker else: 186*105f6285SAndroid Build Coastguard Worker root = manifest.getroot() 187*105f6285SAndroid Build Coastguard Worker repo_list = [(p.get("path", p.get("name")), p.get("name")) for p in root.findall("project")] 188*105f6285SAndroid Build Coastguard Worker 189*105f6285SAndroid Build Coastguard Worker repo_dict = {} 190*105f6285SAndroid Build Coastguard Worker for entry in repo_list: 191*105f6285SAndroid Build Coastguard Worker path, project = entry 192*105f6285SAndroid Build Coastguard Worker for mapping in path_mappings: 193*105f6285SAndroid Build Coastguard Worker if mapping.pattern.fullmatch(path): 194*105f6285SAndroid Build Coastguard Worker path = mapping.pattern.sub(mapping.sub, path) 195*105f6285SAndroid Build Coastguard Worker break 196*105f6285SAndroid Build Coastguard Worker # If the resulting path mapping is empty, then don't add entry 197*105f6285SAndroid Build Coastguard Worker if path: 198*105f6285SAndroid Build Coastguard Worker repo_dict[path] = project 199*105f6285SAndroid Build Coastguard Worker return repo_dict 200*105f6285SAndroid Build Coastguard Worker 201*105f6285SAndroid Build Coastguard Worker 202*105f6285SAndroid Build Coastguard Workerclass ModuleInfo: 203*105f6285SAndroid Build Coastguard Worker """Contains various mappings to/from module/project""" 204*105f6285SAndroid Build Coastguard Worker 205*105f6285SAndroid Build Coastguard Worker def __init__(self, module_info_file, repo_projects, ignore_paths): 206*105f6285SAndroid Build Coastguard Worker """Initialize a module info instance. 207*105f6285SAndroid Build Coastguard Worker 208*105f6285SAndroid Build Coastguard Worker Builds various maps related to platform build system modules and how they 209*105f6285SAndroid Build Coastguard Worker relate to each other and projects. 210*105f6285SAndroid Build Coastguard Worker 211*105f6285SAndroid Build Coastguard Worker Args: 212*105f6285SAndroid Build Coastguard Worker module_info_file: The path to a module-info.json file from a build. 213*105f6285SAndroid Build Coastguard Worker repo_projects: The output of the get_repo_projects function. 214*105f6285SAndroid Build Coastguard Worker ignore_paths: Set of paths to ignore from module_info_file data 215*105f6285SAndroid Build Coastguard Worker 216*105f6285SAndroid Build Coastguard Worker Raises: 217*105f6285SAndroid Build Coastguard Worker ValueError: A module from module-info.json belongs to a path not 218*105f6285SAndroid Build Coastguard Worker known by the repo projects output. 219*105f6285SAndroid Build Coastguard Worker """ 220*105f6285SAndroid Build Coastguard Worker # Maps a project to the set of modules it contains. 221*105f6285SAndroid Build Coastguard Worker self.project_modules = {} 222*105f6285SAndroid Build Coastguard Worker # Maps a module to the project that contains it. 223*105f6285SAndroid Build Coastguard Worker self.module_project = {} 224*105f6285SAndroid Build Coastguard Worker # Maps a module to its class. 225*105f6285SAndroid Build Coastguard Worker self.module_class = {} 226*105f6285SAndroid Build Coastguard Worker # Maps a module to modules it depends on. 227*105f6285SAndroid Build Coastguard Worker self.module_deps = {} 228*105f6285SAndroid Build Coastguard Worker 229*105f6285SAndroid Build Coastguard Worker with open(module_info_file) as module_info_file: 230*105f6285SAndroid Build Coastguard Worker module_info = json.load(module_info_file) 231*105f6285SAndroid Build Coastguard Worker 232*105f6285SAndroid Build Coastguard Worker # Check that module contains a path and the path is not in set of 233*105f6285SAndroid Build Coastguard Worker # ignore paths 234*105f6285SAndroid Build Coastguard Worker def module_has_valid_path(module): 235*105f6285SAndroid Build Coastguard Worker paths = module.get("path") 236*105f6285SAndroid Build Coastguard Worker if not paths: 237*105f6285SAndroid Build Coastguard Worker return False 238*105f6285SAndroid Build Coastguard Worker return all(not paths[0].startswith(p) for p in ignore_paths) 239*105f6285SAndroid Build Coastguard Worker 240*105f6285SAndroid Build Coastguard Worker module_paths = { 241*105f6285SAndroid Build Coastguard Worker module: module_info[module]["path"][0] 242*105f6285SAndroid Build Coastguard Worker for module in module_info 243*105f6285SAndroid Build Coastguard Worker if module_has_valid_path(module_info[module]) 244*105f6285SAndroid Build Coastguard Worker } 245*105f6285SAndroid Build Coastguard Worker module_project_paths = { 246*105f6285SAndroid Build Coastguard Worker module: scan_repo_projects(repo_projects, module_paths[module]) 247*105f6285SAndroid Build Coastguard Worker for module in module_paths 248*105f6285SAndroid Build Coastguard Worker } 249*105f6285SAndroid Build Coastguard Worker 250*105f6285SAndroid Build Coastguard Worker for module, project_path in module_project_paths.items(): 251*105f6285SAndroid Build Coastguard Worker if not project_path: 252*105f6285SAndroid Build Coastguard Worker raise ValueError("Unknown module path for module %s: %s" % 253*105f6285SAndroid Build Coastguard Worker (module, module_info[module])) 254*105f6285SAndroid Build Coastguard Worker repo_project = repo_projects[project_path] 255*105f6285SAndroid Build Coastguard Worker self.project_modules.setdefault(repo_project, set()).add(module) 256*105f6285SAndroid Build Coastguard Worker self.module_project[module] = repo_project 257*105f6285SAndroid Build Coastguard Worker 258*105f6285SAndroid Build Coastguard Worker def dep_from_raw_dep(raw_dep): 259*105f6285SAndroid Build Coastguard Worker match = re.search(_JAVA_LIB_PATTERN, raw_dep) 260*105f6285SAndroid Build Coastguard Worker return match.group(1) if match else raw_dep 261*105f6285SAndroid Build Coastguard Worker 262*105f6285SAndroid Build Coastguard Worker def deps_from_raw_deps(raw_deps): 263*105f6285SAndroid Build Coastguard Worker return [dep_from_raw_dep(raw_dep) for raw_dep in raw_deps] 264*105f6285SAndroid Build Coastguard Worker 265*105f6285SAndroid Build Coastguard Worker self.module_class = { 266*105f6285SAndroid Build Coastguard Worker module: module_info[module]["class"][0] 267*105f6285SAndroid Build Coastguard Worker for module in module_info 268*105f6285SAndroid Build Coastguard Worker } 269*105f6285SAndroid Build Coastguard Worker self.module_deps = { 270*105f6285SAndroid Build Coastguard Worker module: deps_from_raw_deps(module_info[module]["dependencies"]) 271*105f6285SAndroid Build Coastguard Worker for module in module_info 272*105f6285SAndroid Build Coastguard Worker } 273*105f6285SAndroid Build Coastguard Worker 274*105f6285SAndroid Build Coastguard Worker 275*105f6285SAndroid Build Coastguard Workerdef get_ninja_inputs(ninja_binary, ninja_build_file, modules): 276*105f6285SAndroid Build Coastguard Worker """Returns the set of input file path strings for the given modules. 277*105f6285SAndroid Build Coastguard Worker 278*105f6285SAndroid Build Coastguard Worker Uses the `ninja -t inputs` tool. 279*105f6285SAndroid Build Coastguard Worker 280*105f6285SAndroid Build Coastguard Worker Args: 281*105f6285SAndroid Build Coastguard Worker ninja_binary: The path to a ninja binary. 282*105f6285SAndroid Build Coastguard Worker ninja_build_file: The path to a .ninja file from a build. 283*105f6285SAndroid Build Coastguard Worker modules: The list of modules to scan for inputs. 284*105f6285SAndroid Build Coastguard Worker """ 285*105f6285SAndroid Build Coastguard Worker inputs = set() 286*105f6285SAndroid Build Coastguard Worker NINJA_SHARD_LIMIT = 20000 287*105f6285SAndroid Build Coastguard Worker for i in range(0, len(modules), NINJA_SHARD_LIMIT): 288*105f6285SAndroid Build Coastguard Worker modules_shard = modules[i:i + NINJA_SHARD_LIMIT] 289*105f6285SAndroid Build Coastguard Worker inputs = inputs.union(set( 290*105f6285SAndroid Build Coastguard Worker subprocess.check_output([ 291*105f6285SAndroid Build Coastguard Worker ninja_binary, 292*105f6285SAndroid Build Coastguard Worker "-f", 293*105f6285SAndroid Build Coastguard Worker ninja_build_file, 294*105f6285SAndroid Build Coastguard Worker "-t", 295*105f6285SAndroid Build Coastguard Worker "inputs", 296*105f6285SAndroid Build Coastguard Worker "-d", 297*105f6285SAndroid Build Coastguard Worker ] + list(modules_shard)).decode().strip("\n").split("\n"))) 298*105f6285SAndroid Build Coastguard Worker 299*105f6285SAndroid Build Coastguard Worker def input_allowed(path): 300*105f6285SAndroid Build Coastguard Worker path = path.strip() 301*105f6285SAndroid Build Coastguard Worker if path.endswith("TEST_MAPPING") and "test_mapping" not in modules: 302*105f6285SAndroid Build Coastguard Worker # Exclude projects that are only needed for TEST_MAPPING files, unless the 303*105f6285SAndroid Build Coastguard Worker # user is asking to build 'test_mapping'. 304*105f6285SAndroid Build Coastguard Worker return False 305*105f6285SAndroid Build Coastguard Worker if path.endswith("MODULE_LICENSE_GPL"): 306*105f6285SAndroid Build Coastguard Worker # Exclude projects that are included only due to having a 307*105f6285SAndroid Build Coastguard Worker # MODULE_LICENSE_GPL file, if no other inputs from that project are used. 308*105f6285SAndroid Build Coastguard Worker return False 309*105f6285SAndroid Build Coastguard Worker return path 310*105f6285SAndroid Build Coastguard Worker 311*105f6285SAndroid Build Coastguard Worker return {path.strip() for path in inputs if input_allowed(path)} 312*105f6285SAndroid Build Coastguard Worker 313*105f6285SAndroid Build Coastguard Worker 314*105f6285SAndroid Build Coastguard Workerdef get_kati_makefiles(kati_stamp_file, overlays): 315*105f6285SAndroid Build Coastguard Worker """Returns the set of makefile paths from the kati stamp file. 316*105f6285SAndroid Build Coastguard Worker 317*105f6285SAndroid Build Coastguard Worker Uses the ckati prebuilt binary. 318*105f6285SAndroid Build Coastguard Worker Also includes symlink sources in the resulting set for any 319*105f6285SAndroid Build Coastguard Worker makefiles that are symlinks. 320*105f6285SAndroid Build Coastguard Worker 321*105f6285SAndroid Build Coastguard Worker Args: 322*105f6285SAndroid Build Coastguard Worker kati_stamp_file: The path to a .kati_stamp file from a build. 323*105f6285SAndroid Build Coastguard Worker overlays: A list of paths to treat as overlays when parsing the kati stamp 324*105f6285SAndroid Build Coastguard Worker file. 325*105f6285SAndroid Build Coastguard Worker """ 326*105f6285SAndroid Build Coastguard Worker # Get a set of all makefiles that were parsed by Kati during the build. 327*105f6285SAndroid Build Coastguard Worker makefiles = set( 328*105f6285SAndroid Build Coastguard Worker subprocess.check_output([ 329*105f6285SAndroid Build Coastguard Worker "prebuilts/build-tools/linux-x86/bin/ckati", 330*105f6285SAndroid Build Coastguard Worker "--dump_stamp_tool", 331*105f6285SAndroid Build Coastguard Worker "--files", 332*105f6285SAndroid Build Coastguard Worker kati_stamp_file, 333*105f6285SAndroid Build Coastguard Worker ]).decode().strip("\n").split("\n")) 334*105f6285SAndroid Build Coastguard Worker 335*105f6285SAndroid Build Coastguard Worker def is_product_makefile(makefile): 336*105f6285SAndroid Build Coastguard Worker """Returns True if the makefile path meets certain criteria.""" 337*105f6285SAndroid Build Coastguard Worker banned_prefixes = [ 338*105f6285SAndroid Build Coastguard Worker "out/", 339*105f6285SAndroid Build Coastguard Worker # Ignore product makefiles for sample AOSP boards. 340*105f6285SAndroid Build Coastguard Worker "device/amlogic", 341*105f6285SAndroid Build Coastguard Worker "device/generic", 342*105f6285SAndroid Build Coastguard Worker "device/google", 343*105f6285SAndroid Build Coastguard Worker "device/linaro", 344*105f6285SAndroid Build Coastguard Worker "device/sample", 345*105f6285SAndroid Build Coastguard Worker ] 346*105f6285SAndroid Build Coastguard Worker banned_suffixes = [ 347*105f6285SAndroid Build Coastguard Worker # All Android.mk files in the source are always parsed by Kati, 348*105f6285SAndroid Build Coastguard Worker # so including them here would bring in lots of unnecessary projects. 349*105f6285SAndroid Build Coastguard Worker "Android.mk", 350*105f6285SAndroid Build Coastguard Worker # The ckati stamp file always includes a line for the ckati bin at 351*105f6285SAndroid Build Coastguard Worker # the beginnning. 352*105f6285SAndroid Build Coastguard Worker "bin/ckati", 353*105f6285SAndroid Build Coastguard Worker ] 354*105f6285SAndroid Build Coastguard Worker return (all([not makefile.startswith(p) for p in banned_prefixes]) and 355*105f6285SAndroid Build Coastguard Worker all([not makefile.endswith(s) for s in banned_suffixes])) 356*105f6285SAndroid Build Coastguard Worker 357*105f6285SAndroid Build Coastguard Worker # Limit the makefiles to only product makefiles. 358*105f6285SAndroid Build Coastguard Worker product_makefiles = { 359*105f6285SAndroid Build Coastguard Worker os.path.normpath(path) for path in makefiles if is_product_makefile(path) 360*105f6285SAndroid Build Coastguard Worker } 361*105f6285SAndroid Build Coastguard Worker 362*105f6285SAndroid Build Coastguard Worker def strip_overlay(makefile): 363*105f6285SAndroid Build Coastguard Worker """Remove any overlays from a makefile path.""" 364*105f6285SAndroid Build Coastguard Worker for overlay in overlays: 365*105f6285SAndroid Build Coastguard Worker if makefile.startswith(overlay): 366*105f6285SAndroid Build Coastguard Worker return makefile[len(overlay):] 367*105f6285SAndroid Build Coastguard Worker return makefile 368*105f6285SAndroid Build Coastguard Worker 369*105f6285SAndroid Build Coastguard Worker makefiles_and_symlinks = set() 370*105f6285SAndroid Build Coastguard Worker for makefile in product_makefiles: 371*105f6285SAndroid Build Coastguard Worker # Search for the makefile, possibly scanning overlays as well. 372*105f6285SAndroid Build Coastguard Worker for overlay in [""] + overlays: 373*105f6285SAndroid Build Coastguard Worker makefile_with_overlay = os.path.join(overlay, makefile) 374*105f6285SAndroid Build Coastguard Worker if os.path.exists(makefile_with_overlay): 375*105f6285SAndroid Build Coastguard Worker makefile = makefile_with_overlay 376*105f6285SAndroid Build Coastguard Worker break 377*105f6285SAndroid Build Coastguard Worker 378*105f6285SAndroid Build Coastguard Worker if not os.path.exists(makefile): 379*105f6285SAndroid Build Coastguard Worker logger.warning("Unknown kati makefile: %s" % makefile) 380*105f6285SAndroid Build Coastguard Worker continue 381*105f6285SAndroid Build Coastguard Worker 382*105f6285SAndroid Build Coastguard Worker # Ensure the project that contains the makefile is included, as well as 383*105f6285SAndroid Build Coastguard Worker # the project that any makefile symlinks point to. 384*105f6285SAndroid Build Coastguard Worker makefiles_and_symlinks.add(strip_overlay(makefile)) 385*105f6285SAndroid Build Coastguard Worker if os.path.islink(makefile): 386*105f6285SAndroid Build Coastguard Worker makefiles_and_symlinks.add( 387*105f6285SAndroid Build Coastguard Worker strip_overlay(os.path.relpath(os.path.realpath(makefile)))) 388*105f6285SAndroid Build Coastguard Worker 389*105f6285SAndroid Build Coastguard Worker return makefiles_and_symlinks 390*105f6285SAndroid Build Coastguard Worker 391*105f6285SAndroid Build Coastguard Worker 392*105f6285SAndroid Build Coastguard Workerdef scan_repo_projects(repo_projects, input_path): 393*105f6285SAndroid Build Coastguard Worker """Returns the project path of the given input path if it exists. 394*105f6285SAndroid Build Coastguard Worker 395*105f6285SAndroid Build Coastguard Worker Args: 396*105f6285SAndroid Build Coastguard Worker repo_projects: The output of the get_repo_projects function. 397*105f6285SAndroid Build Coastguard Worker input_path: The path of an input file used in the build, as given by the 398*105f6285SAndroid Build Coastguard Worker ninja inputs tool. 399*105f6285SAndroid Build Coastguard Worker 400*105f6285SAndroid Build Coastguard Worker Returns: 401*105f6285SAndroid Build Coastguard Worker The path string, or None if not found. 402*105f6285SAndroid Build Coastguard Worker """ 403*105f6285SAndroid Build Coastguard Worker parts = input_path.split("/") 404*105f6285SAndroid Build Coastguard Worker 405*105f6285SAndroid Build Coastguard Worker for index in reversed(range(0, len(parts))): 406*105f6285SAndroid Build Coastguard Worker project_path = os.path.join(*parts[:index + 1]) 407*105f6285SAndroid Build Coastguard Worker if project_path in repo_projects: 408*105f6285SAndroid Build Coastguard Worker return project_path 409*105f6285SAndroid Build Coastguard Worker 410*105f6285SAndroid Build Coastguard Worker return None 411*105f6285SAndroid Build Coastguard Worker 412*105f6285SAndroid Build Coastguard Worker 413*105f6285SAndroid Build Coastguard Workerdef get_input_projects(repo_projects, inputs): 414*105f6285SAndroid Build Coastguard Worker """Returns the collection of project names that contain the given input paths. 415*105f6285SAndroid Build Coastguard Worker 416*105f6285SAndroid Build Coastguard Worker Args: 417*105f6285SAndroid Build Coastguard Worker repo_projects: The output of the get_repo_projects function. 418*105f6285SAndroid Build Coastguard Worker inputs: The paths of input files used in the build, as given by the ninja 419*105f6285SAndroid Build Coastguard Worker inputs tool. 420*105f6285SAndroid Build Coastguard Worker """ 421*105f6285SAndroid Build Coastguard Worker input_project_paths = {} 422*105f6285SAndroid Build Coastguard Worker for input_path in inputs: 423*105f6285SAndroid Build Coastguard Worker if not input_path.startswith("out/") and not input_path.startswith("/"): 424*105f6285SAndroid Build Coastguard Worker input_project_paths.setdefault( 425*105f6285SAndroid Build Coastguard Worker scan_repo_projects(repo_projects, input_path), []).append(input_path) 426*105f6285SAndroid Build Coastguard Worker 427*105f6285SAndroid Build Coastguard Worker return { 428*105f6285SAndroid Build Coastguard Worker repo_projects[project_path]: inputs 429*105f6285SAndroid Build Coastguard Worker for project_path, inputs in input_project_paths.items() 430*105f6285SAndroid Build Coastguard Worker if project_path is not None 431*105f6285SAndroid Build Coastguard Worker } 432*105f6285SAndroid Build Coastguard Worker 433*105f6285SAndroid Build Coastguard Worker 434*105f6285SAndroid Build Coastguard Workerdef update_manifest(manifest, input_projects, remove_projects): 435*105f6285SAndroid Build Coastguard Worker """Modifies and returns a manifest ElementTree by modifying its projects. 436*105f6285SAndroid Build Coastguard Worker 437*105f6285SAndroid Build Coastguard Worker Args: 438*105f6285SAndroid Build Coastguard Worker manifest: The manifest object to modify. 439*105f6285SAndroid Build Coastguard Worker input_projects: A set of projects that should stay in the manifest. 440*105f6285SAndroid Build Coastguard Worker remove_projects: A set of projects that should be removed from the manifest. 441*105f6285SAndroid Build Coastguard Worker Projects in this set override input_projects. 442*105f6285SAndroid Build Coastguard Worker 443*105f6285SAndroid Build Coastguard Worker Returns: 444*105f6285SAndroid Build Coastguard Worker The modified manifest object. 445*105f6285SAndroid Build Coastguard Worker """ 446*105f6285SAndroid Build Coastguard Worker projects_to_keep = input_projects.difference(remove_projects) 447*105f6285SAndroid Build Coastguard Worker root = manifest.getroot() 448*105f6285SAndroid Build Coastguard Worker for child in root.findall("project"): 449*105f6285SAndroid Build Coastguard Worker if child.attrib["name"] not in projects_to_keep: 450*105f6285SAndroid Build Coastguard Worker root.remove(child) 451*105f6285SAndroid Build Coastguard Worker return manifest 452*105f6285SAndroid Build Coastguard Worker 453*105f6285SAndroid Build Coastguard Worker 454*105f6285SAndroid Build Coastguard Worker@dataclasses.dataclass 455*105f6285SAndroid Build Coastguard Workerclass DebugInfo: 456*105f6285SAndroid Build Coastguard Worker """Simple class to store structured debug info for a project.""" 457*105f6285SAndroid Build Coastguard Worker direct_input: bool = False 458*105f6285SAndroid Build Coastguard Worker adjacent_input: bool = False 459*105f6285SAndroid Build Coastguard Worker deps_input: bool = False 460*105f6285SAndroid Build Coastguard Worker kati_makefiles: List[str] = dataclasses.field(default_factory=list) 461*105f6285SAndroid Build Coastguard Worker manual_add_config: str = "" 462*105f6285SAndroid Build Coastguard Worker manual_remove_config: str = "" 463*105f6285SAndroid Build Coastguard Worker 464*105f6285SAndroid Build Coastguard Worker 465*105f6285SAndroid Build Coastguard Workerdef create_split_manifest(targets, manifest_file, split_manifest_file, 466*105f6285SAndroid Build Coastguard Worker config_files, repo_list_file, ninja_build_file, 467*105f6285SAndroid Build Coastguard Worker ninja_binary, module_info_file, kati_stamp_file, 468*105f6285SAndroid Build Coastguard Worker overlays, installed_prebuilts, debug_file): 469*105f6285SAndroid Build Coastguard Worker """Creates and writes a split manifest by inspecting build inputs. 470*105f6285SAndroid Build Coastguard Worker 471*105f6285SAndroid Build Coastguard Worker Args: 472*105f6285SAndroid Build Coastguard Worker targets: List of targets that should be buildable using the split manifest. 473*105f6285SAndroid Build Coastguard Worker manifest_file: Path to the repo manifest to split. 474*105f6285SAndroid Build Coastguard Worker split_manifest_file: Path to write the resulting split manifest. 475*105f6285SAndroid Build Coastguard Worker config_files: Paths to a config XML file containing projects to add or 476*105f6285SAndroid Build Coastguard Worker remove. See default_config.xml for an example. This flag can be passed 477*105f6285SAndroid Build Coastguard Worker more than once to use multiple config files. 478*105f6285SAndroid Build Coastguard Worker repo_list_file: Path to the output of the 'repo list' command. 479*105f6285SAndroid Build Coastguard Worker ninja_build_file: Path to the combined-<target>.ninja file found in an out 480*105f6285SAndroid Build Coastguard Worker dir. 481*105f6285SAndroid Build Coastguard Worker ninja_binary: Path to the ninja binary. 482*105f6285SAndroid Build Coastguard Worker module_info_file: Path to the module-info.json file found in an out dir. 483*105f6285SAndroid Build Coastguard Worker kati_stamp_file: The path to a .kati_stamp file from a build. 484*105f6285SAndroid Build Coastguard Worker overlays: A list of paths to treat as overlays when parsing the kati stamp 485*105f6285SAndroid Build Coastguard Worker file. 486*105f6285SAndroid Build Coastguard Worker installed_prebuilts: A list of paths for which to create "fake" repo 487*105f6285SAndroid Build Coastguard Worker entries. These entries allow the tool to recognize modules that installed 488*105f6285SAndroid Build Coastguard Worker rather than being sync'd via a manifest. 489*105f6285SAndroid Build Coastguard Worker debug_file: If not None, the path to write JSON debug info. 490*105f6285SAndroid Build Coastguard Worker """ 491*105f6285SAndroid Build Coastguard Worker debug_info = {} 492*105f6285SAndroid Build Coastguard Worker 493*105f6285SAndroid Build Coastguard Worker config = ManifestSplitConfig.from_config_files(config_files) 494*105f6285SAndroid Build Coastguard Worker original_manifest = ET.parse(manifest_file) 495*105f6285SAndroid Build Coastguard Worker 496*105f6285SAndroid Build Coastguard Worker 497*105f6285SAndroid Build Coastguard Worker repo_projects = get_repo_projects(repo_list_file, original_manifest, 498*105f6285SAndroid Build Coastguard Worker config.path_mappings) 499*105f6285SAndroid Build Coastguard Worker repo_projects.update({ip: ip for ip in installed_prebuilts}) 500*105f6285SAndroid Build Coastguard Worker 501*105f6285SAndroid Build Coastguard Worker inputs = get_ninja_inputs(ninja_binary, ninja_build_file, targets) 502*105f6285SAndroid Build Coastguard Worker input_projects = set(get_input_projects(repo_projects, inputs).keys()) 503*105f6285SAndroid Build Coastguard Worker for project in input_projects: 504*105f6285SAndroid Build Coastguard Worker debug_info.setdefault(project, DebugInfo()).direct_input = True 505*105f6285SAndroid Build Coastguard Worker logger.info( 506*105f6285SAndroid Build Coastguard Worker "%s projects needed for Ninja-graph direct dependencies of targets \"%s\"", 507*105f6285SAndroid Build Coastguard Worker len(input_projects), " ".join(targets)) 508*105f6285SAndroid Build Coastguard Worker 509*105f6285SAndroid Build Coastguard Worker if kati_stamp_file: 510*105f6285SAndroid Build Coastguard Worker kati_makefiles = get_kati_makefiles(kati_stamp_file, overlays) 511*105f6285SAndroid Build Coastguard Worker kati_makefiles_projects = get_input_projects(repo_projects, kati_makefiles) 512*105f6285SAndroid Build Coastguard Worker for project, makefiles in kati_makefiles_projects.items(): 513*105f6285SAndroid Build Coastguard Worker debug_info.setdefault(project, DebugInfo()).kati_makefiles = makefiles 514*105f6285SAndroid Build Coastguard Worker input_projects = input_projects.union(kati_makefiles_projects.keys()) 515*105f6285SAndroid Build Coastguard Worker logger.info("%s projects after including Kati makefiles projects.", 516*105f6285SAndroid Build Coastguard Worker len(input_projects)) 517*105f6285SAndroid Build Coastguard Worker else: 518*105f6285SAndroid Build Coastguard Worker logger.info("Kati makefiles projects skipped.") 519*105f6285SAndroid Build Coastguard Worker 520*105f6285SAndroid Build Coastguard Worker for project, cfile in config.add_projects.items(): 521*105f6285SAndroid Build Coastguard Worker debug_info.setdefault(project, DebugInfo()).manual_add_config = cfile 522*105f6285SAndroid Build Coastguard Worker for project, cfile in config.remove_projects.items(): 523*105f6285SAndroid Build Coastguard Worker debug_info.setdefault(project, DebugInfo()).manual_remove_config = cfile 524*105f6285SAndroid Build Coastguard Worker input_projects = input_projects.union(config.add_projects.keys()) 525*105f6285SAndroid Build Coastguard Worker logger.info("%s projects after including manual additions.", 526*105f6285SAndroid Build Coastguard Worker len(input_projects)) 527*105f6285SAndroid Build Coastguard Worker 528*105f6285SAndroid Build Coastguard Worker # Remove projects from our set of input projects before adding adjacent 529*105f6285SAndroid Build Coastguard Worker # modules, so that no project is added only because of an adjacent 530*105f6285SAndroid Build Coastguard Worker # dependency in a to-be-removed project. 531*105f6285SAndroid Build Coastguard Worker input_projects = input_projects.difference(config.remove_projects.keys()) 532*105f6285SAndroid Build Coastguard Worker 533*105f6285SAndroid Build Coastguard Worker # While we still have projects whose modules we haven't checked yet, 534*105f6285SAndroid Build Coastguard Worker if module_info_file: 535*105f6285SAndroid Build Coastguard Worker module_info = ModuleInfo(module_info_file, repo_projects, 536*105f6285SAndroid Build Coastguard Worker config.ignore_paths) 537*105f6285SAndroid Build Coastguard Worker checked_projects = set() 538*105f6285SAndroid Build Coastguard Worker projects_to_check = input_projects.difference(checked_projects) 539*105f6285SAndroid Build Coastguard Worker logger.info("Checking module-info dependencies for direct and adjacent modules...") 540*105f6285SAndroid Build Coastguard Worker else: 541*105f6285SAndroid Build Coastguard Worker logging.info("Direct and adjacent modules skipped.") 542*105f6285SAndroid Build Coastguard Worker projects_to_check = None 543*105f6285SAndroid Build Coastguard Worker 544*105f6285SAndroid Build Coastguard Worker iteration = 0 545*105f6285SAndroid Build Coastguard Worker 546*105f6285SAndroid Build Coastguard Worker while projects_to_check: 547*105f6285SAndroid Build Coastguard Worker iteration += 1 548*105f6285SAndroid Build Coastguard Worker # check all modules in each project, 549*105f6285SAndroid Build Coastguard Worker modules = [] 550*105f6285SAndroid Build Coastguard Worker deps_additions = set() 551*105f6285SAndroid Build Coastguard Worker 552*105f6285SAndroid Build Coastguard Worker def process_deps(module): 553*105f6285SAndroid Build Coastguard Worker for d in module_info.module_deps[module]: 554*105f6285SAndroid Build Coastguard Worker if d in module_info.module_class: 555*105f6285SAndroid Build Coastguard Worker if module_info.module_class[d] == "HEADER_LIBRARIES": 556*105f6285SAndroid Build Coastguard Worker hla = module_info.module_project[d] 557*105f6285SAndroid Build Coastguard Worker if hla not in input_projects: 558*105f6285SAndroid Build Coastguard Worker deps_additions.add(hla) 559*105f6285SAndroid Build Coastguard Worker 560*105f6285SAndroid Build Coastguard Worker for project in projects_to_check: 561*105f6285SAndroid Build Coastguard Worker checked_projects.add(project) 562*105f6285SAndroid Build Coastguard Worker if project not in module_info.project_modules: 563*105f6285SAndroid Build Coastguard Worker continue 564*105f6285SAndroid Build Coastguard Worker for module in module_info.project_modules[project]: 565*105f6285SAndroid Build Coastguard Worker modules.append(module) 566*105f6285SAndroid Build Coastguard Worker process_deps(module) 567*105f6285SAndroid Build Coastguard Worker 568*105f6285SAndroid Build Coastguard Worker for project in deps_additions: 569*105f6285SAndroid Build Coastguard Worker debug_info.setdefault(project, DebugInfo()).deps_input = True 570*105f6285SAndroid Build Coastguard Worker input_projects = input_projects.union(deps_additions) 571*105f6285SAndroid Build Coastguard Worker logger.info( 572*105f6285SAndroid Build Coastguard Worker "pass %d - %d projects after including HEADER_LIBRARIES dependencies", 573*105f6285SAndroid Build Coastguard Worker iteration, len(input_projects)) 574*105f6285SAndroid Build Coastguard Worker 575*105f6285SAndroid Build Coastguard Worker # adding those modules' input projects to our list of projects. 576*105f6285SAndroid Build Coastguard Worker inputs = get_ninja_inputs(ninja_binary, ninja_build_file, modules) 577*105f6285SAndroid Build Coastguard Worker adjacent_module_additions = set( 578*105f6285SAndroid Build Coastguard Worker get_input_projects(repo_projects, inputs).keys()) 579*105f6285SAndroid Build Coastguard Worker for project in adjacent_module_additions: 580*105f6285SAndroid Build Coastguard Worker debug_info.setdefault(project, DebugInfo()).adjacent_input = True 581*105f6285SAndroid Build Coastguard Worker input_projects = input_projects.union(adjacent_module_additions) 582*105f6285SAndroid Build Coastguard Worker logger.info( 583*105f6285SAndroid Build Coastguard Worker "pass %d - %d projects after including adjacent-module Ninja-graph dependencies", 584*105f6285SAndroid Build Coastguard Worker iteration, len(input_projects)) 585*105f6285SAndroid Build Coastguard Worker 586*105f6285SAndroid Build Coastguard Worker projects_to_check = input_projects.difference(checked_projects) 587*105f6285SAndroid Build Coastguard Worker 588*105f6285SAndroid Build Coastguard Worker logger.info("%s projects - complete", len(input_projects)) 589*105f6285SAndroid Build Coastguard Worker 590*105f6285SAndroid Build Coastguard Worker split_manifest = update_manifest(original_manifest, input_projects, 591*105f6285SAndroid Build Coastguard Worker config.remove_projects.keys()) 592*105f6285SAndroid Build Coastguard Worker split_manifest.write(split_manifest_file) 593*105f6285SAndroid Build Coastguard Worker 594*105f6285SAndroid Build Coastguard Worker if debug_file: 595*105f6285SAndroid Build Coastguard Worker with open(debug_file, "w") as debug_fp: 596*105f6285SAndroid Build Coastguard Worker logger.info("Writing debug info to %s", debug_file) 597*105f6285SAndroid Build Coastguard Worker json.dump( 598*105f6285SAndroid Build Coastguard Worker debug_info, 599*105f6285SAndroid Build Coastguard Worker fp=debug_fp, 600*105f6285SAndroid Build Coastguard Worker sort_keys=True, 601*105f6285SAndroid Build Coastguard Worker indent=2, 602*105f6285SAndroid Build Coastguard Worker default=lambda info: info.__dict__) 603*105f6285SAndroid Build Coastguard Worker 604*105f6285SAndroid Build Coastguard Worker 605*105f6285SAndroid Build Coastguard Workerdef main(argv): 606*105f6285SAndroid Build Coastguard Worker try: 607*105f6285SAndroid Build Coastguard Worker opts, args = getopt.getopt(argv, "h", [ 608*105f6285SAndroid Build Coastguard Worker "help", 609*105f6285SAndroid Build Coastguard Worker "debug-file=", 610*105f6285SAndroid Build Coastguard Worker "manifest=", 611*105f6285SAndroid Build Coastguard Worker "split-manifest=", 612*105f6285SAndroid Build Coastguard Worker "config=", 613*105f6285SAndroid Build Coastguard Worker "ignore-default-config", 614*105f6285SAndroid Build Coastguard Worker "repo-list=", 615*105f6285SAndroid Build Coastguard Worker "ninja-build=", 616*105f6285SAndroid Build Coastguard Worker "ninja-binary=", 617*105f6285SAndroid Build Coastguard Worker "module-info=", 618*105f6285SAndroid Build Coastguard Worker "skip-module-info", 619*105f6285SAndroid Build Coastguard Worker "kati-stamp=", 620*105f6285SAndroid Build Coastguard Worker "skip-kati", 621*105f6285SAndroid Build Coastguard Worker "overlay=", 622*105f6285SAndroid Build Coastguard Worker "installed-prebuilt=", 623*105f6285SAndroid Build Coastguard Worker ]) 624*105f6285SAndroid Build Coastguard Worker except getopt.GetoptError as err: 625*105f6285SAndroid Build Coastguard Worker print(__doc__, file=sys.stderr) 626*105f6285SAndroid Build Coastguard Worker print("**%s**" % str(err), file=sys.stderr) 627*105f6285SAndroid Build Coastguard Worker sys.exit(2) 628*105f6285SAndroid Build Coastguard Worker 629*105f6285SAndroid Build Coastguard Worker debug_file = None 630*105f6285SAndroid Build Coastguard Worker manifest_file = None 631*105f6285SAndroid Build Coastguard Worker split_manifest_file = None 632*105f6285SAndroid Build Coastguard Worker config_files = [] 633*105f6285SAndroid Build Coastguard Worker repo_list_file = None 634*105f6285SAndroid Build Coastguard Worker ninja_build_file = None 635*105f6285SAndroid Build Coastguard Worker module_info_file = None 636*105f6285SAndroid Build Coastguard Worker ninja_binary = "prebuilts/build-tools/linux-x86/bin/ninja" 637*105f6285SAndroid Build Coastguard Worker kati_stamp_file = None 638*105f6285SAndroid Build Coastguard Worker overlays = [] 639*105f6285SAndroid Build Coastguard Worker installed_prebuilts = [] 640*105f6285SAndroid Build Coastguard Worker ignore_default_config = False 641*105f6285SAndroid Build Coastguard Worker skip_kati = False 642*105f6285SAndroid Build Coastguard Worker skip_module_info = False 643*105f6285SAndroid Build Coastguard Worker 644*105f6285SAndroid Build Coastguard Worker for o, a in opts: 645*105f6285SAndroid Build Coastguard Worker if o in ("-h", "--help"): 646*105f6285SAndroid Build Coastguard Worker print(__doc__, file=sys.stderr) 647*105f6285SAndroid Build Coastguard Worker sys.exit() 648*105f6285SAndroid Build Coastguard Worker elif o in ("--debug-file"): 649*105f6285SAndroid Build Coastguard Worker debug_file = a 650*105f6285SAndroid Build Coastguard Worker elif o in ("--manifest"): 651*105f6285SAndroid Build Coastguard Worker manifest_file = a 652*105f6285SAndroid Build Coastguard Worker elif o in ("--split-manifest"): 653*105f6285SAndroid Build Coastguard Worker split_manifest_file = a 654*105f6285SAndroid Build Coastguard Worker elif o in ("--config"): 655*105f6285SAndroid Build Coastguard Worker config_files.append(a) 656*105f6285SAndroid Build Coastguard Worker elif o == "--ignore-default-config": 657*105f6285SAndroid Build Coastguard Worker ignore_default_config = True 658*105f6285SAndroid Build Coastguard Worker elif o in ("--repo-list"): 659*105f6285SAndroid Build Coastguard Worker repo_list_file = a 660*105f6285SAndroid Build Coastguard Worker elif o in ("--ninja-build"): 661*105f6285SAndroid Build Coastguard Worker ninja_build_file = a 662*105f6285SAndroid Build Coastguard Worker elif o in ("--ninja-binary"): 663*105f6285SAndroid Build Coastguard Worker ninja_binary = a 664*105f6285SAndroid Build Coastguard Worker elif o in ("--module-info"): 665*105f6285SAndroid Build Coastguard Worker module_info_file = a 666*105f6285SAndroid Build Coastguard Worker elif o == "--skip-module-info": 667*105f6285SAndroid Build Coastguard Worker skip_module_info = True 668*105f6285SAndroid Build Coastguard Worker elif o in ("--kati-stamp"): 669*105f6285SAndroid Build Coastguard Worker kati_stamp_file = a 670*105f6285SAndroid Build Coastguard Worker elif o == "--skip-kati": 671*105f6285SAndroid Build Coastguard Worker skip_kati = True 672*105f6285SAndroid Build Coastguard Worker elif o in ("--overlay"): 673*105f6285SAndroid Build Coastguard Worker overlays.append(a) 674*105f6285SAndroid Build Coastguard Worker elif o in ("--installed-prebuilt"): 675*105f6285SAndroid Build Coastguard Worker installed_prebuilts.append(a) 676*105f6285SAndroid Build Coastguard Worker else: 677*105f6285SAndroid Build Coastguard Worker assert False, "unknown option \"%s\"" % o 678*105f6285SAndroid Build Coastguard Worker 679*105f6285SAndroid Build Coastguard Worker if not args: 680*105f6285SAndroid Build Coastguard Worker print(__doc__, file=sys.stderr) 681*105f6285SAndroid Build Coastguard Worker print("**Missing targets**", file=sys.stderr) 682*105f6285SAndroid Build Coastguard Worker sys.exit(2) 683*105f6285SAndroid Build Coastguard Worker if not manifest_file: 684*105f6285SAndroid Build Coastguard Worker print(__doc__, file=sys.stderr) 685*105f6285SAndroid Build Coastguard Worker print("**Missing required flag --manifest**", file=sys.stderr) 686*105f6285SAndroid Build Coastguard Worker sys.exit(2) 687*105f6285SAndroid Build Coastguard Worker if not split_manifest_file: 688*105f6285SAndroid Build Coastguard Worker print(__doc__, file=sys.stderr) 689*105f6285SAndroid Build Coastguard Worker print("**Missing required flag --split-manifest**", file=sys.stderr) 690*105f6285SAndroid Build Coastguard Worker sys.exit(2) 691*105f6285SAndroid Build Coastguard Worker 692*105f6285SAndroid Build Coastguard Worker if skip_module_info: 693*105f6285SAndroid Build Coastguard Worker if module_info_file: 694*105f6285SAndroid Build Coastguard Worker logging.warning("User provided both --skip-module-info and --module-info args. Arg --module-info ignored.") 695*105f6285SAndroid Build Coastguard Worker module_info_file = None 696*105f6285SAndroid Build Coastguard Worker elif not module_info_file: 697*105f6285SAndroid Build Coastguard Worker module_info_file = os.path.join(os.environ["ANDROID_PRODUCT_OUT"], 698*105f6285SAndroid Build Coastguard Worker "module-info.json") 699*105f6285SAndroid Build Coastguard Worker if skip_kati: 700*105f6285SAndroid Build Coastguard Worker if kati_stamp_file: 701*105f6285SAndroid Build Coastguard Worker logging.warning("User provided both --skip-kati and --kati-stamp args. Arg --kati-stamp ignored.") 702*105f6285SAndroid Build Coastguard Worker kati_stamp_file = None 703*105f6285SAndroid Build Coastguard Worker elif not kati_stamp_file: 704*105f6285SAndroid Build Coastguard Worker kati_stamp_file = os.path.join( 705*105f6285SAndroid Build Coastguard Worker os.environ["ANDROID_BUILD_TOP"], "out", 706*105f6285SAndroid Build Coastguard Worker ".kati_stamp-%s" % os.environ["TARGET_PRODUCT"]) 707*105f6285SAndroid Build Coastguard Worker 708*105f6285SAndroid Build Coastguard Worker if not ninja_build_file: 709*105f6285SAndroid Build Coastguard Worker ninja_build_file = os.path.join( 710*105f6285SAndroid Build Coastguard Worker os.environ["ANDROID_BUILD_TOP"], "out", 711*105f6285SAndroid Build Coastguard Worker "combined-%s.ninja" % os.environ["TARGET_PRODUCT"]) 712*105f6285SAndroid Build Coastguard Worker 713*105f6285SAndroid Build Coastguard Worker with tempfile.NamedTemporaryFile() as default_config_file: 714*105f6285SAndroid Build Coastguard Worker if not ignore_default_config: 715*105f6285SAndroid Build Coastguard Worker default_config_file.write(pkgutil.get_data(__name__, DEFAULT_CONFIG_XML)) 716*105f6285SAndroid Build Coastguard Worker default_config_file.flush() 717*105f6285SAndroid Build Coastguard Worker config_files.insert(0, default_config_file.name) 718*105f6285SAndroid Build Coastguard Worker 719*105f6285SAndroid Build Coastguard Worker create_split_manifest( 720*105f6285SAndroid Build Coastguard Worker targets=args, 721*105f6285SAndroid Build Coastguard Worker manifest_file=manifest_file, 722*105f6285SAndroid Build Coastguard Worker split_manifest_file=split_manifest_file, 723*105f6285SAndroid Build Coastguard Worker config_files=config_files, 724*105f6285SAndroid Build Coastguard Worker repo_list_file=repo_list_file, 725*105f6285SAndroid Build Coastguard Worker ninja_build_file=ninja_build_file, 726*105f6285SAndroid Build Coastguard Worker ninja_binary=ninja_binary, 727*105f6285SAndroid Build Coastguard Worker module_info_file=module_info_file, 728*105f6285SAndroid Build Coastguard Worker kati_stamp_file=kati_stamp_file, 729*105f6285SAndroid Build Coastguard Worker overlays=overlays, 730*105f6285SAndroid Build Coastguard Worker installed_prebuilts=installed_prebuilts, 731*105f6285SAndroid Build Coastguard Worker debug_file=debug_file) 732*105f6285SAndroid Build Coastguard Worker 733*105f6285SAndroid Build Coastguard Worker 734*105f6285SAndroid Build Coastguard Workerif __name__ == "__main__": 735*105f6285SAndroid Build Coastguard Worker main(sys.argv[1:]) 736