Make a status test pass against old servers.
[svn.git] / build / generator / gen_make.py
blobabb7e02e1dbee2328ccae5e8c8313f4a457a8e02
2 # gen_make.py -- generate makefiles and dependencies
5 import os
6 import sys
7 import string
8 import ConfigParser
10 import gen_base
11 import generator.swig.header_wrappers
12 import generator.swig.checkout_swig_header
13 import generator.swig.external_runtime
14 import generator.util.executable
15 _exec = generator.util.executable
17 from gen_base import build_path_join, build_path_strip, build_path_splitfile, \
18 build_path_basename, build_path_dirname, build_path_retreat, unique
20 try:
21 True
22 except NameError:
23 True = 1
24 False = 0
26 class Generator(gen_base.GeneratorBase):
28 _extension_map = {
29 ('exe', 'target'): '$(EXEEXT)',
30 ('exe', 'object'): '.o',
31 ('lib', 'target'): '.la',
32 ('lib', 'object'): '.lo',
35 def __init__(self, fname, verfname, options=None):
36 gen_base.GeneratorBase.__init__(self, fname, verfname, options)
37 self.section_counter = 0
38 self.assume_shared_libs = False
39 if ('--assume-shared-libs', '') in options:
40 self.assume_shared_libs = True
42 def begin_section(self, description):
43 self.section_counter = self.section_counter + 1
44 count = self.section_counter
46 self.ofile.write('\n########################################\n')
47 self.ofile.write('# Section %d: %s\n' % (count, description))
48 self.ofile.write('########################################\n\n')
50 def write(self):
51 self.ofile = open('build-outputs.mk', 'w')
52 self.ofile.write('# DO NOT EDIT -- AUTOMATICALLY GENERATED\n')
54 install_deps = self.graph.get_deps(gen_base.DT_INSTALL)
55 install_sources = self.graph.get_all_sources(gen_base.DT_INSTALL)
57 cp = ConfigParser.ConfigParser()
58 cp.read('gen-make.opts')
59 if cp.has_option('options', '--installed-libs'):
60 self.installed_libs = cp.get('options', '--installed-libs').split(',')
61 else:
62 self.installed_libs = []
64 # ensure consistency between runs
65 install_deps.sort()
66 install_sources.sort(lambda s1, s2: cmp(s1.name, s2.name))
68 ########################################
69 self.begin_section('Global make variables')
71 for target in install_sources:
72 if isinstance(target, gen_base.TargetRaModule) or \
73 isinstance(target, gen_base.TargetFsModule):
74 # name of the module: strip 'libsvn_' and upper-case it
75 name = string.upper(target.name[7:])
77 # construct a list of the other .la libs to link against
78 retreat = build_path_retreat(target.path)
79 if target.name in self.installed_libs:
80 deps = []
81 link = [ '-l%s-%s' % (target.name[3:], self.version) ]
82 else:
83 deps = [ target.filename ]
84 link = [ build_path_join(retreat, target.filename) ]
85 for source in self.graph.get_sources(gen_base.DT_LINK, target.name):
86 if not isinstance(source, gen_base.TargetLib) or source.external_lib:
87 continue
88 elif source.name in self.installed_libs:
89 continue
90 deps.append(source.filename)
91 link.append(build_path_join(retreat, source.filename))
93 self.ofile.write('%s_DEPS = %s\n'
94 '%s_LINK = %s\n\n' % (name, string.join(deps, ' '),
95 name, string.join(link, ' ')))
97 # write a list of directories in which things are built
98 # get all the test scripts' directories
99 script_dirs = map(build_path_dirname, self.scripts + self.bdb_scripts)
101 # remove duplicate directories between targets and tests
102 build_dirs = unique(self.target_dirs + script_dirs + self.swig_dirs)
104 self.ofile.write('BUILD_DIRS = %s\n\n' % string.join(build_dirs))
106 # write lists of test files
107 # deps = all, progs = not including those marked "testing = skip"
108 self.ofile.write('BDB_TEST_DEPS = %s\n\n' %
109 string.join(self.bdb_test_deps + self.bdb_scripts))
110 self.ofile.write('BDB_TEST_PROGRAMS = %s\n\n' %
111 string.join(self.bdb_test_progs + self.bdb_scripts))
112 self.ofile.write('TEST_DEPS = %s\n\n' %
113 string.join(self.test_deps + self.scripts))
114 self.ofile.write('TEST_PROGRAMS = %s\n\n' %
115 string.join(self.test_progs + self.scripts))
117 # write list of all manpages
118 self.ofile.write('MANPAGES = %s\n\n' % string.join(self.manpages))
120 # write a list of files to remove during "make clean"
121 cfiles = [ ]
122 for target in install_sources:
123 # .la files are handled by the standard 'clean' rule; clean all the
124 # other targets
125 if not isinstance(target, gen_base.TargetScript) \
126 and not isinstance(target, gen_base.TargetProject) \
127 and not isinstance(target, gen_base.TargetI18N) \
128 and not isinstance(target, gen_base.TargetJava) \
129 and not target.external_lib \
130 and target.filename[-3:] != '.la':
131 cfiles.append(target.filename)
132 cfiles.sort()
133 self.ofile.write('CLEAN_FILES = %s\n\n' % string.join(cfiles))
135 # this is here because autogen-standalone needs it too
136 self.ofile.write('SWIG_INCLUDES = -I$(abs_srcdir)/subversion/include \\\n'
137 ' -I$(abs_srcdir)/subversion/bindings/swig \\\n'
138 ' -I$(abs_srcdir)/subversion/bindings/swig/include \\\n'
139 ' -I$(abs_srcdir)/subversion/bindings/swig/proxy \\\n'
140 ' -I$(abs_builddir)/subversion/bindings/swig/proxy \\\n'
141 ' $(SVN_APR_INCLUDES) $(SVN_APRUTIL_INCLUDES)\n\n')
143 if self.release_mode:
144 self.ofile.write('RELEASE_MODE = 1\n\n')
146 ########################################
147 self.begin_section('SWIG headers (wrappers and external runtimes)')
149 if not self.release_mode:
150 for swig in (generator.swig.header_wrappers,
151 generator.swig.checkout_swig_header,
152 generator.swig.external_runtime):
153 gen = swig.Generator(self.conf, "swig")
154 gen.write_makefile_rules(self.ofile)
156 ########################################
157 self.begin_section('SWIG autogen rules')
159 # write dependencies and build rules for generated .c files
160 swig_c_deps = self.graph.get_deps(gen_base.DT_SWIG_C)
161 swig_c_deps.sort(lambda (t1, s1), (t2, s2): cmp(t1.filename, t2.filename))
163 swig_lang_deps = {}
164 for lang in self.swig.langs:
165 swig_lang_deps[lang] = []
167 short = self.swig.short
168 for objname, sources in swig_c_deps:
169 lang = objname.lang
170 swig_lang_deps[lang].append(str(objname))
172 for lang in self.swig.langs:
173 lang_deps = string.join(swig_lang_deps[lang])
174 self.ofile.write(
175 'autogen-swig-%s: %s\n' % (short[lang], lang_deps) +
176 'autogen-swig: autogen-swig-%s\n' % short[lang] +
177 '\n')
178 self.ofile.write('\n')
180 ########################################
181 self.begin_section('Rules to build SWIG .c files from .i files')
183 for objname, sources in swig_c_deps:
184 deps = string.join(map(str, sources))
185 source = str(sources[0])
186 source_dir = build_path_dirname(source)
187 opts = self.swig.opts[objname.lang]
188 if not self.release_mode:
189 self.ofile.write('$(top_builddir)/%s: %s\n' % (objname, deps) +
190 '\t$(SWIG) $(SWIG_INCLUDES) %s ' % opts +
191 '-o $@ $(top_srcdir)/%s\n' % source
194 self.ofile.write('\n')
196 ########################################
197 self.begin_section('Individual target build rules')
199 for target_ob in install_sources:
201 if isinstance(target_ob, gen_base.TargetScript):
202 # there is nothing to build
203 continue
205 target = target_ob.name
206 if isinstance(target_ob, gen_base.TargetJava):
207 path = target_ob.output_dir
208 else:
209 path = target_ob.path
211 retreat = build_path_retreat(path)
213 # get the source items (.o and .la) for the link unit
214 objects = [ ]
215 object_srcs = [ ]
216 headers = [ ]
217 header_classes = [ ]
218 header_class_filenames = [ ]
219 deps = [ ]
220 libs = [ ]
222 for link_dep in self.graph.get_sources(gen_base.DT_LINK, target_ob.name):
223 if isinstance(link_dep, gen_base.TargetJava):
224 deps.append(link_dep.name)
225 elif isinstance(link_dep, gen_base.TargetLinked):
226 if link_dep.external_lib:
227 libs.append(link_dep.external_lib)
228 elif link_dep.external_project:
229 # FIXME: This is a temporary workaround to fix build breakage
230 # expeditiously. It is of questionable validity for a build
231 # node to have external_project but not have external_lib.
232 pass
233 elif link_dep.name in self.installed_libs:
234 libs.append('-l%s-%s' % (link_dep.name[3:], self.version))
235 else:
236 # append the output of the target to our stated dependencies
237 if not self.assume_shared_libs:
238 deps.append(link_dep.filename)
240 # link against the library
241 libs.append(build_path_join(retreat, link_dep.filename))
242 elif isinstance(link_dep, gen_base.ObjectFile):
243 # link in the object file
244 objects.append(link_dep.filename)
245 for dep in self.graph.get_sources(gen_base.DT_OBJECT, link_dep, gen_base.SourceFile):
246 object_srcs.append(
247 build_path_join('$(abs_srcdir)', dep.filename))
248 elif isinstance(link_dep, gen_base.HeaderFile):
249 # link in the header file
250 # N.B. that filename_win contains the '_'-escaped class name
251 headers.append(link_dep.filename_win)
252 header_classes.append(link_dep.classname)
253 for dep in self.graph.get_sources(gen_base.DT_OBJECT, link_dep, gen_base.ObjectFile):
254 header_class_filenames.append(dep.filename)
255 else:
256 ### we don't know what this is, so we don't know what to do with it
257 raise UnknownDependency
259 for nonlib in self.graph.get_sources(gen_base.DT_NONLIB, target_ob.name):
260 if isinstance(nonlib, gen_base.TargetLinked):
261 if not nonlib.external_lib:
262 deps.append(nonlib.filename)
264 targ_varname = string.replace(target, '-', '_')
265 objnames = string.join(build_path_strip(path, objects))
267 # Output value of path variable
268 self.ofile.write('%s_PATH = %s\n' % (targ_varname, path))
270 # Add additional install dependencies if necessary
271 if target_ob.add_install_deps:
272 self.ofile.write('install-%s: %s\n'
273 % (target_ob.install, target_ob.add_install_deps))
275 if isinstance(target_ob, gen_base.TargetJava):
276 self.ofile.write(
277 '%s_HEADERS = %s\n'
278 '%s_OBJECTS = %s\n'
279 '%s_DEPS = $(%s_HEADERS) $(%s_OBJECTS) %s %s\n'
280 '%s: $(%s_DEPS)\n'
281 % (targ_varname, string.join(headers),
283 targ_varname, string.join(objects),
285 targ_varname, targ_varname, targ_varname, target_ob.add_deps,
286 string.join(deps),
288 target_ob.name, targ_varname))
290 # Build the headers from the header_classes with one 'javah' call
291 if headers:
292 self.ofile.write(
293 '%s_CLASS_FILENAMES = %s\n'
294 '%s_CLASSES = %s\n'
295 '$(%s_HEADERS): $(%s_CLASS_FILENAMES)\n'
296 '\t%s -d %s -classpath %s:$(%s_CLASSPATH) $(%s_CLASSES)\n'
297 % (targ_varname, string.join(header_class_filenames),
299 targ_varname, string.join(header_classes),
301 targ_varname, targ_varname,
303 target_ob.link_cmd, target_ob.output_dir, target_ob.classes,
304 targ_varname, targ_varname))
306 # Build the objects from the object_srcs with one 'javac' call
307 if object_srcs:
308 self.ofile.write(
309 '%s_SRC = %s\n'
310 '$(%s_OBJECTS): $(%s_SRC)\n'
311 '\t%s -d %s -classpath %s:$(%s_CLASSPATH) $(%s_SRC)\n'
312 % (targ_varname, string.join(object_srcs),
314 targ_varname, targ_varname,
316 target_ob.link_cmd, target_ob.output_dir, target_ob.classes,
317 targ_varname, targ_varname))
319 # Once the bytecodes have been compiled up, we produce the
320 # JAR.
321 if target_ob.jar:
322 self.ofile.write('\n\t$(JAR) cf %s -C %s %s' %
323 (build_path_join(target_ob.classes, target_ob.jar),
324 target_ob.classes,
325 string.join(target_ob.packages, ' ')))
327 self.ofile.write('\n\n')
328 elif isinstance(target_ob, gen_base.TargetI18N):
329 self.ofile.write(
330 '%s_DEPS = %s %s\n'
331 '%s: $(%s_DEPS)\n\n'
332 % (targ_varname, target_ob.add_deps, string.join(objects + deps),
333 target_ob.name, targ_varname))
334 else:
335 self.ofile.write(
336 '%s_DEPS = %s %s\n'
337 '%s_OBJECTS = %s\n'
338 '%s: $(%s_DEPS)\n'
339 '\tcd %s && %s -o %s %s $(%s_OBJECTS) %s $(LIBS)\n\n'
340 % (targ_varname, target_ob.add_deps, string.join(objects + deps),
342 targ_varname, objnames,
344 target_ob.filename, targ_varname,
346 path, target_ob.link_cmd,
347 build_path_basename(target_ob.filename),
348 (isinstance(target_ob, gen_base.TargetLib) and not
349 target_ob.undefined_lib_symbols) and '$(LT_NO_UNDEFINED)' or "",
350 targ_varname, string.join(gen_base.unique(libs)))
353 ########################################
354 self.begin_section('Install-Group build targets')
356 for itype, i_targets in install_deps:
358 # perl bindings do their own thing, "swig-pl" target is
359 # already specified in Makefile.in
360 if itype == "swig-pl":
361 continue
363 outputs = [ ]
364 for t in i_targets:
365 if hasattr(t, 'filename'):
366 outputs.append(t.filename)
367 self.ofile.write('%s: %s\n\n' % (itype, string.join(outputs)))
369 ########################################
370 self.begin_section('Install-Group install targets')
372 # for each install group, write a rule to install its outputs
373 for area, inst_targets in install_deps:
375 # perl bindings do their own thing, "install-swig-pl" target is
376 # already specified in Makefile.in
377 if area == "swig-pl":
378 continue
380 # get the output files for these targets, sorted in dependency order
381 files = gen_base._sorted_files(self.graph, area)
383 if area == 'apache-mod':
384 self.ofile.write('install-mods-shared: %s\n' % (string.join(files),))
385 la_tweaked = { }
386 for file in files:
387 # cd to dirname before install to work around libtool 1.4.2 bug.
388 dirname, fname = build_path_splitfile(file)
389 base, ext = os.path.splitext(fname)
390 name = string.replace(base, 'mod_', '')
391 self.ofile.write('\tcd %s ; '
392 '$(MKDIR) "$(APACHE_LIBEXECDIR)" ; '
393 '$(INSTALL_MOD_SHARED) -n %s %s\n'
394 % (dirname, name, fname))
395 if ext == '.la':
396 la_tweaked[file + '-a'] = None
398 for apmod in inst_targets:
399 for source in self.graph.get_sources(gen_base.DT_LINK, apmod.name,
400 gen_base.Target):
401 if not source.external_lib:
402 bt = source.filename
403 if bt[-3:] == '.la':
404 la_tweaked[bt + '-a'] = None
405 la_tweaked = la_tweaked.keys()
406 la_tweaked.sort()
408 # Construct a .libs directory within the Apache area and populate it
409 # with the appropriate files. Also drop the .la file in the target dir.
410 self.ofile.write('\ninstall-mods-static: %s\n'
411 '\t$(MKDIR) $(DESTDIR)%s\n'
412 % (string.join(la_tweaked + self.apache_files),
413 build_path_join('$(APACHE_TARGET)', '.libs')))
414 for file in la_tweaked:
415 dirname, fname = build_path_splitfile(file)
416 base = os.path.splitext(fname)[0]
417 self.ofile.write('\t$(INSTALL_MOD_STATIC) %s $(DESTDIR)%s\n'
418 '\t$(INSTALL_MOD_STATIC) %s $(DESTDIR)%s\n'
419 % (build_path_join(dirname, '.libs', base + '.a'),
420 build_path_join('$(APACHE_TARGET)', '.libs',
421 base + '.a'),
422 file,
423 build_path_join('$(APACHE_TARGET)', base + '.la')))
425 # copy the other files to the target dir
426 for file in self.apache_files:
427 self.ofile.write('\t$(INSTALL_MOD_STATIC) %s $(DESTDIR)%s\n'
428 % (file, build_path_join('$(APACHE_TARGET)',
429 build_path_basename(file))))
430 self.ofile.write('\n')
432 elif area != 'test' and area != 'bdb-test':
433 area_var = string.replace(area, '-', '_')
434 upper_var = string.upper(area_var)
435 self.ofile.write('install-%s: %s\n'
436 '\t$(MKDIR) $(DESTDIR)$(%sdir)\n'
437 % (area, string.join(files), area_var))
438 for file in files:
439 # cd to dirname before install to work around libtool 1.4.2 bug.
440 dirname, fname = build_path_splitfile(file)
441 if area == 'locale':
442 lang, objext = os.path.splitext(fname)
443 installdir = '$(DESTDIR)$(%sdir)/%s/LC_MESSAGES' % (area_var, lang)
444 self.ofile.write('\t$(MKDIR) %s\n'
445 '\tcd %s ; $(INSTALL_%s) %s '
446 '%s/$(PACKAGE_NAME)%s\n'
447 % (installdir,
448 dirname, upper_var, fname,
449 installdir, objext))
450 else:
451 self.ofile.write('\tcd %s ; $(INSTALL_%s) %s $(DESTDIR)%s\n'
452 % (dirname, upper_var, fname,
453 build_path_join('$(%sdir)' % area_var, fname)))
454 # certain areas require hooks for extra install rules defined
455 # in Makefile.in
456 ### we should turn AREA into an object, then test it instead of this
457 if area[:5] == 'swig-' and area[-4:] != '-lib' or \
458 area[:7] == 'javahl-':
459 self.ofile.write('\t$(INSTALL_EXTRA_%s)\n' % upper_var)
460 self.ofile.write('\n')
462 ########################################
463 self.begin_section('The install-include rule')
465 includedir = build_path_join('$(includedir)',
466 'subversion-%s' % self.version)
467 self.ofile.write('install-include: %s\n'
468 '\t$(MKDIR) $(DESTDIR)%s\n'
469 % (string.join(self.includes), includedir))
470 for file in self.includes:
471 self.ofile.write('\t$(INSTALL_INCLUDE) %s $(DESTDIR)%s\n'
472 % (build_path_join('$(abs_srcdir)', file),
473 build_path_join(includedir,
474 build_path_basename(file))))
476 ########################################
477 self.begin_section('Shortcut targets for manual builds of specific items')
479 for target in install_sources:
480 if not isinstance(target, gen_base.TargetScript) and \
481 not isinstance(target, gen_base.TargetJava) and \
482 not isinstance(target, gen_base.TargetI18N):
483 self.ofile.write('%s: %s\n' % (target.name, target.filename))
485 ########################################
486 self.begin_section('Rules to build all other kinds of object-like files')
488 # write dependencies and build rules (when not using suffix rules)
489 # for all other generated files which will not be installed
490 # (or will be installed, but not by the main generated build)
491 obj_deps = self.graph.get_deps(gen_base.DT_OBJECT)
492 obj_deps.sort(lambda (t1, s1), (t2, s2): cmp(t1.filename, t2.filename))
494 for objname, sources in obj_deps:
495 deps = string.join(map(str, sources))
496 self.ofile.write('%s: %s\n' % (objname, deps))
497 cmd = objname.compile_cmd
498 if cmd:
499 if not getattr(objname, 'source_generated', 0):
500 self.ofile.write('\t%s %s\n\n'
501 % (cmd, build_path_join('$(abs_srcdir)',
502 str(sources[0]))))
503 else:
504 self.ofile.write('\t%s %s\n\n' % (cmd, sources[0]))
505 else:
506 self.ofile.write('\n')
509 self.ofile.close()
510 self.write_standalone()
512 def write_standalone(self):
513 """Write autogen-standalone.mk"""
515 standalone = open("autogen-standalone.mk", "w")
516 standalone.write('# DO NOT EDIT -- AUTOMATICALLY GENERATED\n')
517 standalone.write('abs_srcdir = %s\n' % os.getcwd())
518 standalone.write('abs_builddir = %s\n' % os.getcwd())
519 standalone.write('top_srcdir = .\n')
520 standalone.write('top_builddir = .\n')
521 standalone.write('SWIG = swig\n')
522 standalone.write('PYTHON = python\n')
523 standalone.write('\n')
524 standalone.write(open("build-outputs.mk","r").read())
525 standalone.close()
527 class UnknownDependency(Exception):
528 "We don't know how to deal with the dependent to link it in."
529 pass
531 ### End of file.