build: cope with subsystems with no enabled modules
[obnox/samba/samba-obnox.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, Options, Task, Utils, cc, TaskGen
5 from Configure import conf
6 from Logs import debug
7 from samba_utils import SUBST_VARS_RECURSIVE
8
9 # bring in the other samba modules
10 from samba_optimisation import *
11 from samba_utils import *
12 from samba_autoconf import *
13 from samba_patterns import *
14 from samba_pidl import *
15 from samba_errtable import *
16 from samba_asn1 import *
17 from samba_autoproto import *
18 from samba_python import *
19 from samba_deps import *
20
21 LIB_PATH="shared"
22
23
24
25 #################################################################
26 # create the samba build environment
27 @conf
28 def SAMBA_BUILD_ENV(conf):
29     conf.env['BUILD_DIRECTORY'] = conf.blddir
30     mkdir_p(os.path.join(conf.blddir, LIB_PATH))
31     mkdir_p(os.path.join(conf.blddir, 'python/samba/dcerpc'))
32     # this allows all of the bin/shared and bin/python targets
33     # to be expressed in terms of build directory paths
34     for p in ['python','shared']:
35         link_target = os.path.join(conf.blddir, 'default/' + p)
36         if not os.path.lexists(link_target):
37             os.symlink('../' + p, link_target)
38
39
40
41 ################################################################
42 # add an init_function to the list for a subsystem
43 def ADD_INIT_FUNCTION(bld, subsystem, target, init_function):
44     if init_function is None:
45         return
46     bld.ASSERT(subsystem is not None, "You must specify a subsystem for init_function '%s'" % init_function)
47     cache = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
48     if not subsystem in cache:
49         cache[subsystem] = []
50     cache[subsystem].append( { 'TARGET':target, 'INIT_FUNCTION':init_function } )
51 Build.BuildContext.ADD_INIT_FUNCTION = ADD_INIT_FUNCTION
52
53
54 #################################################################
55 # define a Samba library
56 def SAMBA_LIBRARY(bld, libname, source,
57                   deps='',
58                   public_deps='',
59                   includes='',
60                   public_headers=None,
61                   vnum=None,
62                   cflags='',
63                   external_library=False,
64                   realname=None,
65                   autoproto=None,
66                   group='main',
67                   depends_on='',
68                   local_include=True,
69                   install_path=None,
70                   install=True,
71                   enabled=True):
72
73     if not enabled:
74         SET_TARGET_TYPE(bld, libname, 'DISABLED')
75         return
76
77     # remember empty libraries, so we can strip the dependencies
78     if (source == '') or (source == []):
79         SET_TARGET_TYPE(bld, libname, 'EMPTY')
80         return
81
82     if not SET_TARGET_TYPE(bld, libname, 'LIBRARY'):
83         return
84
85     obj_target = libname + '.objlist'
86
87     # first create a target for building the object files for this library
88     # by separating in this way, we avoid recompiling the C files
89     # separately for the install library and the build library
90     bld.SAMBA_SUBSYSTEM(obj_target,
91                         source         = source,
92                         deps           = deps,
93                         public_deps    = public_deps,
94                         includes       = includes,
95                         public_headers = public_headers,
96                         cflags         = cflags,
97                         group          = group,
98                         autoproto      = autoproto,
99                         depends_on     = depends_on,
100                         local_include  = local_include)
101
102     # the library itself will depend on that object target
103     deps += ' ' + public_deps
104     deps = TO_LIST(deps)
105     deps.append(obj_target)
106
107     bld.SET_BUILD_GROUP(group)
108     t = bld(
109         features        = 'cc cshlib symlink_lib',
110         source          = [],
111         target          = libname,
112         samba_cflags    = CURRENT_CFLAGS(bld, libname, cflags),
113         depends_on      = depends_on,
114         samba_deps      = deps,
115         samba_includes  = includes,
116         local_include   = local_include,
117         vnum            = vnum,
118         install_path    = None
119         )
120
121     if install_path is None:
122         install_path = '${LIBDIR}'
123     install_path = SUBST_VARS_RECURSIVE(install_path, bld.env)
124
125     if install:
126         # create a separate install library, which may have
127         # different rpath settings
128         SET_TARGET_TYPE(bld, libname + '.inst', 'LIBRARY')
129         t = bld(
130             features        = 'cc cshlib',
131             source          = [],
132             target          = libname + '.inst',
133             samba_cflags    = CURRENT_CFLAGS(bld, libname, cflags),
134             depends_on      = depends_on,
135             samba_deps      = deps,
136             samba_includes  = includes,
137             local_include   = local_include,
138             vnum            = vnum,
139             install_as      = libname,
140             install_path    = None,
141             )
142         t.env['RPATH'] = install_rpath(bld)
143
144         if vnum:
145             vnum_base = vnum.split('.')[0]
146             install_name = 'lib%s.so.%s' % (libname, vnum)
147             install_link = 'lib%s.so.%s' % (libname, vnum_base)
148         else:
149             install_name = 'lib%s.so' % libname
150             install_link = None
151
152         bld.install_as(os.path.join(install_path, install_name),
153                        'lib%s.inst.so' % libname)
154         if install_link:
155             bld.symlink_as(os.path.join(install_path, install_link), install_name)
156
157
158     if autoproto is not None:
159         bld.SAMBA_AUTOPROTO(autoproto, source)
160
161 Build.BuildContext.SAMBA_LIBRARY = SAMBA_LIBRARY
162
163
164 #################################################################
165 # define a Samba binary
166 def SAMBA_BINARY(bld, binname, source,
167                  deps='',
168                  includes='',
169                  public_headers=None,
170                  modules=None,
171                  installdir=None,
172                  ldflags=None,
173                  cflags='',
174                  autoproto=None,
175                  use_hostcc=None,
176                  compiler=None,
177                  group='binaries',
178                  manpages=None,
179                  local_include=True,
180                  subsystem_name=None,
181                  needs_python=False,
182                  install=True,
183                  install_path=None):
184
185     if not SET_TARGET_TYPE(bld, binname, 'BINARY'):
186         return
187
188     features = 'cc cprogram'
189     if needs_python:
190         features += ' pyembed'
191
192     bld.SET_BUILD_GROUP(group)
193
194     obj_target = binname + '.objlist'
195
196     # first create a target for building the object files for this binary
197     # by separating in this way, we avoid recompiling the C files
198     # separately for the install binary and the build binary
199     bld.SAMBA_SUBSYSTEM(obj_target,
200                         source         = source,
201                         deps           = deps,
202                         includes       = includes,
203                         cflags         = cflags,
204                         group          = group,
205                         autoproto      = autoproto,
206                         subsystem_name = subsystem_name,
207                         needs_python   = needs_python,
208                         local_include  = local_include)
209
210     # the library itself will depend on that object target
211     deps = TO_LIST(deps)
212     deps.append(obj_target)
213
214     bld(
215         features       = features + ' symlink_bin',
216         source         = [],
217         target         = binname,
218         samba_cflags   = CURRENT_CFLAGS(bld, binname, cflags),
219         samba_deps     = deps,
220         samba_includes = includes,
221         local_include  = local_include,
222         samba_modules  = modules,
223         top            = True,
224         samba_subsystem= subsystem_name,
225         install_path   = None
226         )
227
228     if install_path is None:
229         install_path = '${BINDIR}'
230     install_path = SUBST_VARS_RECURSIVE(install_path, bld.env)
231
232     if install:
233         # we create a separate 'install' binary, which
234         # will have different rpath settings
235         SET_TARGET_TYPE(bld, binname + '.inst', 'BINARY')
236         t = bld(
237             features       = features,
238             source         = [],
239             target         = binname + '.inst',
240             samba_cflags   = CURRENT_CFLAGS(bld, binname, cflags),
241             samba_deps     = deps,
242             samba_includes = includes,
243             local_include  = local_include,
244             samba_modules  = modules,
245             top            = True,
246             samba_subsystem= subsystem_name,
247             install_path   = None
248             )
249         t.env['RPATH'] = install_rpath(bld)
250
251         bld.install_as(os.path.join(install_path, binname),
252                        binname + '.inst',
253                        chmod=0755)
254
255     # setup the subsystem_name as an alias for the real
256     # binary name, so it can be found when expanding
257     # subsystem dependencies
258     if subsystem_name is not None:
259         bld.TARGET_ALIAS(subsystem_name, binname)
260
261     if autoproto is not None:
262         bld.SAMBA_AUTOPROTO(autoproto, source)
263 Build.BuildContext.SAMBA_BINARY = SAMBA_BINARY
264
265
266 #################################################################
267 # define a Samba module.
268 def SAMBA_MODULE(bld, modname, source,
269                  deps='',
270                  includes='',
271                  subsystem=None,
272                  init_function=None,
273                  autoproto=None,
274                  autoproto_extra_source='',
275                  aliases=None,
276                  cflags='',
277                  internal_module=True,
278                  local_include=True,
279                  enabled=True):
280
281     # we add the init function regardless of whether the module
282     # is enabled or not, as we need to generate a null list if
283     # all disabled
284     bld.ADD_INIT_FUNCTION(subsystem, modname, init_function)
285
286     if internal_module:
287         # treat internal modules as subsystems for now
288         SAMBA_SUBSYSTEM(bld, modname, source,
289                         deps=deps,
290                         includes=includes,
291                         autoproto=autoproto,
292                         autoproto_extra_source=autoproto_extra_source,
293                         cflags=cflags,
294                         local_include=local_include,
295                         enabled=enabled)
296         return
297
298     if not enabled:
299         SET_TARGET_TYPE(bld, modname, 'DISABLED')
300         return
301
302     # remember empty modules, so we can strip the dependencies
303     if (source == '') or (source == []):
304         SET_TARGET_TYPE(bld, modname, 'EMPTY')
305         return
306
307     if not SET_TARGET_TYPE(bld, modname, 'MODULE'):
308         return
309
310     if subsystem is not None:
311         deps += ' ' + subsystem
312
313     bld.SET_BUILD_GROUP('main')
314     bld(
315         features       = 'cc',
316         source         = source,
317         target         = modname,
318         samba_cflags   = CURRENT_CFLAGS(bld, modname, cflags),
319         samba_includes = includes,
320         local_include  = local_include,
321         samba_deps     = TO_LIST(deps)
322         )
323
324     if autoproto is not None:
325         bld.SAMBA_AUTOPROTO(autoproto, source + ' ' + autoproto_extra_source)
326
327 Build.BuildContext.SAMBA_MODULE = SAMBA_MODULE
328
329
330 #################################################################
331 # define a Samba subsystem
332 def SAMBA_SUBSYSTEM(bld, modname, source,
333                     deps='',
334                     public_deps='',
335                     includes='',
336                     public_headers=None,
337                     cflags='',
338                     cflags_end=None,
339                     group='main',
340                     init_function_sentinal=None,
341                     heimdal_autoproto=None,
342                     heimdal_autoproto_options=None,
343                     heimdal_autoproto_private=None,
344                     autoproto=None,
345                     autoproto_extra_source='',
346                     depends_on='',
347                     local_include=True,
348                     local_include_first=True,
349                     subsystem_name=None,
350                     enabled=True,
351                     needs_python=False):
352
353     if not enabled:
354         SET_TARGET_TYPE(bld, modname, 'DISABLED')
355         return
356
357     # remember empty subsystems, so we can strip the dependencies
358     if (source == '') or (source == []):
359         SET_TARGET_TYPE(bld, modname, 'EMPTY')
360         return
361
362     if not SET_TARGET_TYPE(bld, modname, 'SUBSYSTEM'):
363         return
364
365     deps += ' ' + public_deps
366
367     bld.SET_BUILD_GROUP(group)
368
369     features = 'cc'
370     if needs_python:
371         features += ' pyext'
372
373     t = bld(
374         features       = features,
375         source         = source,
376         target         = modname,
377         samba_cflags   = CURRENT_CFLAGS(bld, modname, cflags),
378         depends_on     = depends_on,
379         samba_deps     = TO_LIST(deps),
380         samba_includes = includes,
381         local_include  = local_include,
382         local_include_first  = local_include_first,
383         samba_subsystem= subsystem_name
384         )
385
386     if cflags_end is not None:
387         t.samba_cflags.extend(TO_LIST(cflags_end))
388
389     if heimdal_autoproto is not None:
390         bld.HEIMDAL_AUTOPROTO(heimdal_autoproto, source, options=heimdal_autoproto_options)
391     if heimdal_autoproto_private is not None:
392         bld.HEIMDAL_AUTOPROTO_PRIVATE(heimdal_autoproto_private, source)
393     if autoproto is not None:
394         bld.SAMBA_AUTOPROTO(autoproto, source + ' ' + autoproto_extra_source)
395     return t
396
397 Build.BuildContext.SAMBA_SUBSYSTEM = SAMBA_SUBSYSTEM
398
399
400 def SAMBA_GENERATOR(bld, name, rule, source, target,
401                     group='build_source', enabled=True):
402     '''A generic source generator target'''
403
404     if not SET_TARGET_TYPE(bld, name, 'GENERATOR'):
405         return
406
407     if not enabled:
408         return False
409
410     bld.SET_BUILD_GROUP(group)
411     bld(
412         rule=rule,
413         source=source,
414         target=target,
415         before='cc',
416         ext_out='.c',
417         name=name)
418 Build.BuildContext.SAMBA_GENERATOR = SAMBA_GENERATOR
419
420
421
422 ###############################################################
423 # add a new set of build rules from a subdirectory
424 # the @runonce decorator ensures we don't end up
425 # with duplicate rules
426 def BUILD_SUBDIR(bld, dir):
427     path = os.path.normpath(bld.curdir + '/' + dir)
428     cache = LOCAL_CACHE(bld, 'SUBDIR_LIST')
429     if path in cache: return
430     cache[path] = True
431     debug("build: Processing subdirectory %s" % dir)
432     bld.add_subdirs(dir)
433
434 Build.BuildContext.BUILD_SUBDIR = BUILD_SUBDIR
435
436
437 ##########################################################
438 # add a new top level command to waf
439 def ADD_COMMAND(opt, name, function):
440     Utils.g_module.__dict__[name] = function
441     opt.name = function
442 Options.Handler.ADD_COMMAND = ADD_COMMAND
443
444 ###########################################################
445 # setup build groups used to ensure that the different build
446 # phases happen consecutively
447 @runonce
448 def SETUP_BUILD_GROUPS(bld):
449     bld.p_ln = bld.srcnode # we do want to see all targets!
450     bld.env['USING_BUILD_GROUPS'] = True
451     bld.add_group('setup')
452     bld.add_group('base_libraries')
453     bld.add_group('build_compilers')
454     bld.add_group('build_source')
455     bld.add_group('prototypes')
456     bld.add_group('main')
457     bld.add_group('binaries')
458     bld.add_group('final')
459 Build.BuildContext.SETUP_BUILD_GROUPS = SETUP_BUILD_GROUPS
460
461
462 ###########################################################
463 # set the current build group
464 def SET_BUILD_GROUP(bld, group):
465     if not 'USING_BUILD_GROUPS' in bld.env:
466         return
467     bld.set_group(group)
468 Build.BuildContext.SET_BUILD_GROUP = SET_BUILD_GROUP
469
470
471 def h_file(filename):
472     import stat
473     st = os.stat(filename)
474     if stat.S_ISDIR(st[stat.ST_MODE]): raise IOError('not a file')
475     m = Utils.md5()
476     m.update(str(st.st_mtime))
477     m.update(str(st.st_size))
478     m.update(filename)
479     return m.digest()
480
481 @conf
482 def ENABLE_TIMESTAMP_DEPENDENCIES(conf):
483     Utils.h_file = h_file
484
485
486 ##############################
487 # handle the creation of links for libraries and binaries
488 # note that we use a relative symlink path to allow the whole tree
489 # to me moved/copied elsewhere without breaking the links
490 t = Task.simple_task_type('symlink_lib', 'ln -sf ${LINK_SOURCE} ${LINK_TARGET}',
491                           color='PINK', ext_in='.bin')
492 t.quiet = True
493
494 @feature('symlink_lib')
495 @after('apply_link')
496 def symlink_lib(self):
497     tsk = self.create_task('symlink_lib', self.link_task.outputs[0])
498
499     # calculat the link target and put it in the environment
500     soext=""
501     vnum = getattr(self, 'vnum', None)
502     if vnum is not None:
503         soext = '.' + vnum.split('.')[0]
504
505     link_target = getattr(self, 'link_name', '')
506     if link_target == '':
507         link_target = '%s/lib%s.so%s' % (LIB_PATH, self.sname, soext)
508
509
510     link_source = os_path_relpath(self.link_task.outputs[0].abspath(self.env),
511                                   os.path.join(self.env.BUILD_DIRECTORY, link_target))
512
513     tsk.env.LINK_TARGET = link_target
514     tsk.env.LINK_SOURCE = link_source[3:]
515     debug('task_gen: LINK for %s is %s -> %s',
516           self.name, tsk.env.LINK_SOURCE, tsk.env.LINK_TARGET)
517
518
519 t = Task.simple_task_type('symlink_bin', 'ln -sf ${SRC} ${BIN_TARGET}',
520                           color='PINK', ext_in='.bin')
521 t.quiet = True
522
523 @feature('symlink_bin')
524 @after('apply_link')
525 def symlink_bin(self):
526     if Options.is_install:
527         # we don't want to copy the install binary, as
528         # that has the install rpath, not the build rpath
529         # The rpath of the binaries in bin/default/foo/blah is different
530         # during the install phase, as distros insist on not using rpath in installed binaries
531         return
532     tsk = self.create_task('symlink_bin', self.link_task.outputs[0])
533
534     tsk.env.BIN_TARGET = self.target
535     debug('task_gen: BIN_TARGET for %s is %s', self.name, tsk.env.BIN_TARGET)
536
537
538
539
540 t = Task.simple_task_type('copy_script', 'ln -sf ${SRC[0].abspath(env)} ${LINK_TARGET}',
541                           color='PINK', ext_in='.bin', shell=True)
542 t.quiet = True
543
544 @feature('copy_script')
545 @before('apply_link')
546 def copy_script(self):
547     tsk = self.create_task('copy_script', self.allnodes[0])
548     tsk.env.TARGET = self.target
549
550 def SAMBA_SCRIPT(bld, name, pattern, installdir, installname=None):
551     '''used to copy scripts from the source tree into the build directory
552        for use by selftest'''
553
554     source = bld.path.ant_glob(pattern)
555
556     bld.SET_BUILD_GROUP('build_source')
557     for s in TO_LIST(source):
558         iname = s
559         if installname != None:
560             iname = installname
561         target = os.path.join(installdir, iname)
562         tgtdir = os.path.dirname(os.path.join(bld.srcnode.abspath(bld.env), '..', target))
563         mkdir_p(tgtdir)
564         t = bld(features='copy_script',
565                 source       = s,
566                 target       = target,
567                 always       = True,
568                 install_path = None)
569         t.env.LINK_TARGET = target
570
571 Build.BuildContext.SAMBA_SCRIPT = SAMBA_SCRIPT
572