1 # a waf tool to add autoconf-like macros to the configure section
2 # and for SAMBA_ macros for building libraries, binaries etc
4 import Build, os, Logs, sys, Configure, Options, string, Task, Utils, optparse
5 from Configure import conf
7 from TaskGen import extension
9 # bring in the other samba modules
10 from samba_utils import *
11 from samba_autoconf import *
16 #############################################################
17 # set a value in a local cache
18 # return False if it's already set
19 def SET_TARGET_TYPE(ctx, target, value):
20 cache = LOCAL_CACHE(ctx, 'TARGET_TYPE')
22 ASSERT(ctx, cache[target] == value,
23 "Target '%s' re-defined as %s - was %s" % (target, value, cache[target]))
24 debug("task_gen: Skipping duplicate target %s (curdir=%s)" % (target, ctx.curdir))
26 assumed = LOCAL_CACHE(ctx, 'ASSUMED_TARGET')
28 #if assumed[target] != value:
29 # print "Target '%s' was assumed of type '%s' but is '%s'" % (target, assumed[target], value)
30 ASSERT(ctx, assumed[target] == value,
31 "Target '%s' was assumed of type '%s' but is '%s'" % (target, assumed[target], value))
32 predeclared = LOCAL_CACHE(ctx, 'PREDECLARED_TARGET')
33 if target in predeclared:
34 ASSERT(ctx, predeclared[target] == value,
35 "Target '%s' was predeclared of type '%s' but is '%s'" % (target, predeclared[target], value))
36 LOCAL_CACHE_SET(ctx, 'TARGET_TYPE', target, value)
37 debug("task_gen: Target '%s' created of type '%s' in %s" % (target, value, ctx.curdir))
41 #################################################################
42 # create the samba build environment
44 def SAMBA_BUILD_ENV(conf):
45 libpath="%s/%s" % (conf.blddir, LIB_PATH)
46 conf.env['BUILD_DIRECTORY'] = conf.blddir
47 if not os.path.exists(libpath):
50 ##############################################
51 # remove .. elements from a path list
52 def NORMPATH(bld, ilist):
53 return " ".join([os.path.normpath(p) for p in ilist.split(" ")])
54 Build.BuildContext.NORMPATH = NORMPATH
56 ################################################################
57 # add an init_function to the list for a subsystem
58 def ADD_INIT_FUNCTION(bld, subsystem, init_function):
59 if init_function is None:
61 bld.ASSERT(subsystem is not None, "You must specify a subsystem for init_function '%s'" % init_function)
62 cache = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
63 if not subsystem in cache:
65 cache[subsystem] += '%s,' % init_function
66 Build.BuildContext.ADD_INIT_FUNCTION = ADD_INIT_FUNCTION
68 ################################################################
69 # recursively build the dependency list for a target
70 def FULL_DEPENDENCIES(bld, cache, target, chain, path):
71 if not target in cache:
73 deps = cache[target].copy()
74 for t in cache[target]:
75 bld.ASSERT(t not in chain, "Circular dependency for %s: %s->%s" % (t, path, t));
78 dict_concat(deps, FULL_DEPENDENCIES(bld, cache, t, c2, "%s->%s" % (path, t)))
81 ############################################################
82 # check our build dependencies for circular dependencies
83 def CHECK_TARGET_DEPENDENCY(bld, target):
84 cache = LOCAL_CACHE(bld, 'LIB_DEPS')
85 return FULL_DEPENDENCIES(bld, cache, target, { target:True }, target)
87 ############################################################
88 # check that all dependencies have been declared
89 def CHECK_DEPENDENCIES(bld):
90 cache = LOCAL_CACHE(bld, 'LIB_DEPS')
91 target_cache = LOCAL_CACHE(bld, 'TARGET_TYPE')
92 debug('deps: Checking dependencies')
94 deps = CHECK_TARGET_DEPENDENCY(bld, t)
96 #if not d in target_cache:
97 # print "Dependency '%s' of target '%s' not declared" % (d, t)
98 ASSERT(bld, d in target_cache,
99 "Dependency '%s' of target '%s' not declared" % (d, t))
100 debug("deps: Dependencies checked for %u targets" % len(target_cache))
101 Build.BuildContext.CHECK_DEPENDENCIES = CHECK_DEPENDENCIES
104 ############################################################
105 # pre-declare a target as being of a particular type
106 def PREDECLARE(bld, target, type):
107 cache = LOCAL_CACHE(bld, 'PREDECLARED_TARGET')
108 target_cache = LOCAL_CACHE(bld, 'TARGET_TYPE')
109 ASSERT(bld, not target in target_cache, "Target '%s' is already declared" % target)
110 ASSERT(bld, not target in cache, "Target '%s' already predeclared" % target)
112 Build.BuildContext.PREDECLARE = PREDECLARE
116 ################################################################
117 # add to the dependency list. Return a new dependency list with
118 # any circular dependencies removed
119 # returns a tuple containing (systemdeps, localdeps, add_objects)
120 def ADD_DEPENDENCIES(bld, name, deps):
121 debug('deps: Calculating dependencies for %s' % name)
122 lib_deps = LOCAL_CACHE(bld, 'LIB_DEPS')
123 if not name in lib_deps:
128 lib_deps[name][d] = True;
130 CHECK_TARGET_DEPENDENCY(bld, name)
132 except AssertionError:
133 debug("deps: Removing dependency %s from target %s" % (d, name))
134 del(lib_deps[name][d])
136 # extract out the system dependencies
140 cache = LOCAL_CACHE(bld, 'EMPTY_TARGETS')
141 target_cache = LOCAL_CACHE(bld, 'TARGET_TYPE')
142 predeclare = LOCAL_CACHE(bld, 'PREDECLARED_TARGET')
145 # strip out any dependencies on empty libraries
147 debug("deps: Removing empty dependency '%s' from '%s'" % (d, name))
151 if d in target_cache:
152 type = target_cache[d]
153 elif d in predeclare:
157 LOCAL_CACHE_SET(bld, 'ASSUMED_TARGET', d, type)
161 elif type == 'LIBRARY':
163 elif type == 'SUBSYSTEM':
164 add_objects.append(d)
166 elif type == 'MODULE':
167 add_objects.append(d)
169 elif type == 'PYTHON':
173 elif type == 'BINARY':
176 ASSERT(bld, False, "Unknown target type '%s' for dependency %s" % (
179 # for some types we have to build the list recursively
180 if recurse and (d in lib_deps):
181 rec_deps = ' '.join(lib_deps[d].keys())
182 (rec_sysdeps, rec_localdeps, rec_add_objects) = ADD_DEPENDENCIES(bld, d, rec_deps)
183 sysdeps.extend(rec_sysdeps.split())
184 localdeps.extend(rec_localdeps.split())
185 add_objects.extend(rec_add_objects.split())
187 debug('deps: Dependencies for %s: sysdeps: %u localdeps: %u add_objects=%u' % (
188 name, len(sysdeps), len(localdeps), len(add_objects)))
189 return (' '.join(sysdeps), ' '.join(localdeps), ' '.join(add_objects))
192 #################################################################
193 # return a include list for a set of library dependencies
194 def SAMBA_LIBRARY_INCLUDE_LIST(bld, deps):
195 ret = bld.curdir + ' '
196 cache = LOCAL_CACHE(bld, 'INCLUDE_LIST')
197 for l in deps.split():
199 ret = ret + cache[l] + ' '
201 Build.BuildContext.SAMBA_LIBRARY_INCLUDE_LIST = SAMBA_LIBRARY_INCLUDE_LIST
203 #################################################################
204 # define a Samba library
205 def SAMBA_LIBRARY(bld, libname, source_list,
215 if not SET_TARGET_TYPE(bld, libname, 'LIBRARY'):
218 # remember empty libraries, so we can strip the dependencies
219 if (source_list == '') or (source_list == []):
220 LOCAL_CACHE_SET(bld, 'EMPTY_TARGETS', libname, True)
223 (sysdeps, localdeps, add_objects) = ADD_DEPENDENCIES(bld, libname, deps)
225 ilist = bld.SAMBA_LIBRARY_INCLUDE_LIST(deps) + bld.SUBDIR(bld.curdir, include_list)
226 ilist = bld.NORMPATH(ilist)
227 bld.SET_BUILD_GROUP('main')
229 features = 'cc cshlib',
230 source = source_list,
232 uselib_local = localdeps,
234 add_objects = add_objects,
235 ccflags = CURRENT_CFLAGS(bld, cflags),
236 includes='. ' + bld.env['BUILD_DIRECTORY'] + '/default ' + ilist,
239 # put a link to the library in bin/shared
242 soext = '.' + vnum.split('.')[0]
243 bld.SET_BUILD_GROUP('final')
245 source = 'lib%s.so' % libname,
246 rule = 'ln -sf ../${SRC}%s %s/lib%s.so%s' %
247 (soext, LIB_PATH, libname, soext),
251 LOCAL_CACHE_SET(bld, 'INCLUDE_LIST', libname, ilist)
253 Build.BuildContext.SAMBA_LIBRARY = SAMBA_LIBRARY
256 #################################################################
257 # define a Samba binary
258 def SAMBA_BINARY(bld, binname, source_list,
271 ilist = '. ' + bld.env['BUILD_DIRECTORY'] + '/default ' + bld.SAMBA_LIBRARY_INCLUDE_LIST(deps) + ' ' + include_list
272 ilist = bld.NORMPATH(ilist)
274 if not SET_TARGET_TYPE(bld, binname, 'BINARY'):
277 (sysdeps, localdeps, add_objects) = ADD_DEPENDENCIES(bld, binname, deps)
279 cache = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
280 if modules is not None:
281 for m in modules.split():
282 bld.ASSERT(m in cache,
283 "No init_function defined for module '%s' in binary '%s'" % (m, binname))
284 cflags += ' -DSTATIC_%s_MODULES="%s"' % (m, cache[m])
286 bld.SET_BUILD_GROUP(group)
288 features = 'cc cprogram',
289 source = source_list,
291 uselib_local = localdeps,
294 ccflags = CURRENT_CFLAGS(bld, cflags),
295 add_objects = add_objects,
297 # put a link to the binary in bin/
298 if not Options.is_install:
301 rule = 'rm -f %s && cp ${SRC} .' % (binname),
305 Build.BuildContext.SAMBA_BINARY = SAMBA_BINARY
308 #################################################################
309 # define a Samba python module
310 def SAMBA_PYTHON(bld, name, source_list,
315 if not SET_TARGET_TYPE(bld, name, 'PYTHON'):
318 (sysdeps, localdeps, add_objects) = ADD_DEPENDENCIES(bld, name, deps)
321 Build.BuildContext.SAMBA_PYTHON = SAMBA_PYTHON
324 ################################################################################
325 # a asn1 task which calls out to asn1_compile_wrapper.sh to do the work
326 Task.simple_task_type('asn1',
328 # shell script to convert ASN1 to C. This could be separated out if we want to
330 compiler=${TGT[0].compiler}
331 destdir=${TGT[0].destdir}
332 wrapper=${TGT[0].asn1wrapper}
333 srcfile=${SRC[0].abspath(env)}
334 asn1name=${TGT[0].asn1name}
335 options="${TGT[0].asn1options}"
338 $wrapper . $destdir $compiler $srcfile $asn1name ${options} --one-code-file
340 # that generated 3 files:
346 hxfile=$destdir/$asn1name.hx
347 xfile=$destdir/asn1_$asn1name.x
348 listfilee=$destdir/"$asn1name"_files
350 cfile=${TGT[0].abspath(env)}
351 hfile=${TGT[1].abspath(env)}
354 echo '#include "config.h"' > $cfile
364 def process_asn1(self, node):
366 asn1name = string.replace(node.file(), '.', '_')
367 c_node = NEW_NODE(node, 'asn1_%s.c' % asn1name)
368 h_node = NEW_NODE(node, '%s.h' % asn1name)
370 c_node.destdir = "default/source4/heimdal/" + self.asn1directory
371 c_node.asn1options = self.asn1options
372 c_node.asn1name = asn1name
373 c_node.asn1wrapper = "../heimdal_build/asn1_compile_wrapper.sh"
374 c_node.compiler = "default/source4/heimdal_build/asn1_compile"
376 self.create_task('asn1', node, [c_node, h_node])
377 self.allnodes.append(c_node)
380 #################################################################
381 # define a Samba ASN1 target
382 def SAMBA_ASN1(bld, name, source,
385 if not SET_TARGET_TYPE(bld, name, 'ASN1'):
387 bld.SET_BUILD_GROUP('build_source')
392 asn1options = options,
393 asn1directory = directory
395 Build.BuildContext.SAMBA_ASN1 = SAMBA_ASN1
399 ################################################################################
400 # a et task which calls out to compile_et to do the work
401 Task.simple_task_type('et',
402 '../heimdal_build/et_compile_wrapper.sh . ${TGT[0].bld_dir(env)} default/source4/heimdal_build/compile_et ${SRC[0].abspath(env)} ${TGT[0].bldpath(env)}',
403 color='BLUE', ext_out='.c',
407 def process_et(self, node):
408 c_node = node.change_ext('.c')
409 h_node = node.change_ext('.h')
410 self.create_task('et', node, [c_node, h_node])
411 self.allnodes.append(c_node)
414 #################################################################
415 # define a Samba ET target
416 def SAMBA_ERRTABLE(bld, name, source,
419 if not SET_TARGET_TYPE(bld, name, 'ET'):
421 bld.SET_BUILD_GROUP('build_source')
427 Build.BuildContext.SAMBA_ERRTABLE = SAMBA_ERRTABLE
429 ##########################################################
430 # create a node with a new name, based on an existing node
431 def NEW_NODE(node, name):
432 ret = node.parent.find_or_declare([name])
433 ASSERT(node, ret is not None, "Unable to find new target with name '%s' from '%s'" % (
437 ################################################################################
438 # a idl task which calls out to pidl to do the work
439 Task.simple_task_type('idl', '../../pidl/pidl --header --ndr-parser --client --python --server --outputdir=${TGT[0].outputdir} -- ${SRC}', color='BLUE', ext_out='.c')
442 def process_idl(self, node):
443 bname = node.file_base()
444 c_node = NEW_NODE(node, 'ndr_%s.c' % bname)
445 h1_node = NEW_NODE(node, '%s.h' % bname)
446 h2_node = NEW_NODE(node, 'ndr_%s.h' % bname)
447 s_node = NEW_NODE(node, 'ndr_%s_s.c' % bname)
448 cli_node = NEW_NODE(node, 'ndr_%s_c.c' % bname)
449 cli_h_node = NEW_NODE(node, 'ndr_%s_c.h' % bname)
450 py_node = NEW_NODE(node, 'py_%s.c' % bname)
453 dname = os.path.dirname(node.bld_dir(self.env)) + "/gen_ndr"
454 c_node.outputdir = dname
456 self.create_task('idl', node, [c_node, h1_node, h2_node, s_node, cli_node, cli_h_node, py_node])
458 # reinject the c node to the list of nodes to process
459 self.allnodes.append(c_node)
462 #################################################################
463 # define a PIDL target
464 def SAMBA_PIDL(bld, directory, source):
465 name = os.path.basename(string.replace(source, '.idl', ''))
466 name = "%s/ndr_%s.o" % (directory, name)
468 if not SET_TARGET_TYPE(bld, name, 'PIDL'):
471 bld.SET_BUILD_GROUP('build_source')
477 Build.BuildContext.SAMBA_PIDL = SAMBA_PIDL
481 #################################################################
482 # define a set of Samba PIDL targets
483 def SAMBA_PIDL_LIST(bld, directory, source_list):
484 for p in source_list.split():
485 bld.SAMBA_PIDL(directory, p)
486 Build.BuildContext.SAMBA_PIDL_LIST = SAMBA_PIDL_LIST
489 ################################################################
490 # build a C prototype file automatically
491 def AUTOPROTO(bld, header, source_list):
492 if header is not None:
493 bld.SET_BUILD_GROUP('prototypes')
495 source = source_list,
497 rule = '../script/mkproto.pl --srcdir=.. --builddir=. --public=/dev/null --private=${TGT} ${SRC}'
499 Build.BuildContext.AUTOPROTO = AUTOPROTO
502 #################################################################
503 # define a Samba module.
504 def SAMBA_MODULE(bld, modname, source_list,
514 if not SET_TARGET_TYPE(bld, modname, 'MODULE'):
517 # remember empty modules, so we can strip the dependencies
518 if (source_list == '') or (source_list == []):
519 LOCAL_CACHE_SET(bld, 'EMPTY_TARGETS', modname, True)
522 (sysdeps, localdeps, add_objects) = ADD_DEPENDENCIES(bld, modname, deps)
524 ilist = bld.SAMBA_LIBRARY_INCLUDE_LIST(deps) + bld.SUBDIR(bld.curdir, include_list)
525 ilist = bld.NORMPATH(ilist)
526 bld.SET_BUILD_GROUP('main')
529 source = source_list,
531 ccflags = CURRENT_CFLAGS(bld, cflags),
532 includes='. ' + bld.env['BUILD_DIRECTORY'] + '/default ' + ilist)
533 Build.BuildContext.SAMBA_MODULE = SAMBA_MODULE
536 #################################################################
537 # define a Samba subsystem
538 def SAMBA_SUBSYSTEM(bld, modname, source_list,
547 init_function_sentinal=None):
549 if not SET_TARGET_TYPE(bld, modname, 'SUBSYSTEM'):
552 # if the caller specifies a config_option, then we create a blank
553 # subsystem if that configuration option was found at configure time
554 if (config_option is not None) and bld.CONFIG_SET(config_option):
557 # remember empty subsystems, so we can strip the dependencies
558 if (source_list == '') or (source_list == []):
559 LOCAL_CACHE_SET(bld, 'EMPTY_TARGETS', modname, True)
562 (sysdeps, localdeps, add_objects) = ADD_DEPENDENCIES(bld, modname, deps)
564 ilist = bld.SAMBA_LIBRARY_INCLUDE_LIST(deps) + bld.SUBDIR(bld.curdir, include_list)
565 ilist = bld.NORMPATH(ilist)
566 bld.SET_BUILD_GROUP(group)
569 source = source_list,
571 ccflags = CURRENT_CFLAGS(bld, cflags),
572 includes='. ' + bld.env['BUILD_DIRECTORY'] + '/default ' + ilist)
573 Build.BuildContext.SAMBA_SUBSYSTEM = SAMBA_SUBSYSTEM
576 ###############################################################
577 # add a new set of build rules from a subdirectory
578 # the @runonce decorator ensures we don't end up
579 # with duplicate rules
580 def BUILD_SUBDIR(bld, dir):
581 path = os.path.normpath(bld.curdir + '/' + dir)
582 cache = LOCAL_CACHE(bld, 'SUBDIR_LIST')
583 if path in cache: return
585 debug("build: Processing subdirectory %s" % dir)
588 Build.BuildContext.BUILD_SUBDIR = BUILD_SUBDIR
591 ##########################################################
592 # add a new top level command to waf
593 def ADD_COMMAND(opt, name, function):
594 Utils.g_module.__dict__[name] = function
596 Options.Handler.ADD_COMMAND = ADD_COMMAND
598 ###########################################################
599 # setup build groups used to ensure that the different build
600 # phases happen consecutively
602 def SETUP_BUILD_GROUPS(bld):
603 bld.env['USING_BUILD_GROUPS'] = True
604 bld.add_group('setup')
605 bld.add_group('build_compilers')
606 bld.add_group('build_source')
607 bld.add_group('prototypes')
608 bld.add_group('main')
609 bld.add_group('final')
610 Build.BuildContext.SETUP_BUILD_GROUPS = SETUP_BUILD_GROUPS
613 ###########################################################
614 # set the current build group
615 def SET_BUILD_GROUP(bld, group):
616 if not 'USING_BUILD_GROUPS' in bld.env:
619 Build.BuildContext.SET_BUILD_GROUP = SET_BUILD_GROUP