3 # USAGE: gen-build.py TYPE
5 # where TYPE is one of: make, dsp, vcproj
7 # It reads build.conf from the current directory, and produces its output
8 # into the current directory.
22 # legal platforms: aix, beos, netware, os2, os390, unix, win32
23 # 'make' users: aix, beos, os2, os390, unix, win32 (mingw)
25 PLATFORMS = [ 'aix', 'beos', 'netware', 'os2', 'os390', 'unix', 'win32' ]
34 # note: MAKE_PLATFORMS is an ordered set. we want to generate unix symbols
35 # first, so that the later platforms can reference them.
39 parser = ConfigParser.ConfigParser()
40 parser.read('build.conf')
42 if parser.has_option('options', 'dsp'):
43 dsp_file = parser.get('options', 'dsp')
47 headers = get_files(parser.get('options', 'headers'))
49 # compute the relevant headers, along with the implied includes
52 legal_deps[os.path.basename(fname)] = fname
56 h_deps[os.path.basename(fname)] = extract_deps(fname, legal_deps)
59 f = open('build-outputs.mk', 'w')
60 f.write('# DO NOT EDIT. AUTOMATICALLY GENERATED.\n\n')
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))
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:
71 # record the object symbols to build for each platform
72 group = [ '$(OBJECTS_all)' ]
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.
77 if platform == 'win32' and dsp_file:
78 for line in open(dsp_file).readlines():
79 if line[:7] != 'SOURCE=':
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)
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
99 group.append('$(OBJECTS_%s_%s)' % (subdir, parent))
102 # remember that this directory has files/objects
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)
109 if inherit_parent.has_key(subdir):
110 objects = objects + inherit_parent[subdir]
112 symname = 'OBJECTS_%s_%s' % (subdir, platform)
116 # and write the symbol for the whole group
117 f.write('\n%s = %s\n\n' % (symname, string.join(objects)))
119 # and include that symbol in the group
120 group.append('$(%s)' % symname)
124 # write out a symbol which contains the necessary files
125 f.write('OBJECTS_%s = %s\n\n' % (platform, string.join(group)))
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()))
130 if parser.has_option('options', 'modules'):
131 modules = parser.get('options', 'modules')
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))
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))
147 # Build a list of all necessary directories in build tree
149 for dir in dirs.keys():
153 d = os.path.dirname(d)
155 # Sort so 'foo' is before 'foo/bar'
156 keys = alldirs.keys()
158 f.write('BUILD_DIRS = %s\n\n' % string.join(keys))
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')
165 def write_objects(f, legal_deps, h_deps, files):
170 if file[-10:] == '/apr_app.c':
172 assert file[-2:] == '.c'
173 obj = file[:-2] + '.lo'
176 dirs[os.path.dirname(file)] = None
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, {}))
185 f.write('%s: %s .make.dirs %s\n' % (obj, file, string.join(vals)))
192 def extract_deps(fname, legal_deps):
193 "Extract the headers this file includes."
195 for line in open(fname).readlines():
196 if line[:8] != '#include':
198 inc = _re_include.match(line).group(1)
199 if inc in legal_deps.keys():
200 deps[inc] = legal_deps[inc]
202 _re_include = re.compile('#include *["<](.*)[">]')
205 def resolve_deps(header_deps):
206 "Alter the provided dictionary to flatten includes-of-includes."
210 for hdr, deps in header_deps.items():
213 for dep in deps.keys():
214 deps.update(header_deps.get(dep, {}))
215 if len(deps) != start:
218 def clean_path(path):
219 return path.replace("\\", "/")
221 def get_files(patterns):
223 for pat in string.split(patterns):
224 files.extend(map(clean_path, glob.glob(pat)))
229 if __name__ == '__main__':