xref: /aosp_15_r20/external/cronet/third_party/apache-portable-runtime/src/build/gen-build.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1#!/usr/bin/env python
2#
3# USAGE: gen-build.py TYPE
4#
5# where TYPE is one of: make, dsp, vcproj
6#
7# It reads build.conf from the current directory, and produces its output
8# into the current directory.
9#
10
11
12import os
13import ConfigParser
14import getopt
15import string
16import glob
17import re
18
19#import ezt
20
21#
22# legal platforms: aix, beos, netware, os2, os390, unix, win32
23# 'make' users: aix, beos, os2, os390, unix, win32 (mingw)
24#
25PLATFORMS = [ 'aix', 'beos', 'netware', 'os2', 'os390', 'unix', 'win32' ]
26MAKE_PLATFORMS = [
27  ('unix', None),
28  ('aix', 'unix'),
29  ('beos', 'unix'),
30  ('os2', 'unix'),
31  ('os390', 'unix'),
32  ('win32', 'unix'),
33  ]
34# note: MAKE_PLATFORMS is an ordered set. we want to generate unix symbols
35#       first, so that the later platforms can reference them.
36
37
38def main():
39  parser = ConfigParser.ConfigParser()
40  parser.read('build.conf')
41
42  if parser.has_option('options', 'dsp'):
43    dsp_file = parser.get('options', 'dsp')
44  else:
45    dsp_file = None
46
47  headers = get_files(parser.get('options', 'headers'))
48
49  # compute the relevant headers, along with the implied includes
50  legal_deps = { }
51  for fname in headers:
52    legal_deps[os.path.basename(fname)] = fname
53
54  h_deps = { }
55  for fname in headers:
56    h_deps[os.path.basename(fname)] = extract_deps(fname, legal_deps)
57  resolve_deps(h_deps)
58
59  f = open('build-outputs.mk', 'w')
60  f.write('# DO NOT EDIT. AUTOMATICALLY GENERATED.\n\n')
61
62  # write out the platform-independent files
63  files = get_files(parser.get('options', 'paths'))
64  objects, dirs = write_objects(f, legal_deps, h_deps, files)
65  f.write('\nOBJECTS_all = %s\n\n' % string.join(objects))
66
67  # for each platform and each subdirectory holding platform-specific files,
68  # write out their compilation rules, and an OBJECT_<subdir>_<plat> symbol.
69  for platform, parent in MAKE_PLATFORMS:
70
71    # record the object symbols to build for each platform
72    group = [ '$(OBJECTS_all)' ]
73
74    # If we're doing win32, we're going to look in the libapr.dsp file
75    # for those files that we have to manually add to our list.
76    inherit_parent = { }
77    if platform == 'win32' and dsp_file:
78      for line in open(dsp_file).readlines():
79        if line[:7] != 'SOURCE=':
80          continue
81        if line[7:].find('unix') != -1:
82          # skip the leading .\ and split it out
83          inherit_files = line[9:].strip().split('\\')
84          # change the .c to .lo
85          assert inherit_files[-1][-2:] == '.c'
86          inherit_files[-1] = inherit_files[-1][:-2] + '.lo'
87          # replace the \\'s with /'s
88          inherit_line = '/'.join(inherit_files)
89          if not inherit_parent.has_key(inherit_files[0]):
90            inherit_parent[inherit_files[0]] = []
91          inherit_parent[inherit_files[0]].append(inherit_line)
92
93    for subdir in string.split(parser.get('options', 'platform_dirs')):
94      path = '%s/%s' % (subdir, platform)
95      if not os.path.exists(path):
96        # this subdir doesn't have a subdir for this platform, so we'll
97        # use the parent-platform's set of symbols
98        if parent:
99          group.append('$(OBJECTS_%s_%s)' % (subdir, parent))
100        continue
101
102      # remember that this directory has files/objects
103      dirs[path] = None
104
105      # write out the compilation lines for this subdir
106      files = get_files(path + '/*.c')
107      objects, _unused = write_objects(f, legal_deps, h_deps, files)
108
109      if inherit_parent.has_key(subdir):
110        objects = objects + inherit_parent[subdir]
111
112      symname = 'OBJECTS_%s_%s' % (subdir, platform)
113
114      objects.sort()
115
116      # and write the symbol for the whole group
117      f.write('\n%s = %s\n\n' % (symname, string.join(objects)))
118
119      # and include that symbol in the group
120      group.append('$(%s)' % symname)
121
122    group.sort()
123
124    # write out a symbol which contains the necessary files
125    f.write('OBJECTS_%s = %s\n\n' % (platform, string.join(group)))
126
127  f.write('HEADERS = $(top_srcdir)/%s\n\n' % string.join(headers, ' $(top_srcdir)/'))
128  f.write('SOURCE_DIRS = %s $(EXTRA_SOURCE_DIRS)\n\n' % string.join(dirs.keys()))
129
130  if parser.has_option('options', 'modules'):
131    modules = parser.get('options', 'modules')
132
133    for mod in string.split(modules):
134      files = get_files(parser.get(mod, 'paths'))
135      objects, _unused = write_objects(f, legal_deps, h_deps, files)
136      flat_objects = string.join(objects)
137      f.write('OBJECTS_%s = %s\n' % (mod, flat_objects))
138
139      if parser.has_option(mod, 'target'):
140        target = parser.get(mod, 'target')
141        f.write('MODULE_%s = %s\n' % (mod, target))
142        f.write('%s: %s\n' % (target, flat_objects))
143        f.write('\t$(LINK_MODULE) -o $@ $(OBJECTS_%s) $(LDADD_%s)\n' % (mod, mod))
144
145      f.write('\n')
146
147  # Build a list of all necessary directories in build tree
148  alldirs = { }
149  for dir in dirs.keys():
150    d = dir
151    while d:
152      alldirs[d] = None
153      d = os.path.dirname(d)
154
155  # Sort so 'foo' is before 'foo/bar'
156  keys = alldirs.keys()
157  keys.sort()
158  f.write('BUILD_DIRS = %s\n\n' % string.join(keys))
159
160  f.write('.make.dirs: $(srcdir)/build-outputs.mk\n' \
161          '\t@for d in $(BUILD_DIRS); do test -d $$d || mkdir $$d; done\n' \
162          '\t@echo timestamp > $@\n')
163
164
165def write_objects(f, legal_deps, h_deps, files):
166  dirs = { }
167  objects = [ ]
168
169  for file in files:
170    if file[-10:] == '/apr_app.c':
171      continue
172    assert file[-2:] == '.c'
173    obj = file[:-2] + '.lo'
174    objects.append(obj)
175
176    dirs[os.path.dirname(file)] = None
177
178    # what headers does this file include, along with the implied headers
179    deps = extract_deps(file, legal_deps)
180    for hdr in deps.keys():
181      deps.update(h_deps.get(hdr, {}))
182
183    vals = deps.values()
184    vals.sort()
185    f.write('%s: %s .make.dirs %s\n' % (obj, file, string.join(vals)))
186
187  objects.sort()
188
189  return objects, dirs
190
191
192def extract_deps(fname, legal_deps):
193  "Extract the headers this file includes."
194  deps = { }
195  for line in open(fname).readlines():
196    if line[:8] != '#include':
197      continue
198    inc = _re_include.match(line).group(1)
199    if inc in legal_deps.keys():
200      deps[inc] = legal_deps[inc]
201  return deps
202_re_include = re.compile('#include *["<](.*)[">]')
203
204
205def resolve_deps(header_deps):
206  "Alter the provided dictionary to flatten includes-of-includes."
207  altered = 1
208  while altered:
209    altered = 0
210    for hdr, deps in header_deps.items():
211      # print hdr, deps
212      start = len(deps)
213      for dep in deps.keys():
214        deps.update(header_deps.get(dep, {}))
215      if len(deps) != start:
216        altered = 1
217
218def clean_path(path):
219    return path.replace("\\", "/")
220
221def get_files(patterns):
222  files = [ ]
223  for pat in string.split(patterns):
224    files.extend(map(clean_path, glob.glob(pat)))
225  files.sort()
226  return files
227
228
229if __name__ == '__main__':
230  main()
231