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