Files
platform-external-webrtc/android_tools/generate_bp.py
Colin Cross a626e135fb Fix dependency on python hash seed
Sort the list of targets before writing them to the output, which fixes
the only place where output ordering depended on the python hash seed.
Also remove the fixed python hash seed from the script.

Test: android_tools/generate_android_bp.sh && git diff
Test: mma
Change-Id: Icfadfaaebf438d00bfef13c231fc09afda454916
2023-02-24 16:28:21 -08:00

754 lines
27 KiB
Python
Executable File

#!/usr/bin/env python
import json
import os
import sys
PRINT_ORIGINAL_FULL = False
# This flags are augmented with flags added to the json files but not present in .gn or .gni files
IGNORED_FLAGS = [
'-Wall',
'-Werror',
'-L',
'-isystem',
'-Xclang',
'-B',
'--sysroot',
'-fcrash-diagnostics-dir',
'.',
'-fdebug-compilation-dir',
'-instcombine-lower-dbg-declare=0',
'-Wno-non-c-typedef-for-linkage',
'-Werror',
'-fcomplete-member-pointers',
'-fno-stack-protector',
'--target=i686-linux-android16',
'--target=aarch64-linux-android21'
'--target=i686-linux-android16',
'--target=x86_64-linux-android21',
'--target=arm-linux-androideabi16',
'--target=aarch64-linux-gnu',
'--target=arm-linux-gnueabihf',
'-ggnu-pubnames',
'-m64',
'-m32',
'-march=x86-64',
'-march=armv8-a',
'-march=armv7-a',
'-mllvm',
'-mfloat-abi=hard',
'-target-feature',
'+crypto',
'+crc',
'-fno-unique-section-names',
'-fno-short-enums',
'-fno-delete-null-pointer-checks',
'-ffile-compilation-dir=.',
'-Wno-unneeded-internal-declaration',
'-Wno-unreachable-code-aggressive',
'-Wno-unreachable-code-break',
'-fuse-ctor-homing',
'-fno-rtti',
'-gsplit-dwarf', # TODO(b/266468464): breaks riscv
'-gdwarf-aranges', # TODO(b/269343483): breaks riscv
]
DEFAULT_CFLAGS = [
'-Wno-everything',
'-Wno-all',
'-Wno-error',
'-Wno-unreachable-code-aggressive',
'-Wno-unreachable-code-break',
'-Wno-unused-parameter',
'-Wno-missing-field-initializers',
'-Wno-implicit-const-int-float-conversion',
'-DUSE_UDEV',
'-DUSE_AURA=1',
'-DUSE_GLIB=1',
'-DUSE_NSS_CERTS=1',
'-DUSE_X11=1',
'-D_FILE_OFFSET_BITS=64',
'-D_LARGEFILE_SOURCE',
'-D_LARGEFILE64_SOURCE',
'-D_GNU_SOURCE',
'-DWEBRTC_ENABLE_PROTOBUF=0',
'-DWEBRTC_ANDROID_PLATFORM_BUILD=1',
'-DWEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE',
'-DRTC_ENABLE_VP9',
'-DWEBRTC_HAVE_SCTP',
'-DWEBRTC_LIBRARY_IMPL',
'-DWEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS=1',
'-DWEBRTC_POSIX',
'-DWEBRTC_LINUX',
'-DWEBRTC_STRICT_FIELD_TRIALS=0',
'-DWEBRTC_ENABLE_AVX2',
'-DABSL_ALLOCATOR_NOTHROW=1',
'-DWEBRTC_APM_DEBUG_DUMP=0',
'-msse3',
]
DEFAULT_CFLAGS_BY_ARCH = {
'x86': ['-msse2', '-mavx2', '-mfma', '-DHAVE_ARM64_CRC32C=0'],
'x64': ['-msse2', '-mavx2', '-mfma', '-DHAVE_ARM64_CRC32C=0'],
'arm': ['-DWEBRTC_HAS_NEON', '-DWEBRTC_ARCH_ARM_V7', '-DWEBRTC_ARCH_ARM', '-mfpu=neon', '-mthumb', '-DHAVE_ARM64_CRC32C=0'],
'arm64': ['-DWEBRTC_HAS_NEON', '-DWEBRTC_ARCH_ARM64', '-DHAVE_ARM64_CRC32C=0'],
'riscv64': ['-DHAVE_ARM64_CRC32C=0'],
}
FLAGS = ['cflags', 'cflags_c', 'cflags_cc', 'asmflags']
ARCH_NAME_MAP = {n: n for n in DEFAULT_CFLAGS_BY_ARCH.keys()}
ARCH_NAME_MAP['x64'] = 'x86_64'
ARCHS = sorted(ARCH_NAME_MAP.keys())
def FormatList(l):
return json.dumps(sorted(list(l)))
def IsInclude(name):
return name.endswith('.h') or name.endswith('.inc')
def FilterIncludes(l):
return filter(lambda x: not IsInclude(x), l)
def PrintOrigin(target):
print('/* From target:')
if PRINT_ORIGINAL_FULL:
print(json.dumps(target, sort_keys = True, indent = 4))
else:
print(target['original_name'])
print('*/')
def MakeRelatives(l):
return map(lambda x: x.split('//').pop(), l)
def FormatName(name):
return 'webrtc_' + name.split('/').pop().replace(':', '__')
def FormatNames(target):
target['original_name'] = target['name']
target['name'] = FormatName(target['name'])
target['deps'] = sorted([FormatName(d) for d in target['deps']])
target['sources'] = list(map(lambda s: (':' + FormatName(s[1:])) if s.startswith(':') else s, target['sources']))
return target
def FilterFlags(flags, to_skip = set()):
skipped_opts = set(IGNORED_FLAGS).union(to_skip).union(DEFAULT_CFLAGS)
return sorted([x for x in flags if not any([x.startswith(y) for y in skipped_opts])])
def PrintHeader():
print('package {')
print(' default_applicable_licenses: ["external_webrtc_license"],')
print('}')
print('')
print('// Added automatically by a large-scale-change that took the approach of')
print('// \'apply every license found to every target\'. While this makes sure we respect')
print('// every license restriction, it may not be entirely correct.')
print('//')
print('// e.g. GPL in an MIT project might only apply to the contrib/ directory.')
print('//')
print('// Please consider splitting the single license below into multiple licenses,')
print('// taking care not to lose any license_kind information, and overriding the')
print('// default license using the \'licenses: [...]\' property on targets as needed.')
print('//')
print('// For unused files, consider creating a \'fileGroup\' with "//visibility:private"')
print('// to attach the license to, and including a comment whether the files may be')
print('// used in the current project.')
print('//')
print('// large-scale-change included anything that looked like it might be a license')
print('// text as a license_text. e.g. LICENSE, NOTICE, COPYING etc.')
print('//')
print('// Please consider removing redundant or irrelevant files from \'license_text:\'.')
print('// See: http://go/android-license-faq')
print('')
print('///////////////////////////////////////////////////////////////////////////////')
print('// Do not edit this file directly, it\'s automatically generated by a script. //')
print('// Modify android_tools/generate_android_bp.py and run that instead. //')
print('///////////////////////////////////////////////////////////////////////////////')
print('')
print('license {')
print(' name: "external_webrtc_license",')
print(' visibility: [":__subpackages__"],')
print(' license_kinds: [')
print(' "SPDX-license-identifier-Apache-2.0",')
print(' "SPDX-license-identifier-BSD",')
print(' "SPDX-license-identifier-MIT",')
print(' "SPDX-license-identifier-Zlib",')
print(' "legacy_notice",')
print(' "legacy_unencumbered",')
print(' ],')
print(' license_text: [')
print(' "LICENSE",')
print(' "PATENTS",')
print(' "license_template.txt",')
print(' ],')
print('}')
def GatherDefaultFlags(targets):
default = { f: [] for f in FLAGS}
arch = {a: {} for a in ARCHS}
first = True
for target in targets.values():
typ = target['type']
if typ != 'static_library':
continue
if first:
first = False
# Add all the flags to the default, we'll remove some later
for flag_type in default.keys():
default[flag_type] = []
for flag in target[flag_type]:
default[flag_type].append(flag)
for a in arch.keys():
arch[a][flag_type] = []
for flag in target.get('arch', {}).get(a, {}).get(flag_type, []):
arch[a][flag_type].append(flag)
else:
for flag_type in default.keys():
if flag_type not in target:
target[flag_type] = []
default[flag_type] = list(set(default[flag_type]) & set(target[flag_type]))
for a in arch.keys():
arch[a][flag_type] = list(set(arch[a][flag_type]) & set(target.get('arch', {}).get(a, {}).get(flag_type, [])))
default['arch'] = arch
return default
def GenerateDefault(targets):
in_default = GatherDefaultFlags(targets)
print('cc_defaults {')
print(' name: "webrtc_defaults",')
print(' local_include_dirs: [')
print(' ".",')
print(' "webrtc",')
print(' "third_party/crc32c/src/include",')
print(' ],')
if PRINT_ORIGINAL_FULL:
for typ in sorted(in_default.keys()):
print(' // {0}: ['.format(typ.replace('asmflags', 'asflags')
.replace('cflags_cc', 'cppflags')
.replace('cflags_c', 'conlyflags')))
for flag in FilterFlags(in_default[typ]):
print(' // "{0}",'.format(flag.replace('"', '\\"')))
print(' // ],')
print(' cflags: {0},'.format(FormatList(DEFAULT_CFLAGS)))
print(' header_libs: [')
print(' "libwebrtc_absl_headers",')
print(' ],')
print(' static_libs: [')
print(' "libaom",')
print(' "libevent",')
print(' "libopus",')
print(' "libsrtp2",')
print(' "libvpx",')
print(' "libyuv",')
print(' "libpffft",')
print(' "rnnoise_rnn_vad",')
print(' ],')
print(' shared_libs: [')
print(' "libcrypto",')
print(' "libprotobuf-cpp-full",')
print(' "libprotobuf-cpp-lite",')
print(' "libssl",')
print(' ],')
print(' host_supported: true,')
print(' // vendor needed for libpreprocessing effects.')
print(' vendor: true,')
print(' target: {')
print(' darwin: {')
print(' enabled: false,')
print(' },')
print(' },')
print(' arch: {')
for a in ARCHS:
print(' {0}: {{'.format(ARCH_NAME_MAP[a]))
print(' cflags: {0}'.format(FormatList(DEFAULT_CFLAGS_BY_ARCH[a])))
print(' },')
print(' },')
print(' visibility: [')
print(' "//frameworks/av/media/libeffects/preprocessing:__subpackages__",')
print(' "//device/google/cuttlefish/host/frontend/webrtc:__subpackages__",')
print(' ],')
print('}')
in_default['cflags'].extend(DEFAULT_CFLAGS)
for a in ARCHS:
in_default['arch'][a]['cflags'].extend(DEFAULT_CFLAGS_BY_ARCH[a])
# The flags in the default entry can be safely removed from the targets
for target in targets.values():
flag_types = in_default.keys() - {'arch'}
for flag_type in flag_types:
target[flag_type] = FilterFlags(target.get(flag_type, []), in_default[flag_type])
if len(target[flag_type]) == 0:
target.pop(flag_type)
if 'arch' not in target:
continue
for arch_name in in_default['arch'].keys():
if arch_name not in target['arch']:
continue
arch = target['arch'][arch_name]
if flag_type not in arch:
continue
arch[flag_type] = FilterFlags(arch[flag_type], in_default['arch'][arch_name][flag_type])
if len(arch[flag_type]) == 0:
arch.pop(flag_type)
if len(arch.keys()) == 0:
target['arch'].pop(arch_name)
if len(target['arch'].keys()) == 0:
target.pop('arch')
return in_default
def TransitiveDependencies(name, dep_type, targets):
target = targets[name]
field = 'transitive_' + dep_type
if field in target.keys():
return target[field]
target[field] = {'global': set()}
for a in ARCHS:
target[field][a] = set()
if target['type'] == dep_type:
target[field]['global'].add(name)
for d in target.get('deps', []):
if targets[d]['type'] == dep_type:
target[field]['global'].add(d)
tDeps = TransitiveDependencies(d, dep_type, targets)
target[field]['global'] |= tDeps['global']
for a in ARCHS:
target[field][a] |= tDeps[a]
if 'arch' in target:
for a, x in target['arch'].items():
for d in x.get('deps', []):
tDeps = TransitiveDependencies(d, dep_type, targets)
target[field][a] |= tDeps['global'] | tDeps[a]
target[field][a] -= target[field]['global']
return target[field]
def GenerateGroup(target):
# PrintOrigin(target)
pass
def GenerateSourceSet(target):
sources = target.get('sources', [])
# arch is not defined for filegroups so put all the sources in the top level,
# the static libraries that depend on the filegroup will add it in the
# appropriate arch.
for arch in target.get('arch', {}).values():
sources += arch.get('sources', [])
if len(sources) == 0:
return ''
PrintOrigin(target)
name = target['name']
print('filegroup {')
print(' name: "{0}",'.format(name))
print(' srcs: {0},'.format(FormatList(sources)))
print('}')
return name
def GenerateStaticLib(target, targets):
PrintOrigin(target)
name = target['name']
print('cc_library_static {')
print(' name: "{0}",'.format(name))
print(' defaults: ["webrtc_defaults"],')
sources = target.get('sources', [])
print(' srcs: {0},'.format(FormatList(sources)))
print(' host_supported: true,')
if 'asmflags' in target.keys():
asmflags = target['asmflags']
if len(asmflags) > 0:
print(' asflags: {0},'.format(FormatList(asmflags)))
if 'cflags' in target.keys():
cflags = target['cflags']
print(' cflags: {0},'.format(FormatList(cflags)))
if 'cflags_c' in target.keys():
cflags_c = target['cflags_c']
if len(cflags_c) > 0:
print(' conlyflags: {0},'.format(FormatList(cflags_c)))
if 'cflags_cc' in target.keys():
cflags_cc = target['cflags_cc']
if len(cflags_cc) > 0:
print(' cppflags: {0},'.format(FormatList(cflags_cc)))
static_libs = sorted([d for d in target.get('deps', []) if targets[d]['type'] == 'static_library'])
if len(static_libs) > 0:
print(' static_libs: {0},'.format(FormatList(static_libs)))
if 'arch' in target:
print(' arch: {')
for arch_name in ARCHS:
if arch_name not in target['arch'].keys():
continue
arch = target['arch'][arch_name]
print(' ' + ARCH_NAME_MAP[arch_name] + ': {')
if 'cflags' in arch.keys():
cflags = arch['cflags']
print(' cflags: {0},'.format(FormatList(cflags)))
if 'cflags_c' in arch.keys():
cflags_c = arch['cflags_c']
if len(cflags_c) > 0:
print(' conlyflags: {0},'.format(FormatList(cflags_c)))
if 'cflags_cc' in arch.keys():
cflags_cc = arch['cflags_cc']
if len(cflags_cc) > 0:
print(' cppflags: {0},'.format(FormatList(cflags_cc)))
if 'deps' in arch:
static_libs = [d for d in arch['deps'] if targets[d]['type'] == 'static_library']
print(' static_libs: {0},'.format(FormatList(static_libs)))
if 'sources' in arch:
sources = arch['sources']
print(' srcs: {0},'.format(FormatList(sources)))
if 'enabled' in arch:
print(' enabled: {0},'.format(arch['enabled']))
print(' },')
print(' },')
print('}')
return name
def DFS(seed, targets):
visited = set()
stack = [seed]
while len(stack) > 0:
nxt = stack.pop()
if nxt in visited:
continue
visited.add(nxt)
stack += targets[nxt]['deps']
stack += [s[1:] for s in targets[nxt]['sources'] if s.startswith(':')]
if 'arch' not in targets[nxt]:
continue
for arch in targets[nxt]['arch']:
if 'deps' in arch:
stack += arch['deps']
if 'sources' in arch:
stack += [s[1:] for s in arch['sources'] if s.startswith(':')]
return visited
def Preprocess(project):
targets = {}
for name, target in project['targets'].items():
target['name'] = name
targets[name] = target
if target['type'] == 'shared_library':
# Don't bother creating shared libraries
target['type'] = 'static_library'
if 'defines' in target:
target['cflags'] = target.get('cflags', []) + ['-D{0}'.format(d) for d in target['defines']]
target.pop('defines')
if 'sources' not in target:
continue
sources = list(MakeRelatives(FilterIncludes(target['sources'])))
if len(sources) > 0:
target['sources'] = sources
else:
target.pop('sources')
# These dependencies are provided by aosp
ignored_targets = {
'//third_party/libaom:libaom',
'//third_party/libevent:libevent',
'//third_party/opus:opus',
'//third_party/libsrtp:libsrtp',
'//third_party/libvpx:libvpx',
'//third_party/libyuv:libyuv',
'//third_party/pffft:pffft',
'//third_party/rnnoise:rnn_vad',
'//third_party/boringssl:boringssl',
'//third_party/android_ndk:cpu_features',
'//buildtools/third_party/libunwind:libunwind',
'//buildtools/third_party/libc++:libc++',
}
for name, target in targets.items():
# Skip all "action" targets
if target['type'] in {'action', 'action_foreach'}:
ignored_targets.add(name)
targets = {name: target for name, target in targets.items() if name not in ignored_targets}
for target in targets.values():
# Don't depend on ignored targets
target['deps'] = [d for d in target['deps'] if d not in ignored_targets]
# filegroups can't have dependencies, so put their dependencies in the static libraries that
# depend on them.
for target in targets.values():
if target['type'] == 'static_library':
source_sets = TransitiveDependencies(target['name'], 'source_set', targets)
source_sets_deps = {}
for a in ['global'] + ARCHS:
deps = set()
if a == 'global':
for ss in [targets[n].get('deps', []) for n in source_sets[a]]:
deps |= set(ss)
else:
for ss in [targets[n].get('arch', {}).get(a, {}).get('deps') for n in source_sets[a]]:
deps |= set(ss)
source_sets_deps[a] = deps
target['deps'] = sorted(set(target['deps']) | source_sets['global'] | source_sets_deps['global'])
for a in ARCHS:
deps = source_sets[a] | source_sets_deps[a]
if len(deps) == 0:
continue
if 'arch' not in target:
target['arch'] = {}
if a not in target['arch']:
target['arch'][a] = {}
if 'deps' not in target['arch'][a]:
target['arch'][a]['deps'] = []
deps |= set(target['arch'][a]['deps'])
target['arch'][a]['deps'] = sorted(deps)
# Ignore empty source sets
empty_sets = set()
for name, target in targets.items():
if target['type'] == 'source_set' and 'sources' not in target:
empty_sets.add(name)
for s in empty_sets:
targets.pop(s)
for target in targets.values():
target['deps'] = [d for d in target['deps'] if d not in empty_sets]
# Move source_set dependencies to the sources fields of static libs
for target in targets.values():
if 'sources' not in target:
target['sources'] = []
if target['type'] != 'static_library':
continue
source_sets = {d for d in target['deps'] if targets[d]['type'] == 'source_set'}
target['deps'] = sorted(list(set(target['deps']) - source_sets))
target['sources'] += [':' + ss for ss in source_sets]
target['sources'] = sorted(target['sources'])
if 'arch' in target:
for arch in target['arch'].values():
if 'deps' in arch:
source_sets = {d for d in arch['deps'] if targets[d]['type'] == 'source_set'}
if len(source_sets) == 0:
continue;
arch['deps'] = sorted(list(set(arch['deps']) - source_sets))
arch['sources'] = sorted(arch.get('sources', []) + [':' + ss for ss in source_sets])
# Select libwebrtc, libaudio_processing and its dependencies
selected = set()
selected |= DFS('//:webrtc', targets)
selected |= DFS('//modules/audio_processing:audio_processing', targets)
return {FormatName(n): FormatNames(targets[n]) for n in selected}
def NonNoneFrom(l):
for a in l:
if a is not None:
return a
return None
def MergeListField(target, f, target_by_arch):
set_by_arch = {}
for a, t in target_by_arch.items():
if len(t) == 0:
# We only care about enabled archs
continue
set_by_arch[a] = set(t.get(f, []))
union = set()
for _, s in set_by_arch.items():
union |= s
common = union
for a, s in set_by_arch.items():
common &= s
not_common = {a: s - common for a,s in set_by_arch.items()}
if len(common) > 0:
target[f] = list(common)
for a, s in not_common.items():
if len(s) > 0:
target['arch'][a][f] = sorted(list(s))
def Merge(target_by_arch):
# The new target shouldn't have the transitive dependencies memoization fields
# or have the union of those fields from all 4 input targets.
target = {}
for f in ['original_name', 'name', 'type']:
target[f] = NonNoneFrom([t.get(f) for _,t in target_by_arch.items()])
target['arch'] = {}
for a, t in target_by_arch.items():
target['arch'][a] = {}
if len(t) == 0:
target['arch'][a]['enabled'] = 'false'
list_fields = ['sources',
'deps',
'cflags',
'cflags_c',
'cflags_cc',
'asmflags']
for lf in list_fields:
MergeListField(target, lf, target_by_arch)
# Static libraries should be depended on at the root level and disabled for
# the corresponding architectures.
for arch in target['arch'].values():
if 'deps' not in arch:
continue
deps = arch['deps']
if 'deps' not in target:
target['deps'] = []
target['deps'] += deps
arch.pop('deps')
if 'deps' in target:
target['deps'] = sorted(target['deps'])
# Remove empty sets
for a in ARCHS:
if len(target['arch'][a]) == 0:
target['arch'].pop(a)
if len(target['arch']) == 0:
target.pop('arch')
return target
def DisabledArchs4Target(target):
ret = set()
for a in ARCHS:
if a not in target.get('arch', {}):
continue
if target['arch'][a].get('enabled', 'true') == 'false':
ret.add(a)
return ret
def HandleDisabledArchs(targets):
for n, t in targets.items():
if 'arch' not in t:
continue
disabledArchs = DisabledArchs4Target(t)
if len(disabledArchs) == 0:
continue
# Fix targets that depend on this one
for t in targets.values():
if DisabledArchs4Target(t) == disabledArchs:
# With the same disabled archs there is no need to move dependencies
continue
if 'deps' in t and n in t['deps']:
# Remove the dependency from the high level list
t['deps'] = sorted(set(t['deps']) - {n})
if 'arch' not in t:
t['arch'] = {}
for a in ARCHS:
if a in disabledArchs:
continue
if a not in t['arch']:
t['arch'][a] = {}
if 'deps' not in t['arch'][a]:
t['arch'][a]['deps'] = []
t['arch'][a]['deps'] += [n]
def MergeAll(targets_by_arch):
names = set()
for t in targets_by_arch.values():
names |= t.keys()
targets = {}
for name in names:
targets[name] = Merge({a: t.get(name, {}) for a,t in targets_by_arch.items()})
HandleDisabledArchs(targets)
return targets
def GatherAllFlags(obj):
if type(obj) != type({}):
# not a dictionary
return set()
ret = set()
for f in FLAGS:
ret |= set(obj.get(f, []))
for v in obj.values():
ret |= GatherAllFlags(v)
return ret
def FilterFlagsInUse(flags, directory):
unused = []
for f in flags:
nf = f
if nf.startswith("-D"):
nf = nf[2:]
i = nf.find('=')
if i > 0:
nf = nf[:i]
c = os.system(f"find {directory} -name '*.gn*' | xargs grep -q -s -e '{nf}'")
if c != 0:
# couldn't find the flag in *.gn or *.gni
unused.append(f)
return unused
if len(sys.argv) != 2:
print('wrong number of arguments', file = sys.stderr)
exit(1)
dir = sys.argv[1]
targets_by_arch = {}
flags = set()
for arch in ARCHS:
path = "{0}/project_{1}.json".format(dir, arch)
json_file = open(path, 'r')
targets_by_arch[arch] = Preprocess(json.load(json_file))
flags |= GatherAllFlags(targets_by_arch[arch])
unusedFlags = FilterFlagsInUse(flags, f"{dir}/..")
IGNORED_FLAGS = sorted(set(IGNORED_FLAGS) | set(unusedFlags))
targets = MergeAll(targets_by_arch)
PrintHeader()
GenerateDefault(targets)
print('\n\n')
for name, target in sorted(targets.items()):
typ = target['type']
if typ == 'static_library':
GenerateStaticLib(target, targets)
elif typ == 'source_set':
GenerateSourceSet(target)
elif typ == 'group':
GenerateGroup(target)
else:
print('Unknown type: {0} ({1})'.format(typ, target['name']), file = sys.stderr)
exit(1)
print('\n\n')
webrtc_libs = TransitiveDependencies(FormatName('//:webrtc'), 'static_library', targets)
print('cc_library_static {')
print(' name: "libwebrtc",')
print(' defaults: ["webrtc_defaults"],')
print(' export_include_dirs: ["."],')
print(' whole_static_libs: {0},'.format(FormatList(sorted(webrtc_libs['global']) + ['libpffft', 'rnnoise_rnn_vad'])))
print(' arch: {')
for a in ARCHS:
if len(webrtc_libs[a]) > 0:
print(' {0}: {{'.format(ARCH_NAME_MAP[a]))
print(' whole_static_libs: {0},'.format(FormatList(sorted(webrtc_libs[a]))))
print(' },')
print(' },')
print('}')
print('\n\n')
audio_proc_libs = TransitiveDependencies(FormatName('//modules/audio_processing:audio_processing'), 'static_library', targets)
print('cc_library_static {')
print(' name: "webrtc_audio_processing",')
print(' defaults: ["webrtc_defaults"],')
print(' export_include_dirs: [')
print(' ".",')
print(' "modules/include",')
print(' "modules/audio_processing/include",')
print(' ],')
print(' whole_static_libs: {0},'.format(FormatList(sorted(audio_proc_libs['global']) + ['libpffft', 'rnnoise_rnn_vad'])))
print(' arch: {')
for a in ARCHS:
if len(audio_proc_libs[a]) > 0:
print(' {0}: {{'.format(ARCH_NAME_MAP[a]))
print(' whole_static_libs: {0},'.format(FormatList(sorted(audio_proc_libs[a]))))
print(' },')
print(' },')
print('}')