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