xref: /aosp_15_r20/external/musl/android/generate_bp.py (revision c9945492fdd68bbe62686c5b452b4dc1be3f8453)
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