xref: /aosp_15_r20/development/vndk/tools/sourcedr/blueprint/vndk.py (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
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