1*90c8c64dSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*90c8c64dSAndroid Build Coastguard Worker 3*90c8c64dSAndroid Build Coastguard Worker# 4*90c8c64dSAndroid Build Coastguard Worker# Copyright (C) 2018 The Android Open Source Project 5*90c8c64dSAndroid Build Coastguard Worker# 6*90c8c64dSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 7*90c8c64dSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 8*90c8c64dSAndroid Build Coastguard Worker# You may obtain a copy of the License at 9*90c8c64dSAndroid Build Coastguard Worker# 10*90c8c64dSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 11*90c8c64dSAndroid Build Coastguard Worker# 12*90c8c64dSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 13*90c8c64dSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 14*90c8c64dSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15*90c8c64dSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 16*90c8c64dSAndroid Build Coastguard Worker# limitations under the License. 17*90c8c64dSAndroid Build Coastguard Worker# 18*90c8c64dSAndroid Build Coastguard Worker 19*90c8c64dSAndroid Build Coastguard Worker"""This script scans all Android.bp in an android source tree and check the 20*90c8c64dSAndroid Build Coastguard Workercorrectness of dependencies.""" 21*90c8c64dSAndroid Build Coastguard Worker 22*90c8c64dSAndroid Build Coastguard Workerimport copy 23*90c8c64dSAndroid Build Coastguard Worker 24*90c8c64dSAndroid Build Coastguard Workerfrom blueprint import RecursiveParser, evaluate_defaults, fill_module_namespaces 25*90c8c64dSAndroid Build Coastguard Worker 26*90c8c64dSAndroid Build Coastguard Worker 27*90c8c64dSAndroid Build Coastguard Workerclass Module(object): 28*90c8c64dSAndroid Build Coastguard Worker """The class for Blueprint module definition.""" 29*90c8c64dSAndroid Build Coastguard Worker 30*90c8c64dSAndroid Build Coastguard Worker def __init__(self, rule, attrs): 31*90c8c64dSAndroid Build Coastguard Worker """Initialize from a module definition.""" 32*90c8c64dSAndroid Build Coastguard Worker self.rule = rule 33*90c8c64dSAndroid Build Coastguard Worker self._attrs = attrs 34*90c8c64dSAndroid Build Coastguard Worker 35*90c8c64dSAndroid Build Coastguard Worker 36*90c8c64dSAndroid Build Coastguard Worker def get_property(self, *names, **kwargs): 37*90c8c64dSAndroid Build Coastguard Worker """Get a property in the module definition.""" 38*90c8c64dSAndroid Build Coastguard Worker try: 39*90c8c64dSAndroid Build Coastguard Worker result = self._attrs 40*90c8c64dSAndroid Build Coastguard Worker for name in names: 41*90c8c64dSAndroid Build Coastguard Worker result = result[name] 42*90c8c64dSAndroid Build Coastguard Worker return result 43*90c8c64dSAndroid Build Coastguard Worker except KeyError: 44*90c8c64dSAndroid Build Coastguard Worker return kwargs.get('default', None) 45*90c8c64dSAndroid Build Coastguard Worker 46*90c8c64dSAndroid Build Coastguard Worker 47*90c8c64dSAndroid Build Coastguard Worker def is_vndk(self): 48*90c8c64dSAndroid Build Coastguard Worker """Check whether this module is a VNDK shared library.""" 49*90c8c64dSAndroid Build Coastguard Worker return bool(self.get_property('vndk', 'enabled')) 50*90c8c64dSAndroid Build Coastguard Worker 51*90c8c64dSAndroid Build Coastguard Worker 52*90c8c64dSAndroid Build Coastguard Worker def is_vndk_sp(self): 53*90c8c64dSAndroid Build Coastguard Worker """Check whether this module is a VNDK-SP shared library.""" 54*90c8c64dSAndroid Build Coastguard Worker return bool(self.get_property('vndk', 'support_system_process')) 55*90c8c64dSAndroid Build Coastguard Worker 56*90c8c64dSAndroid Build Coastguard Worker 57*90c8c64dSAndroid Build Coastguard Worker def is_vendor(self): 58*90c8c64dSAndroid Build Coastguard Worker """Check whether this module is a vendor module.""" 59*90c8c64dSAndroid Build Coastguard Worker return bool(self.get_property('vendor') or 60*90c8c64dSAndroid Build Coastguard Worker self.get_property('proprietary')) 61*90c8c64dSAndroid Build Coastguard Worker 62*90c8c64dSAndroid Build Coastguard Worker 63*90c8c64dSAndroid Build Coastguard Worker def is_vendor_available(self): 64*90c8c64dSAndroid Build Coastguard Worker """Check whether this module is vendor available.""" 65*90c8c64dSAndroid Build Coastguard Worker return bool(self.get_property('vendor_available')) 66*90c8c64dSAndroid Build Coastguard Worker 67*90c8c64dSAndroid Build Coastguard Worker 68*90c8c64dSAndroid Build Coastguard Worker def has_vendor_variant(self): 69*90c8c64dSAndroid Build Coastguard Worker """Check whether the module is VNDK or vendor available.""" 70*90c8c64dSAndroid Build Coastguard Worker return self.is_vndk() or self.is_vendor_available() 71*90c8c64dSAndroid Build Coastguard Worker 72*90c8c64dSAndroid Build Coastguard Worker 73*90c8c64dSAndroid Build Coastguard Worker def get_name(self): 74*90c8c64dSAndroid Build Coastguard Worker """Get the module name.""" 75*90c8c64dSAndroid Build Coastguard Worker return self.get_property('name') 76*90c8c64dSAndroid Build Coastguard Worker 77*90c8c64dSAndroid Build Coastguard Worker 78*90c8c64dSAndroid Build Coastguard Worker def get_dependencies(self): 79*90c8c64dSAndroid Build Coastguard Worker """Get module dependencies.""" 80*90c8c64dSAndroid Build Coastguard Worker 81*90c8c64dSAndroid Build Coastguard Worker shared_libs = set(self.get_property('shared_libs', default=[])) 82*90c8c64dSAndroid Build Coastguard Worker static_libs = set(self.get_property('static_libs', default=[])) 83*90c8c64dSAndroid Build Coastguard Worker header_libs = set(self.get_property('header_libs', default=[])) 84*90c8c64dSAndroid Build Coastguard Worker 85*90c8c64dSAndroid Build Coastguard Worker target_vendor = self.get_property('target', 'vendor') 86*90c8c64dSAndroid Build Coastguard Worker if target_vendor: 87*90c8c64dSAndroid Build Coastguard Worker shared_libs -= set(target_vendor.get('exclude_shared_libs', [])) 88*90c8c64dSAndroid Build Coastguard Worker static_libs -= set(target_vendor.get('exclude_static_libs', [])) 89*90c8c64dSAndroid Build Coastguard Worker header_libs -= set(target_vendor.get('exclude_header_libs', [])) 90*90c8c64dSAndroid Build Coastguard Worker 91*90c8c64dSAndroid Build Coastguard Worker return (sorted(shared_libs), sorted(static_libs), sorted(header_libs)) 92*90c8c64dSAndroid Build Coastguard Worker 93*90c8c64dSAndroid Build Coastguard Worker 94*90c8c64dSAndroid Build Coastguard Workerclass ModuleClassifier(object): 95*90c8c64dSAndroid Build Coastguard Worker """Dictionaries (all_libs, vndk_libs, vndk_sp_libs, 96*90c8c64dSAndroid Build Coastguard Worker vendor_available_libs, and llndk_libs) for modules.""" 97*90c8c64dSAndroid Build Coastguard Worker 98*90c8c64dSAndroid Build Coastguard Worker 99*90c8c64dSAndroid Build Coastguard Worker def __init__(self): 100*90c8c64dSAndroid Build Coastguard Worker self.all_libs = {} 101*90c8c64dSAndroid Build Coastguard Worker self.vndk_libs = {} 102*90c8c64dSAndroid Build Coastguard Worker self.vndk_sp_libs = {} 103*90c8c64dSAndroid Build Coastguard Worker self.vendor_available_libs = {} 104*90c8c64dSAndroid Build Coastguard Worker self.llndk_libs = {} 105*90c8c64dSAndroid Build Coastguard Worker 106*90c8c64dSAndroid Build Coastguard Worker 107*90c8c64dSAndroid Build Coastguard Worker def add_module(self, name, module): 108*90c8c64dSAndroid Build Coastguard Worker """Add a module to one or more dictionaries.""" 109*90c8c64dSAndroid Build Coastguard Worker 110*90c8c64dSAndroid Build Coastguard Worker # If this is an llndk_library, add the module to llndk_libs and return. 111*90c8c64dSAndroid Build Coastguard Worker if module.rule == 'llndk_library': 112*90c8c64dSAndroid Build Coastguard Worker if name in self.llndk_libs: 113*90c8c64dSAndroid Build Coastguard Worker raise ValueError('lldnk name {!r} conflicts'.format(name)) 114*90c8c64dSAndroid Build Coastguard Worker self.llndk_libs[name] = module 115*90c8c64dSAndroid Build Coastguard Worker return 116*90c8c64dSAndroid Build Coastguard Worker 117*90c8c64dSAndroid Build Coastguard Worker # Check the module name uniqueness. 118*90c8c64dSAndroid Build Coastguard Worker prev_module = self.all_libs.get(name) 119*90c8c64dSAndroid Build Coastguard Worker if prev_module: 120*90c8c64dSAndroid Build Coastguard Worker # If there are two modules with the same module name, pick the one 121*90c8c64dSAndroid Build Coastguard Worker # without _prebuilt_library_shared. 122*90c8c64dSAndroid Build Coastguard Worker if module.rule.endswith('_prebuilt_library_shared'): 123*90c8c64dSAndroid Build Coastguard Worker return 124*90c8c64dSAndroid Build Coastguard Worker if not prev_module.rule.endswith('_prebuilt_library_shared'): 125*90c8c64dSAndroid Build Coastguard Worker raise ValueError('module name {!r} conflicts'.format(name)) 126*90c8c64dSAndroid Build Coastguard Worker 127*90c8c64dSAndroid Build Coastguard Worker # Add the module to dictionaries. 128*90c8c64dSAndroid Build Coastguard Worker self.all_libs[name] = module 129*90c8c64dSAndroid Build Coastguard Worker 130*90c8c64dSAndroid Build Coastguard Worker if module.is_vndk(): 131*90c8c64dSAndroid Build Coastguard Worker self.vndk_libs[name] = module 132*90c8c64dSAndroid Build Coastguard Worker 133*90c8c64dSAndroid Build Coastguard Worker if module.is_vndk_sp(): 134*90c8c64dSAndroid Build Coastguard Worker self.vndk_sp_libs[name] = module 135*90c8c64dSAndroid Build Coastguard Worker 136*90c8c64dSAndroid Build Coastguard Worker if module.is_vendor_available(): 137*90c8c64dSAndroid Build Coastguard Worker self.vendor_available_libs[name] = module 138*90c8c64dSAndroid Build Coastguard Worker 139*90c8c64dSAndroid Build Coastguard Worker 140*90c8c64dSAndroid Build Coastguard Worker def _add_modules_from_parsed_pairs(self, parsed_items, namespaces): 141*90c8c64dSAndroid Build Coastguard Worker """Add modules from the parsed (rule, attrs) pairs.""" 142*90c8c64dSAndroid Build Coastguard Worker 143*90c8c64dSAndroid Build Coastguard Worker for rule, attrs in parsed_items: 144*90c8c64dSAndroid Build Coastguard Worker name = attrs.get('name') 145*90c8c64dSAndroid Build Coastguard Worker if name is None: 146*90c8c64dSAndroid Build Coastguard Worker continue 147*90c8c64dSAndroid Build Coastguard Worker 148*90c8c64dSAndroid Build Coastguard Worker namespace = attrs.get('_namespace') 149*90c8c64dSAndroid Build Coastguard Worker if namespace not in namespaces: 150*90c8c64dSAndroid Build Coastguard Worker continue 151*90c8c64dSAndroid Build Coastguard Worker 152*90c8c64dSAndroid Build Coastguard Worker if rule == 'llndk_library': 153*90c8c64dSAndroid Build Coastguard Worker self.add_module(name, Module(rule, attrs)) 154*90c8c64dSAndroid Build Coastguard Worker if rule in {'llndk_library', 'ndk_library'}: 155*90c8c64dSAndroid Build Coastguard Worker continue 156*90c8c64dSAndroid Build Coastguard Worker 157*90c8c64dSAndroid Build Coastguard Worker if rule.endswith('_library') or \ 158*90c8c64dSAndroid Build Coastguard Worker rule.endswith('_library_shared') or \ 159*90c8c64dSAndroid Build Coastguard Worker rule.endswith('_library_static') or \ 160*90c8c64dSAndroid Build Coastguard Worker rule.endswith('_headers'): 161*90c8c64dSAndroid Build Coastguard Worker self.add_module(name, Module(rule, attrs)) 162*90c8c64dSAndroid Build Coastguard Worker continue 163*90c8c64dSAndroid Build Coastguard Worker 164*90c8c64dSAndroid Build Coastguard Worker if rule == 'hidl_interface': 165*90c8c64dSAndroid Build Coastguard Worker attrs['vendor_available'] = True 166*90c8c64dSAndroid Build Coastguard Worker self.add_module(name, Module(rule, attrs)) 167*90c8c64dSAndroid Build Coastguard Worker 168*90c8c64dSAndroid Build Coastguard Worker adapter_module_name = name + '-adapter-helper' 169*90c8c64dSAndroid Build Coastguard Worker adapter_module_dict = copy.deepcopy(attrs) 170*90c8c64dSAndroid Build Coastguard Worker adapter_module_dict['name'] = adapter_module_name 171*90c8c64dSAndroid Build Coastguard Worker self.add_module(adapter_module_name, 172*90c8c64dSAndroid Build Coastguard Worker Module(rule, adapter_module_dict)) 173*90c8c64dSAndroid Build Coastguard Worker continue 174*90c8c64dSAndroid Build Coastguard Worker 175*90c8c64dSAndroid Build Coastguard Worker 176*90c8c64dSAndroid Build Coastguard Worker def parse_root_bp(self, root_bp_path, namespaces=None): 177*90c8c64dSAndroid Build Coastguard Worker """Parse blueprint files and add module definitions.""" 178*90c8c64dSAndroid Build Coastguard Worker 179*90c8c64dSAndroid Build Coastguard Worker namespaces = {''} if namespaces is None else set(namespaces) 180*90c8c64dSAndroid Build Coastguard Worker 181*90c8c64dSAndroid Build Coastguard Worker parser = RecursiveParser() 182*90c8c64dSAndroid Build Coastguard Worker parser.parse_file(root_bp_path) 183*90c8c64dSAndroid Build Coastguard Worker parsed_items = evaluate_defaults(parser.modules) 184*90c8c64dSAndroid Build Coastguard Worker parsed_items = fill_module_namespaces(root_bp_path, parsed_items) 185*90c8c64dSAndroid Build Coastguard Worker 186*90c8c64dSAndroid Build Coastguard Worker self._add_modules_from_parsed_pairs(parsed_items, namespaces) 187*90c8c64dSAndroid Build Coastguard Worker 188*90c8c64dSAndroid Build Coastguard Worker 189*90c8c64dSAndroid Build Coastguard Worker @classmethod 190*90c8c64dSAndroid Build Coastguard Worker def create_from_root_bp(cls, root_bp_path, namespaces=None): 191*90c8c64dSAndroid Build Coastguard Worker """Create a ModuleClassifier from a root blueprint file.""" 192*90c8c64dSAndroid Build Coastguard Worker result = cls() 193*90c8c64dSAndroid Build Coastguard Worker result.parse_root_bp(root_bp_path, namespaces) 194*90c8c64dSAndroid Build Coastguard Worker return result 195