1#!/usr/bin/env python3 2 3# This replicates the logic in Makefile to produce lists of generic 4# and architecture specific sources, then writes them into sources.bp 5# as cc_defaults modules for use by the Android.bp file. 6 7import copy 8import glob 9import os.path 10 11BP_TO_MUSL_ARCHES = { 12 'arm': 'arm', 13 'arm64': 'aarch64', 14 'x86': 'i386', 15 'x86_64': 'x86_64', 16} 17 18SRC_DIRS = ( 19 'src/*', 20 'src/malloc/mallocng', 21) 22COMPAT32_SRC_DIRS = ( 23 'compat/time32', 24) 25OPT_DIRS = ( 26 'src/internal', 27 'src/malloc', 28 'src/string', 29) 30NOSSP_SRCS = ( 31 'src/env/__libc_start_main.c', 32 'src/env/__init_tls.c', 33 'src/env/__stack_chk_fail.c', 34 'src/thread/__set_thread_area.c', 35 'src/string/memset.c', 36 'src/string/memcpy.c', 37) 38LDSO_SRC_DIRS = ( 39 'ldso', 40) 41CRT_SRCS = ( 42 'crt/crt1.c', 43 'crt/crti.c', 44 'crt/crtn.c', 45 'crt/rcrt1.c', 46 'crt/Scrt1.c', 47) 48 49def overridden_base_src(arch, src): 50 src = src.replace('/'+arch+'/','/') 51 if src.endswith('.s') or src.endswith('.S'): 52 src = src[:-2]+'.c' 53 return src 54 55def overridden_base_srcs(arch, srcs): 56 return [overridden_base_src(arch, src) for src in srcs] 57 58def glob_dirs(*args): 59 """glob_dirs takes a list of parts of glob patterns, some of which may be 60 lists or tuples, expands the lists and tuples into every combination 61 of patterns, and returns the glob expansion of the patterns.""" 62 ret = [] 63 for i, arg in enumerate(args): 64 if type(arg) is list or type(arg) is tuple: 65 for entry in arg: 66 new_args = list(args) 67 new_args[i] = entry 68 ret += glob_dirs(*new_args) 69 return ret 70 return sorted(glob.glob('/'.join(args))) 71 72def force_exists(files): 73 """force_exists raises an exception if any of the input files are missing 74 and returns the sorted list of inputs files""" 75 files = sorted(files) 76 glob_files = glob_dirs(files) 77 if glob_files != files: 78 raise(Exception('failed to find sources: %s' % ', '.join(['"'+x+'"' for x in list(set(files) - set(glob_files))]))) 79 return files 80 81def files_to_arch_files(base_files, arch): 82 files=[] 83 for f in base_files: 84 base, ext = os.path.splitext(os.path.basename(f)) 85 pattern = os.path.join(os.path.dirname(f), arch, base+'.[csS]') 86 glob_files = glob.glob(pattern) 87 if len(glob_files) > 1: 88 raise(Exception('expected at most one file for %s, found %s' % (pattern, glob_files))) 89 elif glob_files: 90 files.append(glob_files[0]) 91 92 return files 93 94class SourceSet(object): 95 def __init__(self, *, dirs=[], files=[]): 96 self.srcs = self._srcs(dirs, files) 97 self.arch_srcs, self.arch_exclude_srcs = self._arch_srcs(dirs, files) 98 99 def _srcs(self, dirs, files): 100 return glob_dirs(dirs, '*.c') + force_exists(files) 101 102 def _arch_srcs(self, dirs, files): 103 srcs = {} 104 exclude_srcs = {} 105 for bp_arch, musl_arch in BP_TO_MUSL_ARCHES.items(): 106 arch_srcs = glob_dirs(dirs, musl_arch, '*.[csS]') 107 arch_srcs += files_to_arch_files(files, musl_arch) 108 arch_exclude_srcs = overridden_base_srcs(musl_arch, arch_srcs) 109 if arch_srcs: 110 srcs[bp_arch] = arch_srcs 111 if arch_exclude_srcs: 112 exclude_srcs[bp_arch] = arch_exclude_srcs 113 return srcs, exclude_srcs 114 115 def intersect(self, other): 116 diff = self.subtract(other) 117 return self.subtract(diff) 118 119 def subtract(self, other): 120 ret = copy.deepcopy(self) 121 ret.srcs = sorted(list(set(ret.srcs) - set(other.srcs))) 122 for bp_arch in BP_TO_MUSL_ARCHES: 123 ret.arch_srcs[bp_arch] = sorted(list(set(ret.arch_srcs[bp_arch]) - set(other.arch_srcs[bp_arch]))) 124 ret.arch_exclude_srcs[bp_arch] = sorted(list(set(ret.arch_exclude_srcs[bp_arch]) - set(other.arch_exclude_srcs[bp_arch]))) 125 return ret 126 127 def union(self, other): 128 ret = copy.deepcopy(self) 129 ret.srcs = sorted(ret.srcs + other.srcs) 130 for bp_arch in BP_TO_MUSL_ARCHES: 131 ret.arch_srcs[bp_arch] = sorted(ret.arch_srcs[bp_arch] + other.arch_srcs[bp_arch]) 132 ret.arch_exclude_srcs[bp_arch] = sorted(ret.arch_exclude_srcs[bp_arch] + other.arch_exclude_srcs[bp_arch]) 133 return self 134 135class Blueprint(object): 136 def __init__(self, out): 137 self.out = out 138 139 def PrintHeader(self): 140 self.out.write( 141"""// Copyright (C) 2021 The Android Open Source Project 142// 143// Licensed under the Apache License, Version 2.0 (the "License"); 144// you may not use this file except in compliance with the License. 145// You may obtain a copy of the License at 146// 147// http://www.apache.org/licenses/LICENSE-2.0 148// 149// Unless required by applicable law or agreed to in writing, software 150// distributed under the License is distributed on an "AS IS" BASIS, 151// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 152// See the License for the specific language governing permissions and 153// limitations under the License. 154 155// This file is created by generate_bp.py. Do not edit manually. 156""") 157 158 def PrintDefaults(self, name, srcs): 159 """Print a cc_defaults section from a list of source files, architecture 160 specific source files, and source files replaced by architecture specific 161 source files""" 162 self.out.write('\n') 163 self.out.write('cc_defaults {\n') 164 self.out.write(' name: "%s",\n' % name) 165 self.out.write(' srcs: [\n') 166 for f in srcs.srcs: 167 self.out.write(' "%s",\n' % f) 168 self.out.write(' ],\n') 169 170 if srcs.arch_srcs or srcs.arch_exclude_srcs: 171 self.out.write(' arch: {\n') 172 for arch in BP_TO_MUSL_ARCHES.keys(): 173 if srcs.arch_srcs[arch] or srcs.arch_exclude_srcs[arch]: 174 self.out.write(' %s: {\n' % arch) 175 if srcs.arch_srcs[arch]: 176 self.out.write(' srcs: [\n') 177 for f in srcs.arch_srcs[arch]: 178 self.out.write(' "%s",\n' % f) 179 self.out.write(' ],\n') 180 if srcs.arch_exclude_srcs[arch]: 181 self.out.write(' exclude_srcs: [\n') 182 for f in srcs.arch_exclude_srcs[arch]: 183 self.out.write(' "%s",\n' % f) 184 self.out.write(' ],\n') 185 self.out.write(' },\n') 186 self.out.write(' },\n') 187 188 self.out.write('}\n') 189 190 191libc = SourceSet(dirs=SRC_DIRS) 192compat32 = SourceSet(dirs=COMPAT32_SRC_DIRS) 193opt = SourceSet(dirs=OPT_DIRS) 194nossp = SourceSet(files=NOSSP_SRCS) 195ldso = SourceSet(dirs=LDSO_SRC_DIRS) 196 197crts = {} 198for crt in CRT_SRCS: 199 srcs = SourceSet(files=[crt]) 200 name = os.path.splitext(os.path.basename(crt))[0] 201 crts[name] = srcs 202 203libc = libc.subtract(opt).subtract(nossp) 204opt_nossp = opt.intersect(nossp) 205opt = opt.subtract(opt_nossp) 206nossp = nossp.subtract(opt_nossp) 207 208dir_name = os.path.dirname(os.path.realpath(__file__)) 209 210with open(os.path.join(dir_name, '..', 'sources.bp'), 'w+') as out: 211 bp = Blueprint(out) 212 bp.PrintHeader() 213 bp.PrintDefaults('libc_musl_sources', libc) 214 bp.PrintDefaults('libc_musl_compat32_sources', compat32) 215 bp.PrintDefaults('libc_musl_opt_sources', opt) 216 bp.PrintDefaults('libc_musl_opt_nossp_sources', opt_nossp) 217 bp.PrintDefaults('libc_musl_nossp_sources', nossp) 218 bp.PrintDefaults('libc_musl_ldso_sources', ldso) 219 for crt in sorted(crts.keys()): 220 bp.PrintDefaults('libc_musl_%s_sources' % crt, crts[crt]) 221