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