• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#  Copyright The ANGLE Project Authors. All rights reserved.
2#  Use of this source code is governed by a BSD-style license that can be
3#  found in the LICENSE file.
4#
5# Generates an Android.bp file from the json output of 4 'gn desc' commands.
6# Invoked during Skia rolls by roll_aosp.sh. For local testing, see:
7#  scripts/roll_aosp.sh --genAndroidBp
8
9import json
10import sys
11import re
12import os
13import argparse
14import functools
15import collections
16
17ROOT_TARGETS = [
18    "//:libGLESv2",
19    "//:libGLESv1_CM",
20    "//:libEGL",
21]
22
23MIN_SDK_VERSION = '28'
24TARGET_SDK_VERSION = '33'
25STL = 'libc++_static'
26
27ABI_ARM = 'arm'
28ABI_ARM64 = 'arm64'
29ABI_X86 = 'x86'
30ABI_X64 = 'x86_64'
31
32ABI_TARGETS = [ABI_ARM, ABI_ARM64, ABI_X86, ABI_X64]
33
34
35def gn_abi(abi):
36    # gn uses x64, rather than x86_64
37    return 'x64' if abi == ABI_X64 else abi
38
39
40# Makes dict cache-able "by reference" (assumed not to be mutated)
41class BuildInfo(dict):
42
43    def __hash__(self):
44        return 0
45
46    def __eq__(self, other):
47        return self is other
48
49
50def tabs(indent):
51    return ' ' * (indent * 4)
52
53
54def has_child_values(value):
55    # Elements of the blueprint can be pruned if they are empty lists or dictionaries of empty
56    # lists
57    if isinstance(value, list):
58        return len(value) > 0
59    if isinstance(value, dict):
60        for (item, item_value) in value.items():
61            if has_child_values(item_value):
62                return True
63        return False
64
65    # This is a value leaf node
66    return True
67
68
69def write_blueprint_key_value(output, name, value, indent=1):
70    if not has_child_values(value):
71        return
72
73    if isinstance(value, set) or isinstance(value, list):
74        value = list(sorted(set(value)))
75
76    if isinstance(value, list):
77        output.append(tabs(indent) + '%s: [' % name)
78        for item in value:
79            output.append(tabs(indent + 1) + '"%s",' % item)
80        output.append(tabs(indent) + '],')
81        return
82    if isinstance(value, dict):
83        if not value:
84            return
85        output.append(tabs(indent) + '%s: {' % name)
86        for (item, item_value) in value.items():
87            write_blueprint_key_value(output, item, item_value, indent + 1)
88        output.append(tabs(indent) + '},')
89        return
90    if isinstance(value, bool):
91        output.append(tabs(indent) + '%s: %s,' % (name, 'true' if value else 'false'))
92        return
93    output.append(tabs(indent) + '%s: "%s",' % (name, value))
94
95
96def write_blueprint(output, target_type, values):
97    if target_type == 'license':
98        comment = """
99// Added automatically by a large-scale-change that took the approach of
100// 'apply every license found to every target'. While this makes sure we respect
101// every license restriction, it may not be entirely correct.
102//
103// e.g. GPL in an MIT project might only apply to the contrib/ directory.
104//
105// Please consider splitting the single license below into multiple licenses,
106// taking care not to lose any license_kind information, and overriding the
107// default license using the 'licenses: [...]' property on targets as needed.
108//
109// For unused files, consider creating a 'fileGroup' with "//visibility:private"
110// to attach the license to, and including a comment whether the files may be
111// used in the current project.
112// See: http://go/android-license-faq"""
113        output.append(comment)
114
115    output.append('')
116    output.append('%s {' % target_type)
117    for (key, value) in values.items():
118        write_blueprint_key_value(output, key, value)
119    output.append('}')
120
121
122def gn_target_to_blueprint_target(target, target_info):
123    if 'output_name' in target_info:
124        return target_info['output_name']
125
126    # Split the gn target name (in the form of //gn_file_path:target_name) into gn_file_path and
127    # target_name
128    match = re.match(r"^//([a-zA-Z0-9\-\+_/]*):([a-zA-Z0-9\-\+_.]+)$", target)
129    assert match is not None
130
131    gn_file_path = match.group(1)
132    target_name = match.group(2)
133    assert len(target_name) > 0
134
135    # Clean up the gn file path to be a valid blueprint target name.
136    gn_file_path = gn_file_path.replace("/", "_").replace(".", "_").replace("-", "_")
137
138    # Generate a blueprint target name by merging the gn path and target so each target is unique.
139    # Prepend the 'angle' prefix to all targets in the root path (empty gn_file_path).
140    # Skip this step if the target name already starts with 'angle' to avoid target names such as 'angle_angle_common'.
141    root_prefix = "angle"
142    if len(gn_file_path) == 0 and not target_name.startswith(root_prefix):
143        gn_file_path = root_prefix
144
145    # Avoid names such as _angle_common if the gn_file_path is empty.
146    if len(gn_file_path) > 0:
147        gn_file_path += "_"
148
149    return gn_file_path + target_name
150
151
152def remap_gn_path(path):
153    # TODO: pass the gn gen folder as an arg so it is future proof. b/150457277
154    remap_folders = [
155        ('out/Android/gen/angle/', ''),
156        ('out/Android/gen/', ''),
157    ]
158
159    remapped_path = path
160    for (remap_source, remap_dest) in remap_folders:
161        remapped_path = remapped_path.replace(remap_source, remap_dest)
162
163    return remapped_path
164
165
166def gn_path_to_blueprint_path(source):
167    # gn uses '//' to indicate the root directory, blueprint uses the .bp file's location
168    return remap_gn_path(re.sub(r'^//?', '', source))
169
170
171def gn_paths_to_blueprint_paths(paths):
172    rebased_paths = []
173    for path in paths:
174        rebased_paths.append(gn_path_to_blueprint_path(path))
175    return rebased_paths
176
177
178def gn_sources_to_blueprint_sources(sources):
179    # Blueprints only list source files in the sources list. Headers are only referenced though
180    # include paths.
181    file_extension_allowlist = [
182        '.c',
183        '.cc',
184        '.cpp',
185    ]
186
187    rebased_sources = []
188    for source in sources:
189        if os.path.splitext(source)[1] in file_extension_allowlist:
190            rebased_sources.append(gn_path_to_blueprint_path(source))
191    return rebased_sources
192
193
194target_blockist = [
195    '//build/config:shared_library_deps',
196    '//third_party/vulkan-validation-layers/src:vulkan_clean_old_validation_layer_objects',
197    '//third_party/zlib:zlib',
198    '//third_party/zlib/google:compression_utils_portable',
199]
200
201third_party_target_allowlist = [
202    '//third_party/abseil-cpp',
203    '//third_party/glslang/src',
204    '//third_party/spirv-cross/src',
205    '//third_party/spirv-headers/src',
206    '//third_party/spirv-tools/src',
207    '//third_party/vulkan-headers/src',
208    '//third_party/vulkan-loader/src',
209    '//third_party/vulkan-tools/src',
210    '//third_party/vulkan-utility-libraries/src',
211    '//third_party/vulkan-validation-layers/src',
212    '//third_party/vulkan_memory_allocator',
213]
214
215include_blocklist = [
216    '//buildtools/third_party/libc++/',
217    '//third_party/libc++/src/',
218    '//out/Android/gen/third_party/glslang/src/include/',
219    '//third_party/zlib/',
220    '//third_party/zlib/google/',
221]
222
223
224@functools.lru_cache(maxsize=None)  # .cache() is py3.9 http://b/246559064#comment8
225def gn_deps_to_blueprint_deps(abi, target, build_info):
226    target_info = build_info[abi][target]
227    static_libs = []
228    shared_libs = []
229    defaults = []
230    generated_headers = []
231    header_libs = []
232    if 'deps' not in target_info:
233        return static_libs, defaults
234
235    for dep in target_info['deps']:
236        if dep not in target_blockist and (not dep.startswith('//third_party') or any(
237                dep.startswith(substring) for substring in third_party_target_allowlist)):
238            dep_info = build_info[abi][dep]
239            blueprint_dep_name = gn_target_to_blueprint_target(dep, dep_info)
240
241            # Depending on the dep type, blueprints reference it differently.
242            gn_dep_type = dep_info['type']
243            if gn_dep_type == 'static_library':
244                static_libs.append(blueprint_dep_name)
245            elif gn_dep_type == 'shared_library':
246                shared_libs.append(blueprint_dep_name)
247            elif gn_dep_type == 'source_set' or gn_dep_type == 'group':
248                defaults.append(blueprint_dep_name)
249            elif gn_dep_type == 'action':
250                generated_headers.append(blueprint_dep_name)
251
252            # Blueprints do not chain linking of static libraries.
253            (child_static_libs, _, _, child_generated_headers,
254             _) = gn_deps_to_blueprint_deps(abi, dep, build_info)
255
256            # Each target needs to link all child static library dependencies.
257            static_libs += child_static_libs
258
259            # Each blueprint target runs genrules in a different output directory unlike GN. If a
260            # target depends on another's genrule, it wont find the outputs. Propogate generated
261            # headers up the dependency stack.
262            generated_headers += child_generated_headers
263        elif dep == '//third_party/zlib/google:compression_utils_portable':
264            # Replace zlib by Android's zlib, compression_utils_portable is the root dependency
265            shared_libs.append('libz')
266            static_libs.extend(['zlib_google_compression_utils_portable', 'cpufeatures'])
267
268    return static_libs, shared_libs, defaults, generated_headers, header_libs
269
270
271def gn_libs_to_blueprint_shared_libraries(target_info):
272    lib_blockist = [
273        'android_support',
274        'unwind',
275    ]
276
277    result = []
278    if 'libs' in target_info:
279        for lib in target_info['libs']:
280            if lib not in lib_blockist:
281                android_lib = lib if '@' in lib else 'lib' + lib
282                result.append(android_lib)
283    return result
284
285
286def gn_include_dirs_to_blueprint_include_dirs(target_info):
287    result = []
288    if 'include_dirs' in target_info:
289        for include_dir in target_info['include_dirs']:
290            if len(include_dir) > 0 and include_dir not in include_blocklist:
291                result.append(gn_path_to_blueprint_path(include_dir))
292    return result
293
294
295def escape_quotes(string):
296    return string.replace("\"", "\\\"").replace("\'", "\\\'")
297
298
299def gn_cflags_to_blueprint_cflags(target_info):
300    result = []
301
302    # regexs of allowlisted cflags
303    cflag_allowlist = [
304        r'^-Wno-.*$',  # forward cflags that disable warnings
305        r'^-fvisibility.*$',  # forward visibility (https://gcc.gnu.org/wiki/Visibility) flags for better perf on x86
306        r'-mpclmul'  # forward "-mpclmul" (used by zlib)
307    ]
308
309    for cflag_type in ['cflags', 'cflags_c', 'cflags_cc']:
310        if cflag_type in target_info:
311            for cflag in target_info[cflag_type]:
312                for allowlisted_cflag in cflag_allowlist:
313                    if re.search(allowlisted_cflag, cflag):
314                        result.append(cflag)
315
316    if 'defines' in target_info:
317        for define in target_info['defines']:
318            # Don't emit ANGLE's CPU-bits define here, it will be part of the arch-specific
319            # information later
320            result.append('-D%s' % escape_quotes(define))
321
322    return result
323
324
325blueprint_library_target_types = {
326    "static_library": "cc_library_static",
327    "shared_library": "cc_library_shared",
328    "source_set": "cc_defaults",
329    "group": "cc_defaults",
330}
331
332
333def merge_bps(bps_for_abis):
334    common_bp = {}
335    for abi in ABI_TARGETS:
336        for key, values in bps_for_abis[abi].items():
337            if not isinstance(values, list):
338                # Assume everything that's not a list is common to all ABIs
339                common_bp[key] = values
340                continue
341
342            # Find list values that are common to all ABIs
343            values_in_all_abis = set.intersection(
344                *[set(bps_for_abis[abi2].get(key, [])) for abi2 in ABI_TARGETS])
345
346            for value in values:
347                if value in values_in_all_abis or key == 'defaults':  # arch-specific defaults are not supported
348                    common_bp.setdefault(key, [])
349                    common_bp[key].append(value)
350                else:
351                    common_bp.setdefault('arch', {abi3: {} for abi3 in ABI_TARGETS})
352                    abi_specific = common_bp['arch'][abi]
353                    abi_specific.setdefault(key, [])
354                    abi_specific[key].append(value)
355
356    return common_bp
357
358
359def library_target_to_blueprint(target, build_info):
360    bps_for_abis = {}
361    blueprint_type = ""
362    for abi in ABI_TARGETS:
363        if target not in build_info[abi].keys():
364            bps_for_abis[abi] = {}
365            continue
366
367        target_info = build_info[abi][target]
368
369        blueprint_type = blueprint_library_target_types[target_info['type']]
370
371        bp = {'name': gn_target_to_blueprint_target(target, target_info)}
372
373        if 'sources' in target_info:
374            bp['srcs'] = gn_sources_to_blueprint_sources(target_info['sources'])
375
376        (bp['static_libs'], bp['shared_libs'], bp['defaults'], bp['generated_headers'],
377         bp['header_libs']) = gn_deps_to_blueprint_deps(abi, target, build_info)
378        bp['shared_libs'] += gn_libs_to_blueprint_shared_libraries(target_info)
379
380        bp['local_include_dirs'] = gn_include_dirs_to_blueprint_include_dirs(target_info)
381
382        bp['cflags'] = gn_cflags_to_blueprint_cflags(target_info)
383
384        bp['defaults'].append('angle_common_library_cflags')
385
386        bp['sdk_version'] = MIN_SDK_VERSION
387        bp['stl'] = STL
388        if target in ROOT_TARGETS:
389            bp['defaults'].append('angle_vendor_cc_defaults')
390        bps_for_abis[abi] = bp
391
392    common_bp = merge_bps(bps_for_abis)
393
394    return blueprint_type, common_bp
395
396
397def gn_action_args_to_blueprint_args(blueprint_inputs, blueprint_outputs, args):
398    # TODO: pass the gn gen folder as an arg so we know how to get from the gen path to the root
399    # path. b/150457277
400    remap_folders = [
401        # Specific special-cases first, since the other will strip the prefixes.
402        ('gen/third_party/glslang/src/include/glslang/build_info.h', 'glslang/build_info.h'),
403        ('third_party/glslang/src', 'external/angle/third_party/glslang/src'),
404        ('../../', ''),
405        ('gen/', ''),
406    ]
407
408    result_args = []
409    for arg in args:
410        # Attempt to find if this arg is a path to one of the inputs. If it is, use the blueprint
411        # $(location <path>) argument instead so the path gets remapped properly to the location
412        # that the script is run from
413        remapped_path_arg = arg
414        for (remap_source, remap_dest) in remap_folders:
415            remapped_path_arg = remapped_path_arg.replace(remap_source, remap_dest)
416
417        if remapped_path_arg in blueprint_inputs or remapped_path_arg in blueprint_outputs:
418            result_args.append('$(location %s)' % remapped_path_arg)
419        elif os.path.basename(remapped_path_arg) in blueprint_outputs:
420            result_args.append('$(location %s)' % os.path.basename(remapped_path_arg))
421        else:
422            result_args.append(remapped_path_arg)
423
424    return result_args
425
426
427blueprint_gen_types = {
428    "action": "cc_genrule",
429}
430
431
432inputs_blocklist = [
433    '//.git/HEAD',
434]
435
436outputs_remap = {
437    'build_info.h': 'glslang/build_info.h',
438}
439
440
441def is_input_in_tool_files(tool_files, input):
442    return input in tool_files
443
444
445# special handling the {{response_file_name}} args in GN:
446# see https://gn.googlesource.com/gn/+/main/docs/reference.md#var_response_file_contents
447# in GN, if we use response_file_contents, the GN build system will automatically
448# write contents specified in response_file_contents arg into a temporary file
449# identified by {{response_file_name}}. However, Android blueprint does not have
450# the matching machanism. Android blueprint does automatically generate the
451# temporary file and does not recognize '{{response_file_name}}'.
452# To solve the problem:
453# 1) replace the '{{response_file_name}}' in command argument with the new
454# temporary file name.
455# 2) write the content specified in 'response_file_contents' to the new temporary
456# file
457# This function completes step 1) above. It checks if there are
458# '{{response_file_name}}' used in the command arguments. If there are,
459# the function replaces the '{{response_file_name}}' with the new temp file
460# named 'gn_response_file', and returns the new temp file to indicate
461# we need to complete step 2)
462def handle_gn_build_arg_response_file_name(command_arg_list):
463    new_temp_file_name = None
464    updated_args = command_arg_list[:]
465    for index, arg in enumerate(updated_args):
466        if arg == '{{response_file_name}}':
467            new_temp_file_name = '$(genDir)/gn_response_file'
468            updated_args[index] = new_temp_file_name
469    return new_temp_file_name, updated_args
470
471
472def action_target_to_blueprint(abi, target, build_info):
473    target_info = build_info[abi][target]
474    blueprint_type = blueprint_gen_types[target_info['type']]
475
476    bp = {'name': gn_target_to_blueprint_target(target, target_info)}
477
478    # Blueprints use only one 'srcs', merge all gn inputs into one list.
479    gn_inputs = []
480    if 'inputs' in target_info:
481        for input in target_info['inputs']:
482            if input not in inputs_blocklist:
483                gn_inputs.append(input)
484    if 'sources' in target_info:
485        gn_inputs += target_info['sources']
486    # Filter out the 'script' entry since Android.bp doesn't like the duplicate entries
487    if 'script' in target_info:
488        gn_inputs = [
489            input for input in gn_inputs
490            if not is_input_in_tool_files(target_info['script'], input)
491        ]
492
493    bp_srcs = gn_paths_to_blueprint_paths(gn_inputs)
494
495    bp['srcs'] = bp_srcs
496
497    # genrules generate the output right into the 'root' directory. Strip any path before the
498    # file name.
499    bp_outputs = []
500    for gn_output in target_info['outputs']:
501        output = os.path.basename(gn_output)
502        if output in outputs_remap.keys():
503            output = outputs_remap[output]
504        bp_outputs.append(output)
505
506    bp['out'] = bp_outputs
507
508    bp['tool_files'] = [gn_path_to_blueprint_path(target_info['script'])]
509
510    new_temporary_gn_response_file, updated_args = handle_gn_build_arg_response_file_name(
511        target_info['args'])
512
513    if new_temporary_gn_response_file:
514        # add the command 'echo $(in) > $(genDir)/gn_response_file' to
515        # write $response_file_contents into the new_temporary_gn_response_file.
516        cmd = ['echo $(in) >', new_temporary_gn_response_file, '&&', '$(location)'
517              ] + gn_action_args_to_blueprint_args(bp_srcs, bp_outputs, updated_args)
518    else:
519        cmd = ['$(location)'] + gn_action_args_to_blueprint_args(bp_srcs, bp_outputs,
520                                                                 target_info['args'])
521
522    bp['cmd'] = ' '.join(cmd)
523
524    bp['sdk_version'] = MIN_SDK_VERSION
525
526    return blueprint_type, bp
527
528
529def gn_target_to_blueprint(target, build_info):
530    for abi in ABI_TARGETS:
531        gn_type = build_info[abi][target]['type']
532        if gn_type in blueprint_library_target_types:
533            return library_target_to_blueprint(target, build_info)
534        elif gn_type in blueprint_gen_types:
535            return action_target_to_blueprint(abi, target, build_info)
536        else:
537            # Target is not used by this ABI
538            continue
539
540
541@functools.lru_cache(maxsize=None)
542def get_gn_target_dependencies(abi, target, build_info):
543    result = collections.OrderedDict()
544    result[target] = 1
545
546    for dep in build_info[abi][target]['deps']:
547        if dep in target_blockist:
548            # Blocklisted dep
549            continue
550        if dep not in build_info[abi]:
551            # No info for this dep, skip it
552            continue
553
554        # Recurse
555        result.update(get_gn_target_dependencies(abi, dep, build_info))
556
557    return result
558
559
560def get_angle_in_vendor_flag_config():
561    blueprint_results = []
562
563    blueprint_results.append(('soong_config_module_type', {
564        'name': 'angle_config_cc_defaults',
565        'module_type': 'cc_defaults',
566        'config_namespace': 'angle',
567        'bool_variables': ['angle_in_vendor',],
568        'properties': [
569            'target.android.relative_install_path',
570            'vendor',
571        ],
572    }))
573
574    blueprint_results.append(('soong_config_bool_variable', {
575        'name': 'angle_in_vendor',
576    }))
577
578    blueprint_results.append((
579        'angle_config_cc_defaults',
580        {
581            'name': 'angle_vendor_cc_defaults',
582            'vendor': False,
583            'target': {
584                'android': {
585                    # Android EGL loader can not load from /system/egl/${LIB}
586                    # path and hence don't set the relative path so that ANGLE
587                    # libraries get built into /system/${LIB}
588                    'relative_install_path': '',
589                },
590            },
591            'soong_config_variables': {
592                'angle_in_vendor': {
593                    'vendor': True,
594                    'target': {
595                        'android': {
596                            'relative_install_path': 'egl',
597                        },
598                    },
599                },
600            },
601        }))
602
603    return blueprint_results
604
605
606def main():
607    parser = argparse.ArgumentParser(
608        description='Generate Android blueprints from gn descriptions.')
609
610    for abi in ABI_TARGETS:
611        parser.add_argument(
612            '--gn_json_' + gn_abi(abi),
613            help=gn_abi(abi) +
614            ' gn desc file in json format. Generated with \'gn desc <out_dir> --format=json "*"\'.',
615            required=True)
616    parser.add_argument('--output', help='output file (e.g. Android.bp)')
617    args = vars(parser.parse_args())
618
619    infos = {}
620    for abi in ABI_TARGETS:
621        with open(args['gn_json_' + gn_abi(abi)], 'r') as f:
622            infos[abi] = json.load(f)
623
624    build_info = BuildInfo(infos)
625    targets_to_write = collections.OrderedDict()
626    for abi in ABI_TARGETS:
627        for root_target in ROOT_TARGETS:
628            targets_to_write.update(get_gn_target_dependencies(abi, root_target, build_info))
629
630    blueprint_targets = []
631
632    blueprint_targets.extend(get_angle_in_vendor_flag_config())
633
634    blueprint_targets.append((
635        'cc_defaults',
636        {
637            'name':
638                'angle_common_library_cflags',
639            'cpp_std':
640                'gnu++17',  # TODO(b/330910097): std::popcount missing from external/libcxx
641            'cflags': [
642                # Chrome and Android use different versions of Clang which support differnt warning options.
643                # Ignore errors about unrecognized warning flags.
644                '-Wno-unknown-warning-option',
645                '-O2',
646                # Override AOSP build flags to match ANGLE's CQ testing and reduce binary size
647                '-fno-unwind-tables',
648                # Disable stack protector to reduce cpu overhead.
649                '-fno-stack-protector',
650            ],
651        }))
652
653    generated_targets = []
654    for target in reversed(targets_to_write.keys()):
655        generated_targets.append(gn_target_to_blueprint(target, build_info))
656
657    # Move cflags that are repeated in each target to cc_defaults
658    all_cflags = [set(bp['cflags']) for _, bp in generated_targets if 'cflags' in bp]
659    all_target_cflags = set.intersection(*all_cflags)
660
661    for _, bp in generated_targets:
662        if 'cflags' in bp:
663            bp['cflags'] = list(set(bp['cflags']) - all_target_cflags)
664            bp['defaults'].append('angle_common_auto_cflags')
665
666    blueprint_targets.append(('cc_defaults', {
667        'name': 'angle_common_auto_cflags',
668        'cflags': list(all_target_cflags),
669    }))
670    blueprint_targets.extend(generated_targets)
671
672    # Add license build rules
673    blueprint_targets.append(('package', {
674        'default_applicable_licenses': ['external_angle_license'],
675    }))
676    blueprint_targets.append(('license', {
677        'name':
678            'external_angle_license',
679        'visibility': [':__subpackages__'],
680        'license_kinds': [
681            'SPDX-license-identifier-Apache-2.0',
682            'SPDX-license-identifier-BSD',
683            'SPDX-license-identifier-GPL',
684            'SPDX-license-identifier-GPL-2.0',
685            'SPDX-license-identifier-GPL-3.0',
686            'SPDX-license-identifier-LGPL',
687            'SPDX-license-identifier-MIT',
688            'SPDX-license-identifier-Zlib',
689            'legacy_unencumbered',
690        ],
691        'license_text': [
692            'LICENSE',
693            'src/common/third_party/xxhash/LICENSE',
694            'src/libANGLE/renderer/vulkan/shaders/src/third_party/ffx_spd/LICENSE',
695            'src/tests/test_utils/third_party/LICENSE',
696            'src/third_party/libXNVCtrl/LICENSE',
697            'src/third_party/volk/LICENSE.md',
698            'third_party/abseil-cpp/LICENSE',
699            'third_party/android_system_sdk/LICENSE',
700            'third_party/bazel/LICENSE',
701            'third_party/colorama/LICENSE',
702            'third_party/proguard/LICENSE',
703            'third_party/r8/LICENSE',
704            'third_party/turbine/LICENSE',
705            'third_party/glslang/LICENSE',
706            'third_party/glslang/src/LICENSE.txt',
707            'third_party/spirv-headers/LICENSE',
708            'third_party/spirv-headers/src/LICENSE',
709            'third_party/spirv-tools/LICENSE',
710            'third_party/spirv-tools/src/LICENSE',
711            'third_party/spirv-tools/src/utils/vscode/src/lsp/LICENSE',
712            'third_party/vulkan-headers/LICENSE.txt',
713            'third_party/vulkan-headers/src/LICENSE.md',
714            'third_party/vulkan_memory_allocator/LICENSE.txt',
715            'tools/flex-bison/third_party/m4sugar/LICENSE',
716            'tools/flex-bison/third_party/skeletons/LICENSE',
717            'util/windows/third_party/StackWalker/LICENSE',
718        ],
719    }))
720
721    # Add APKs with all of the root libraries and permissions xml
722    blueprint_targets.append((
723        'filegroup',
724        {
725            'name':
726                'ANGLE_srcs',
727            # We only need EmptyMainActivity.java since we just need to be able to reply to the intent
728            # android.app.action.ANGLE_FOR_ANDROID to indicate ANGLE is present on the device.
729            # However, the internal branch currently uses these files with patches in that branch.
730            'srcs': [
731                'src/android_system_settings/src/com/android/angle/MainActivity.java',
732                'src/android_system_settings/src/com/android/angle/common/AngleRuleHelper.java',
733                'src/android_system_settings/src/com/android/angle/common/GlobalSettings.java',
734                'src/android_system_settings/src/com/android/angle/common/MainFragment.java',
735                'src/android_system_settings/src/com/android/angle/common/Receiver.java',
736                'src/android_system_settings/src/com/android/angle/common/SearchProvider.java',
737            ],
738        }))
739
740    blueprint_targets.append(('prebuilt_etc', {
741        'name': 'android.software.angle.xml',
742        'src': 'android/android.software.angle.xml',
743        'product_specific': True,
744        'sub_dir': 'permissions',
745    }))
746
747    blueprint_targets.append((
748        'java_defaults',
749        {
750            'name': 'ANGLE_java_defaults',
751            'sdk_version': 'system_current',
752            'target_sdk_version': TARGET_SDK_VERSION,
753            'min_sdk_version': MIN_SDK_VERSION,
754            'compile_multilib': 'both',
755            'use_embedded_native_libs': True,
756            'jni_libs': [
757                # hack: assume ABI_ARM
758                gn_target_to_blueprint_target(target, build_info[ABI_ARM][target])
759                for target in ROOT_TARGETS
760            ],
761            'aaptflags': [
762                '-0 .json',  # Don't compress *.json files
763                "--extra-packages com.android.angle.common",
764            ],
765            'srcs': [':ANGLE_srcs'],
766            'privileged': True,
767            'product_specific': True,
768            'owner': 'google',
769            'required': ['android.software.angle.xml'],
770        }))
771
772    blueprint_targets.append(('android_library', {
773        'name': 'ANGLE_library',
774        'sdk_version': 'system_current',
775        'target_sdk_version': TARGET_SDK_VERSION,
776        'min_sdk_version': MIN_SDK_VERSION,
777        'resource_dirs': ['src/android_system_settings/res',],
778        'asset_dirs': ['src/android_system_settings/assets',],
779        'aaptflags': ['-0 .json',],
780        'manifest': 'src/android_system_settings/src/com/android/angle/AndroidManifest.xml',
781        'static_libs': ['androidx.preference_preference',],
782    }))
783
784    blueprint_targets.append(('android_app', {
785        'name': 'ANGLE',
786        'defaults': ['ANGLE_java_defaults'],
787        'manifest': 'src/android_system_settings/src/com/android/angle/AndroidManifest.xml',
788        'static_libs': ['ANGLE_library'],
789        'optimize': {
790            'enabled': True,
791            'shrink': True,
792            'proguard_compatibility': False,
793        },
794        'asset_dirs': ['src/android_system_settings/assets',],
795    }))
796
797    blueprint_targets.append((
798        'java_defaults',
799        {
800            'name': 'ANGLE_java_settings_defaults',
801            'sdk_version': 'system_current',
802            'target_sdk_version': TARGET_SDK_VERSION,
803            'min_sdk_version': MIN_SDK_VERSION,
804            'compile_multilib': 'both',
805            'use_embedded_native_libs': True,
806            'aaptflags': [
807                '-0 .json',  # Don't compress *.json files
808                "--extra-packages com.android.angle.common",
809            ],
810            'srcs': [':ANGLE_srcs'],
811            'privileged': True,
812            'product_specific': True,
813            'owner': 'google',
814            'required': ['android.software.angle.xml'],
815        }))
816
817    blueprint_targets.append(('android_app', {
818        'name': 'ANGLE_settings',
819        'defaults': ['ANGLE_java_settings_defaults'],
820        'manifest': 'src/android_system_settings/src/com/android/angle/AndroidManifest.xml',
821        'static_libs': ['ANGLE_library'],
822        'optimize': {
823            'enabled': True,
824            'shrink': True,
825            'proguard_compatibility': False,
826        },
827        'asset_dirs': ['src/android_system_settings/assets',],
828    }))
829
830    output = [
831        """// GENERATED FILE - DO NOT EDIT.
832// Generated by %s
833//
834// Copyright 2020 The ANGLE Project Authors. All rights reserved.
835// Use of this source code is governed by a BSD-style license that can be
836// found in the LICENSE file.
837//""" % sys.argv[0]
838    ]
839    for (blueprint_type, blueprint_data) in blueprint_targets:
840        write_blueprint(output, blueprint_type, blueprint_data)
841
842    with open(args['output'], 'w') as f:
843        f.write('\n'.join(output) + '\n')
844
845
846if __name__ == '__main__':
847    sys.exit(main())
848