build: add output_type and realname for mit_samba library
[nivanova/samba-autobuild/.git] / buildtools / wafsamba / wafsamba.py
1 # a waf tool to add autoconf-like macros to the configure section
2 # and for SAMBA_ macros for building libraries, binaries etc
3
4 import Build, os, Logs, sys, Configure, Options, string, Task, Utils, optparse
5 from Configure import conf
6 from Logs import debug
7 from TaskGen import extension
8
9 # bring in the other samba modules
10 from samba_utils import *
11 from samba_autoconf import *
12
13 LIB_PATH="shared"
14
15
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')
21     if target in cache:
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))
25         return False
26     assumed = LOCAL_CACHE(ctx, 'ASSUMED_TARGET')
27     if target in assumed:
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))
38     return True
39
40
41 #################################################################
42 # create the samba build environment
43 @conf
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):
48         os.mkdir(libpath)
49
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
55
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:
60         return
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:
64         cache[subsystem] = ''
65     cache[subsystem] += '%s,' % init_function
66 Build.BuildContext.ADD_INIT_FUNCTION = ADD_INIT_FUNCTION
67
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:
72         return {}
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));
76         c2 = chain.copy()
77         c2[t] = True
78         dict_concat(deps, FULL_DEPENDENCIES(bld, cache, t, c2, "%s->%s" % (path, t)))
79     return deps
80
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)
86
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')
93     for t in cache:
94         deps = CHECK_TARGET_DEPENDENCY(bld, t)
95         for d in deps:
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
102
103
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)
111     cache[target] = type
112 Build.BuildContext.PREDECLARE = PREDECLARE
113
114
115
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:
124         lib_deps[name] = {}
125     list = deps.split()
126     list2 = []
127     for d in list:
128         lib_deps[name][d] = True;
129         try:
130             CHECK_TARGET_DEPENDENCY(bld, name)
131             list2.append(d)
132         except AssertionError:
133             debug("deps: Removing dependency %s from target %s" % (d, name))
134             del(lib_deps[name][d])
135
136     # extract out the system dependencies
137     sysdeps = []
138     localdeps = []
139     add_objects = []
140     cache = LOCAL_CACHE(bld, 'EMPTY_TARGETS')
141     target_cache = LOCAL_CACHE(bld, 'TARGET_TYPE')
142     predeclare = LOCAL_CACHE(bld, 'PREDECLARED_TARGET')
143     for d in list2:
144         recurse = False
145         # strip out any dependencies on empty libraries
146         if d in cache:
147             debug("deps: Removing empty dependency '%s' from '%s'" % (d, name))
148             continue
149         type = None
150
151         if d in target_cache:
152             type = target_cache[d]
153         elif d in predeclare:
154             type = predeclare[d]
155         else:
156             type = 'SUBSYSTEM'
157             LOCAL_CACHE_SET(bld, 'ASSUMED_TARGET', d, type)
158
159         if type == 'SYSLIB':
160             sysdeps.append(d)
161         elif type == 'LIBRARY':
162             localdeps.append(d)
163         elif type == 'SUBSYSTEM':
164             add_objects.append(d)
165             recurse = True
166         elif type == 'MODULE':
167             add_objects.append(d)
168             recurse = True
169         elif type == 'PYTHON':
170             pass
171         elif type == 'ASN1':
172             pass
173         elif type == 'BINARY':
174             pass
175         else:
176             ASSERT(bld, False, "Unknown target type '%s' for dependency %s" % (
177                     type, d))
178
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())
186
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))
190
191
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():
198         if l in cache:
199             ret = ret + cache[l] + ' '
200     return ret
201 Build.BuildContext.SAMBA_LIBRARY_INCLUDE_LIST = SAMBA_LIBRARY_INCLUDE_LIST
202
203 #################################################################
204 # define a Samba library
205 def SAMBA_LIBRARY(bld, libname, source_list,
206                   deps='',
207                   public_deps='',
208                   include_list='.',
209                   public_headers=None,
210                   vnum=None,
211                   cflags='',
212                   output_type=None,
213                   realname=None,
214                   autoproto=None):
215     if not SET_TARGET_TYPE(bld, libname, 'LIBRARY'):
216         return
217
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)
221         return
222
223     (sysdeps, localdeps, add_objects) = ADD_DEPENDENCIES(bld, libname, deps)
224
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')
228     bld(
229         features = 'cc cshlib',
230         source = source_list,
231         target=libname,
232         uselib_local = localdeps,
233         uselib = sysdeps,
234         add_objects = add_objects,
235         ccflags = CURRENT_CFLAGS(bld, cflags),
236         includes='. ' + bld.env['BUILD_DIRECTORY'] + '/default ' + ilist,
237         vnum=vnum)
238
239     # put a link to the library in bin/shared
240     soext=""
241     if vnum is not None:
242         soext = '.' + vnum.split('.')[0]
243     bld.SET_BUILD_GROUP('final')
244     bld(
245         source = 'lib%s.so' % libname,
246         rule = 'ln -sf ../${SRC}%s %s/lib%s.so%s' %
247         (soext, LIB_PATH, libname, soext),
248         shell = True,
249         after = 'cc_link',
250         )
251     LOCAL_CACHE_SET(bld, 'INCLUDE_LIST', libname, ilist)
252
253 Build.BuildContext.SAMBA_LIBRARY = SAMBA_LIBRARY
254
255
256 #################################################################
257 # define a Samba binary
258 def SAMBA_BINARY(bld, binname, source_list,
259                  deps='',
260                  include_list='',
261                  public_headers=None,
262                  modules=None,
263                  installdir=None,
264                  ldflags=None,
265                  cflags='',
266                  autoproto=None,
267                  use_hostcc=None,
268                  compiler=None,
269                  group='main',
270                  manpages=None):
271     ilist = '. ' + bld.env['BUILD_DIRECTORY'] + '/default ' + bld.SAMBA_LIBRARY_INCLUDE_LIST(deps) + ' ' + include_list
272     ilist = bld.NORMPATH(ilist)
273
274     if not SET_TARGET_TYPE(bld, binname, 'BINARY'):
275         return
276
277     (sysdeps, localdeps, add_objects) = ADD_DEPENDENCIES(bld, binname, deps)
278
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])
285
286     bld.SET_BUILD_GROUP(group)
287     bld(
288         features = 'cc cprogram',
289         source = source_list,
290         target = binname,
291         uselib_local = localdeps,
292         uselib = sysdeps,
293         includes = ilist,
294         ccflags = CURRENT_CFLAGS(bld, cflags),
295         add_objects = add_objects,
296         top=True)
297     # put a link to the binary in bin/
298     if not Options.is_install:
299         bld(
300             source = binname,
301             rule = 'rm -f %s && cp ${SRC} .' % (binname),
302             shell = True,
303             after = 'cc_link'
304             )
305 Build.BuildContext.SAMBA_BINARY = SAMBA_BINARY
306
307
308 #################################################################
309 # define a Samba python module
310 def SAMBA_PYTHON(bld, name, source_list,
311                  deps='',
312                  public_deps='',
313                  realname=''):
314
315     if not SET_TARGET_TYPE(bld, name, 'PYTHON'):
316         return
317
318     (sysdeps, localdeps, add_objects) = ADD_DEPENDENCIES(bld, name, deps)
319
320     return
321 Build.BuildContext.SAMBA_PYTHON = SAMBA_PYTHON
322
323
324 ################################################################################
325 # a asn1 task which calls out to asn1_compile_wrapper.sh to do the work
326 Task.simple_task_type('asn1',
327                       '''
328 # shell script to convert ASN1 to C. This could be separated out if we want to
329 set -e
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}"
336
337 # run the wrapper
338 $wrapper . $destdir $compiler $srcfile $asn1name ${options} --one-code-file
339
340 # that generated 3 files:
341 #    ${asn1name}.hx
342 #    asn1_${asn1name}.x
343 #    ${asn1name}_files
344
345
346 hxfile=$destdir/$asn1name.hx
347 xfile=$destdir/asn1_$asn1name.x
348 listfilee=$destdir/"$asn1name"_files
349
350 cfile=${TGT[0].abspath(env)}
351 hfile=${TGT[1].abspath(env)}
352
353 cp $hxfile $hfile
354 echo '#include "config.h"' > $cfile
355 cat $xfile >> $cfile
356 rm -f $listfile
357
358 ''',
359                       color='BLUE',
360                       ext_out='.c',
361                       shell = True)
362
363 @extension('.asn1')
364 def process_asn1(self, node):
365
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)
369
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"
375
376     self.create_task('asn1', node, [c_node, h_node])
377     self.allnodes.append(c_node)
378
379
380 #################################################################
381 # define a Samba ASN1 target
382 def SAMBA_ASN1(bld, name, source,
383                options='',
384                directory=''):
385     if not SET_TARGET_TYPE(bld, name, 'ASN1'):
386         return
387     bld.SET_BUILD_GROUP('build_source')
388     bld(
389         features       = 'cc',
390         source         = source,
391         target         = name,
392         asn1options    = options,
393         asn1directory  = directory
394     )
395 Build.BuildContext.SAMBA_ASN1 = SAMBA_ASN1
396
397
398
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',
404                       shell = False)
405
406 @extension('.et')
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)
412
413
414 #################################################################
415 # define a Samba ET target
416 def SAMBA_ERRTABLE(bld, name, source,
417                options='',
418                directory=''):
419     if not SET_TARGET_TYPE(bld, name, 'ET'):
420         return
421     bld.SET_BUILD_GROUP('build_source')
422     bld(
423         features = 'cc',
424         source   = source,
425         target   = name
426     )
427 Build.BuildContext.SAMBA_ERRTABLE = SAMBA_ERRTABLE
428
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'" % (
434             name, node.name))
435     return ret
436
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')
440
441 @extension('.idl')
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)
451
452
453     dname = os.path.dirname(node.bld_dir(self.env)) + "/gen_ndr"
454     c_node.outputdir = dname
455
456     self.create_task('idl', node, [c_node, h1_node, h2_node, s_node, cli_node, cli_h_node, py_node])
457
458     # reinject the c node to the list of nodes to process
459     self.allnodes.append(c_node)
460
461
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)
467
468     if not SET_TARGET_TYPE(bld, name, 'PIDL'):
469         return
470
471     bld.SET_BUILD_GROUP('build_source')
472     bld(
473         features = 'cc',
474         source   = source,
475         target   = name
476     )
477 Build.BuildContext.SAMBA_PIDL = SAMBA_PIDL
478
479
480
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
487
488
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')
494         bld(
495             source = source_list,
496             target = header,
497             rule = '../script/mkproto.pl --srcdir=.. --builddir=. --public=/dev/null --private=${TGT} ${SRC}'
498             )
499 Build.BuildContext.AUTOPROTO = AUTOPROTO
500
501
502 #################################################################
503 # define a Samba module.
504 def SAMBA_MODULE(bld, modname, source_list,
505                  deps='',
506                  include_list='.',
507                  subsystem=None,
508                  init_function=None,
509                  autoproto=None,
510                  aliases=None,
511                  cflags='',
512                  output_type=None):
513
514     if not SET_TARGET_TYPE(bld, modname, 'MODULE'):
515         return
516
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)
520         return
521
522     (sysdeps, localdeps, add_objects) = ADD_DEPENDENCIES(bld, modname, deps)
523
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')
527     bld(
528         features = 'cc',
529         source = source_list,
530         target=modname,
531         ccflags = CURRENT_CFLAGS(bld, cflags),
532         includes='. ' + bld.env['BUILD_DIRECTORY'] + '/default ' + ilist)
533 Build.BuildContext.SAMBA_MODULE = SAMBA_MODULE
534
535
536 #################################################################
537 # define a Samba subsystem
538 def SAMBA_SUBSYSTEM(bld, modname, source_list,
539                     deps='',
540                     public_deps='',
541                     include_list='.',
542                     public_headers=None,
543                     autoproto=None,
544                     cflags='',
545                     group='main',
546                     config_option=None,
547                     init_function_sentinal=None):
548
549     if not SET_TARGET_TYPE(bld, modname, 'SUBSYSTEM'):
550         return
551
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):
555             source_list = ''
556
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)
560         return
561
562     (sysdeps, localdeps, add_objects) = ADD_DEPENDENCIES(bld, modname, deps)
563
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)
567     bld(
568         features = 'cc',
569         source = source_list,
570         target=modname,
571         ccflags = CURRENT_CFLAGS(bld, cflags),
572         includes='. ' + bld.env['BUILD_DIRECTORY'] + '/default ' + ilist)
573 Build.BuildContext.SAMBA_SUBSYSTEM = SAMBA_SUBSYSTEM
574
575
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
584     cache[path] = True
585     debug("build: Processing subdirectory %s" % dir)
586     bld.add_subdirs(dir)
587
588 Build.BuildContext.BUILD_SUBDIR = BUILD_SUBDIR
589
590
591 ##########################################################
592 # add a new top level command to waf
593 def ADD_COMMAND(opt, name, function):
594     Utils.g_module.__dict__[name] = function
595     opt.name = function
596 Options.Handler.ADD_COMMAND = ADD_COMMAND
597
598 ###########################################################
599 # setup build groups used to ensure that the different build
600 # phases happen consecutively
601 @runonce
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
611
612
613 ###########################################################
614 # set the current build group
615 def SET_BUILD_GROUP(bld, group):
616     if not 'USING_BUILD_GROUPS' in bld.env:
617         return
618     bld.set_group(group)
619 Build.BuildContext.SET_BUILD_GROUP = SET_BUILD_GROUP
620