wafsamba: change the default value for SAMBA_MODULE of pyembed to False
[bbaumbach/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, re, shutil, Logs, Constants
5 from Configure import conf
6 from Logs import debug
7 from samba_utils import SUBST_VARS_RECURSIVE
8 TaskGen.task_gen.apply_verif = Utils.nada
9
10 # bring in the other samba modules
11 from samba_optimisation import *
12 from samba_utils import *
13 from samba_version import *
14 from samba_autoconf import *
15 from samba_patterns import *
16 from samba_pidl import *
17 from samba_autoproto import *
18 from samba_python import *
19 from samba_deps import *
20 from samba_bundled import *
21 import samba_install
22 import samba_conftests
23 import samba_abi
24 import tru64cc
25 import irixcc
26 import hpuxcc
27 import generic_cc
28 import samba_dist
29 import samba_wildcard
30 import stale_files
31 import symbols
32 import pkgconfig
33
34 # some systems have broken threading in python
35 if os.environ.get('WAF_NOTHREADS') == '1':
36     import nothreads
37
38 LIB_PATH="shared"
39
40 os.putenv('PYTHONUNBUFFERED', '1')
41
42
43 if Constants.HEXVERSION < 0x105019:
44     Logs.error('''
45 Please use the version of waf that comes with Samba, not
46 a system installed version. See http://wiki.samba.org/index.php/Waf
47 for details.
48
49 Alternatively, please use ./autogen-waf.sh, and then
50 run ./configure and make as usual. That will call the right version of waf.
51 ''')
52     sys.exit(1)
53
54
55 @conf
56 def SAMBA_BUILD_ENV(conf):
57     '''create the samba build environment'''
58     conf.env.BUILD_DIRECTORY = conf.blddir
59     mkdir_p(os.path.join(conf.blddir, LIB_PATH))
60     mkdir_p(os.path.join(conf.blddir, LIB_PATH, "private"))
61     mkdir_p(os.path.join(conf.blddir, "modules"))
62     mkdir_p(os.path.join(conf.blddir, 'python/samba/dcerpc'))
63     # this allows all of the bin/shared and bin/python targets
64     # to be expressed in terms of build directory paths
65     mkdir_p(os.path.join(conf.blddir, 'default'))
66     for p in ['python','shared', 'modules']:
67         link_target = os.path.join(conf.blddir, 'default/' + p)
68         if not os.path.lexists(link_target):
69             os.symlink('../' + p, link_target)
70
71     # get perl to put the blib files in the build directory
72     blib_bld = os.path.join(conf.blddir, 'default/pidl/blib')
73     blib_src = os.path.join(conf.srcdir, 'pidl/blib')
74     mkdir_p(blib_bld + '/man1')
75     mkdir_p(blib_bld + '/man3')
76     if os.path.islink(blib_src):
77         os.unlink(blib_src)
78     elif os.path.exists(blib_src):
79         shutil.rmtree(blib_src)
80
81
82 def ADD_INIT_FUNCTION(bld, subsystem, target, init_function):
83     '''add an init_function to the list for a subsystem'''
84     if init_function is None:
85         return
86     bld.ASSERT(subsystem is not None, "You must specify a subsystem for init_function '%s'" % init_function)
87     cache = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
88     if not subsystem in cache:
89         cache[subsystem] = []
90     cache[subsystem].append( { 'TARGET':target, 'INIT_FUNCTION':init_function } )
91 Build.BuildContext.ADD_INIT_FUNCTION = ADD_INIT_FUNCTION
92
93
94
95 #################################################################
96 def SAMBA_LIBRARY(bld, libname, source,
97                   deps='',
98                   public_deps='',
99                   includes='',
100                   public_headers=None,
101                   header_path=None,
102                   pc_files=None,
103                   vnum=None,
104                   soname=None,
105                   cflags='',
106                   ldflags='',
107                   external_library=False,
108                   realname=None,
109                   autoproto=None,
110                   group='libraries',
111                   depends_on='',
112                   local_include=True,
113                   vars=None,
114                   install_path=None,
115                   install=True,
116                   pyembed=False,
117                   pyext=False,
118                   target_type='LIBRARY',
119                   bundled_extension=True,
120                   link_name=None,
121                   abi_directory=None,
122                   abi_match=None,
123                   hide_symbols=False,
124                   manpages=None,
125                   private_library=False,
126                   grouping_library=False,
127                   enabled=True):
128     '''define a Samba library'''
129
130     if not enabled:
131         SET_TARGET_TYPE(bld, libname, 'DISABLED')
132         return
133
134     source = bld.EXPAND_VARIABLES(source, vars=vars)
135
136     # remember empty libraries, so we can strip the dependencies
137     if ((source == '') or (source == [])) and deps == '' and public_deps == '':
138         SET_TARGET_TYPE(bld, libname, 'EMPTY')
139         return
140
141     if BUILTIN_LIBRARY(bld, libname):
142         obj_target = libname
143     else:
144         obj_target = libname + '.objlist'
145
146     if group == 'libraries':
147         subsystem_group = 'main'
148     else:
149         subsystem_group = group
150
151     # first create a target for building the object files for this library
152     # by separating in this way, we avoid recompiling the C files
153     # separately for the install library and the build library
154     bld.SAMBA_SUBSYSTEM(obj_target,
155                         source         = source,
156                         deps           = deps,
157                         public_deps    = public_deps,
158                         includes       = includes,
159                         public_headers = public_headers,
160                         header_path    = header_path,
161                         cflags         = cflags,
162                         group          = subsystem_group,
163                         autoproto      = autoproto,
164                         depends_on     = depends_on,
165                         hide_symbols   = hide_symbols,
166                         pyext          = pyext or (target_type == "PYTHON"),
167                         local_include  = local_include)
168
169     if BUILTIN_LIBRARY(bld, libname):
170         return
171
172     if not SET_TARGET_TYPE(bld, libname, target_type):
173         return
174
175     # the library itself will depend on that object target
176     deps += ' ' + public_deps
177     deps = TO_LIST(deps)
178     deps.append(obj_target)
179
180     realname = bld.map_shlib_extension(realname, python=(target_type=='PYTHON'))
181     link_name = bld.map_shlib_extension(link_name, python=(target_type=='PYTHON'))
182
183     # we don't want any public libraries without version numbers
184     if not private_library and vnum is None and soname is None and target_type != 'PYTHON' and not realname:
185         raise Utils.WafError("public library '%s' must have a vnum" % libname)
186
187     if target_type == 'PYTHON' or realname or not private_library:
188         bundled_name = libname.replace('_', '-')
189     else:
190         bundled_name = PRIVATE_NAME(bld, libname, bundled_extension, private_library)
191
192     ldflags = TO_LIST(ldflags)
193
194     features = 'cc cshlib symlink_lib install_lib'
195     if target_type == 'PYTHON':
196         features += ' pyext'
197     if pyext or pyembed:
198         # this is quite strange. we should add pyext feature for pyext
199         # but that breaks the build. This may be a bug in the waf python tool
200         features += ' pyembed'
201
202     if abi_directory:
203         features += ' abi_check'
204
205     if bld.env.HAVE_LD_VERSION_SCRIPT:
206         vscript = "%s.vscript" % libname
207         if private_library:
208             version = "%s_%s" % (Utils.g_module.APPNAME, Utils.g_module.VERSION)
209         elif vnum:
210             version = "%s_%s" % (libname, vnum)
211         else:
212             version = None
213         if version:
214             bld.ABI_VSCRIPT(libname, abi_directory, version, vscript)
215             ldflags.append("-Wl,--version-script=%s/%s" % (bld.path.abspath(bld.env), vscript))
216             fullname = bld.env.shlib_PATTERN % bundled_name
217             bld.add_manual_dependency(bld.path.find_or_declare(fullname), bld.path.find_or_declare(vscript))
218             if Options.is_install:
219                 # also make the .inst file depend on the vscript
220                 instname = bld.env.shlib_PATTERN % (bundled_name + '.inst')
221                 bld.add_manual_dependency(bld.path.find_or_declare(instname), bld.path.find_or_declare(vscript))
222
223     bld.SET_BUILD_GROUP(group)
224     t = bld(
225         features        = features,
226         source          = [],
227         target          = bundled_name,
228         depends_on      = depends_on,
229         ldflags         = ldflags,
230         samba_deps      = deps,
231         samba_includes  = includes,
232         local_include   = local_include,
233         vnum            = vnum,
234         soname          = soname,
235         install_path    = None,
236         samba_inst_path = install_path,
237         name            = libname,
238         samba_realname  = realname,
239         samba_install   = install,
240         abi_directory   = "%s/%s" % (bld.path.abspath(), abi_directory),
241         abi_match       = abi_match,
242         private_library = private_library,
243         grouping_library=grouping_library
244         )
245
246     if realname and not link_name:
247         link_name = 'shared/%s' % realname
248
249     if link_name:
250         t.link_name = link_name
251
252     if pc_files is not None:
253         bld.PKG_CONFIG_FILES(pc_files, vnum=vnum)
254
255     if manpages is not None and 'XSLTPROC_MANPAGES' in bld.env and bld.env['XSLTPROC_MANPAGES']:
256         bld.MANPAGES(manpages)
257
258
259 Build.BuildContext.SAMBA_LIBRARY = SAMBA_LIBRARY
260
261
262 #################################################################
263 def SAMBA_BINARY(bld, binname, source,
264                  deps='',
265                  includes='',
266                  public_headers=None,
267                  header_path=None,
268                  modules=None,
269                  ldflags=None,
270                  cflags='',
271                  autoproto=None,
272                  use_hostcc=False,
273                  use_global_deps=True,
274                  compiler=None,
275                  group='binaries',
276                  manpages=None,
277                  local_include=True,
278                  subsystem_name=None,
279                  pyembed=False,
280                  vars=None,
281                  install=True,
282                  install_path=None,
283                  enabled=True):
284     '''define a Samba binary'''
285
286     if not enabled:
287         SET_TARGET_TYPE(bld, binname, 'DISABLED')
288         return
289
290     if not SET_TARGET_TYPE(bld, binname, 'BINARY'):
291         return
292
293     features = 'cc cprogram symlink_bin install_bin'
294     if pyembed:
295         features += ' pyembed'
296
297     obj_target = binname + '.objlist'
298
299     source = bld.EXPAND_VARIABLES(source, vars=vars)
300     source = unique_list(TO_LIST(source))
301
302     if group == 'binaries':
303         subsystem_group = 'main'
304     else:
305         subsystem_group = group
306
307     # first create a target for building the object files for this binary
308     # by separating in this way, we avoid recompiling the C files
309     # separately for the install binary and the build binary
310     bld.SAMBA_SUBSYSTEM(obj_target,
311                         source         = source,
312                         deps           = deps,
313                         includes       = includes,
314                         cflags         = cflags,
315                         group          = subsystem_group,
316                         autoproto      = autoproto,
317                         subsystem_name = subsystem_name,
318                         local_include  = local_include,
319                         use_hostcc     = use_hostcc,
320                         pyext          = pyembed,
321                         use_global_deps= use_global_deps)
322
323     bld.SET_BUILD_GROUP(group)
324
325     # the binary itself will depend on that object target
326     deps = TO_LIST(deps)
327     deps.append(obj_target)
328
329     t = bld(
330         features       = features,
331         source         = [],
332         target         = binname,
333         samba_deps     = deps,
334         samba_includes = includes,
335         local_include  = local_include,
336         samba_modules  = modules,
337         top            = True,
338         samba_subsystem= subsystem_name,
339         install_path   = None,
340         samba_inst_path= install_path,
341         samba_install  = install
342         )
343
344     if manpages is not None and 'XSLTPROC_MANPAGES' in bld.env and bld.env['XSLTPROC_MANPAGES']:
345         bld.MANPAGES(manpages)
346
347 Build.BuildContext.SAMBA_BINARY = SAMBA_BINARY
348
349
350 #################################################################
351 def SAMBA_MODULE(bld, modname, source,
352                  deps='',
353                  includes='',
354                  subsystem=None,
355                  init_function=None,
356                  module_init_name='samba_init_module',
357                  autoproto=None,
358                  autoproto_extra_source='',
359                  cflags='',
360                  internal_module=True,
361                  local_include=True,
362                  vars=None,
363                  enabled=True,
364                  pyembed=False,
365                  ):
366     '''define a Samba module.'''
367
368     source = bld.EXPAND_VARIABLES(source, vars=vars)
369
370     if internal_module or BUILTIN_LIBRARY(bld, modname):
371         bld.SAMBA_SUBSYSTEM(modname, source,
372                     deps=deps,
373                     includes=includes,
374                     autoproto=autoproto,
375                     autoproto_extra_source=autoproto_extra_source,
376                     cflags=cflags,
377                     local_include=local_include,
378                     enabled=enabled)
379
380         bld.ADD_INIT_FUNCTION(subsystem, modname, init_function)
381         return
382
383     if not enabled:
384         SET_TARGET_TYPE(bld, modname, 'DISABLED')
385         return
386
387     obj_target = modname + '.objlist'
388
389     realname = modname
390     if subsystem is not None:
391         deps += ' ' + subsystem
392         while realname.startswith("lib"+subsystem+"_"):
393             realname = realname[len("lib"+subsystem+"_"):]
394         while realname.startswith(subsystem+"_"):
395             realname = realname[len(subsystem+"_"):]
396
397     realname = bld.make_libname(realname)
398     while realname.startswith("lib"):
399         realname = realname[len("lib"):]
400
401     build_link_name = "modules/%s/%s" % (subsystem, realname)
402
403     if init_function:
404         cflags += " -D%s=%s" % (init_function, module_init_name)
405
406     bld.SAMBA_LIBRARY(modname,
407                       source,
408                       deps=deps,
409                       cflags=cflags,
410                       realname = realname,
411                       autoproto = autoproto,
412                       local_include=local_include,
413                       vars=vars,
414                       link_name=build_link_name,
415                       install_path="${MODULESDIR}/%s" % subsystem,
416                       pyembed=pyembed,
417                       )
418
419
420 Build.BuildContext.SAMBA_MODULE = SAMBA_MODULE
421
422
423 #################################################################
424 def SAMBA_SUBSYSTEM(bld, modname, source,
425                     deps='',
426                     public_deps='',
427                     includes='',
428                     public_headers=None,
429                     header_path=None,
430                     cflags='',
431                     cflags_end=None,
432                     group='main',
433                     init_function_sentinal=None,
434                     autoproto=None,
435                     autoproto_extra_source='',
436                     depends_on='',
437                     local_include=True,
438                     local_include_first=True,
439                     subsystem_name=None,
440                     enabled=True,
441                     use_hostcc=False,
442                     use_global_deps=True,
443                     vars=None,
444                     hide_symbols=False,
445                     pyext=False):
446     '''define a Samba subsystem'''
447
448     if not enabled:
449         SET_TARGET_TYPE(bld, modname, 'DISABLED')
450         return
451
452     # remember empty subsystems, so we can strip the dependencies
453     if ((source == '') or (source == [])) and deps == '' and public_deps == '':
454         SET_TARGET_TYPE(bld, modname, 'EMPTY')
455         return
456
457     if not SET_TARGET_TYPE(bld, modname, 'SUBSYSTEM'):
458         return
459
460     source = bld.EXPAND_VARIABLES(source, vars=vars)
461     source = unique_list(TO_LIST(source))
462
463     deps += ' ' + public_deps
464
465     bld.SET_BUILD_GROUP(group)
466
467     features = 'cc'
468     if pyext:
469         features += ' pyext'
470
471     t = bld(
472         features       = features,
473         source         = source,
474         target         = modname,
475         samba_cflags   = CURRENT_CFLAGS(bld, modname, cflags, hide_symbols=hide_symbols),
476         depends_on     = depends_on,
477         samba_deps     = TO_LIST(deps),
478         samba_includes = includes,
479         local_include  = local_include,
480         local_include_first  = local_include_first,
481         samba_subsystem= subsystem_name,
482         samba_use_hostcc = use_hostcc,
483         samba_use_global_deps = use_global_deps
484         )
485
486     if cflags_end is not None:
487         t.samba_cflags.extend(TO_LIST(cflags_end))
488
489     if autoproto is not None:
490         bld.SAMBA_AUTOPROTO(autoproto, source + TO_LIST(autoproto_extra_source))
491     if public_headers is not None:
492         bld.PUBLIC_HEADERS(public_headers, header_path=header_path)
493     return t
494
495
496 Build.BuildContext.SAMBA_SUBSYSTEM = SAMBA_SUBSYSTEM
497
498
499 def SAMBA_GENERATOR(bld, name, rule, source='', target='',
500                     group='generators', enabled=True,
501                     public_headers=None,
502                     header_path=None,
503                     vars=None,
504                     always=False):
505     '''A generic source generator target'''
506
507     if not SET_TARGET_TYPE(bld, name, 'GENERATOR'):
508         return
509
510     if not enabled:
511         return
512
513     bld.SET_BUILD_GROUP(group)
514     t = bld(
515         rule=rule,
516         source=bld.EXPAND_VARIABLES(source, vars=vars),
517         target=target,
518         shell=isinstance(rule, str),
519         on_results=True,
520         before='cc',
521         ext_out='.c',
522         samba_type='GENERATOR',
523         vars = [rule],
524         name=name)
525
526     if always:
527         t.always = True
528
529     if public_headers is not None:
530         bld.PUBLIC_HEADERS(public_headers, header_path=header_path)
531     return t
532 Build.BuildContext.SAMBA_GENERATOR = SAMBA_GENERATOR
533
534
535
536 @runonce
537 def SETUP_BUILD_GROUPS(bld):
538     '''setup build groups used to ensure that the different build
539     phases happen consecutively'''
540     bld.p_ln = bld.srcnode # we do want to see all targets!
541     bld.env['USING_BUILD_GROUPS'] = True
542     bld.add_group('setup')
543     bld.add_group('build_compiler_source')
544     bld.add_group('vscripts')
545     bld.add_group('base_libraries')
546     bld.add_group('generators')
547     bld.add_group('compiler_prototypes')
548     bld.add_group('compiler_libraries')
549     bld.add_group('build_compilers')
550     bld.add_group('build_source')
551     bld.add_group('prototypes')
552     bld.add_group('main')
553     bld.add_group('symbolcheck')
554     bld.add_group('libraries')
555     bld.add_group('binaries')
556     bld.add_group('syslibcheck')
557     bld.add_group('final')
558 Build.BuildContext.SETUP_BUILD_GROUPS = SETUP_BUILD_GROUPS
559
560
561 def SET_BUILD_GROUP(bld, group):
562     '''set the current build group'''
563     if not 'USING_BUILD_GROUPS' in bld.env:
564         return
565     bld.set_group(group)
566 Build.BuildContext.SET_BUILD_GROUP = SET_BUILD_GROUP
567
568
569
570 @conf
571 def ENABLE_TIMESTAMP_DEPENDENCIES(conf):
572     """use timestamps instead of file contents for deps
573     this currently doesn't work"""
574     def h_file(filename):
575         import stat
576         st = os.stat(filename)
577         if stat.S_ISDIR(st[stat.ST_MODE]): raise IOError('not a file')
578         m = Utils.md5()
579         m.update(str(st.st_mtime))
580         m.update(str(st.st_size))
581         m.update(filename)
582         return m.digest()
583     Utils.h_file = h_file
584
585
586
587 t = Task.simple_task_type('copy_script', 'rm -f "${LINK_TARGET}" && ln -s "${SRC[0].abspath(env)}" ${LINK_TARGET}',
588                           shell=True, color='PINK', ext_in='.bin')
589 t.quiet = True
590
591 @feature('copy_script')
592 @before('apply_link')
593 def copy_script(self):
594     tsk = self.create_task('copy_script', self.allnodes[0])
595     tsk.env.TARGET = self.target
596
597 def SAMBA_SCRIPT(bld, name, pattern, installdir, installname=None):
598     '''used to copy scripts from the source tree into the build directory
599        for use by selftest'''
600
601     source = bld.path.ant_glob(pattern)
602
603     bld.SET_BUILD_GROUP('build_source')
604     for s in TO_LIST(source):
605         iname = s
606         if installname != None:
607             iname = installname
608         target = os.path.join(installdir, iname)
609         tgtdir = os.path.dirname(os.path.join(bld.srcnode.abspath(bld.env), '..', target))
610         mkdir_p(tgtdir)
611         t = bld(features='copy_script',
612                 source       = s,
613                 target       = target,
614                 always       = True,
615                 install_path = None)
616         t.env.LINK_TARGET = target
617
618 Build.BuildContext.SAMBA_SCRIPT = SAMBA_SCRIPT
619
620
621 def install_file(bld, destdir, file, chmod=MODE_644, flat=False,
622                  python_fixup=False, destname=None, base_name=None):
623     '''install a file'''
624     destdir = bld.EXPAND_VARIABLES(destdir)
625     if not destname:
626         destname = file
627         if flat:
628             destname = os.path.basename(destname)
629     dest = os.path.join(destdir, destname)
630     if python_fixup:
631         # fixup the python path it will use to find Samba modules
632         inst_file = file + '.inst'
633         if bld.env["PYTHONDIR"] not in sys.path:
634             regex = "s|\(sys.path.insert.*\)bin/python\(.*\)$|\\1${PYTHONDIR}\\2|g"
635         else:
636             # Eliminate updating sys.path if the target python dir is already
637             # in python path.
638             regex = "s|sys.path.insert.*bin/python.*$||g"
639         bld.SAMBA_GENERATOR('python_%s' % destname,
640                             rule="sed '%s' < ${SRC} > ${TGT}" % regex,
641                             source=file,
642                             target=inst_file)
643         file = inst_file
644     if base_name:
645         file = os.path.join(base_name, file)
646     bld.install_as(dest, file, chmod=chmod)
647
648
649 def INSTALL_FILES(bld, destdir, files, chmod=MODE_644, flat=False,
650                   python_fixup=False, destname=None, base_name=None):
651     '''install a set of files'''
652     for f in TO_LIST(files):
653         install_file(bld, destdir, f, chmod=chmod, flat=flat,
654                      python_fixup=python_fixup, destname=destname,
655                      base_name=base_name)
656 Build.BuildContext.INSTALL_FILES = INSTALL_FILES
657
658
659 def INSTALL_WILDCARD(bld, destdir, pattern, chmod=MODE_644, flat=False,
660                      python_fixup=False, exclude=None, trim_path=None):
661     '''install a set of files matching a wildcard pattern'''
662     files=TO_LIST(bld.path.ant_glob(pattern))
663     if trim_path:
664         files2 = []
665         for f in files:
666             files2.append(os_path_relpath(f, trim_path))
667         files = files2
668
669     if exclude:
670         for f in files[:]:
671             if fnmatch.fnmatch(f, exclude):
672                 files.remove(f)
673     INSTALL_FILES(bld, destdir, files, chmod=chmod, flat=flat,
674                   python_fixup=python_fixup, base_name=trim_path)
675 Build.BuildContext.INSTALL_WILDCARD = INSTALL_WILDCARD
676
677
678 def INSTALL_DIRS(bld, destdir, dirs):
679     '''install a set of directories'''
680     destdir = bld.EXPAND_VARIABLES(destdir)
681     dirs = bld.EXPAND_VARIABLES(dirs)
682     for d in TO_LIST(dirs):
683         bld.install_dir(os.path.join(destdir, d))
684 Build.BuildContext.INSTALL_DIRS = INSTALL_DIRS
685
686
687 re_header = re.compile('#include[ \t]*"([^"]+)"', re.I | re.M)
688 class header_task(Task.Task):
689     """
690     The public headers (the one installed on the system) have both
691     different paths and contents, so the rename is not enough.
692
693     Intermediate .inst.h files are created because path manipulation
694     may be slow. The substitution is thus performed only once.
695     """
696
697     name = 'header'
698     color = 'PINK'
699     vars = ['INCLUDEDIR', 'HEADER_DEPS']
700
701     def run(self):
702         txt = self.inputs[0].read(self.env)
703
704         # hard-coded string, but only present in samba4 (I promise, you won't feel a thing)
705         txt = txt.replace('#if _SAMBA_BUILD_ == 4', '#if 1\n')
706
707         # use a regexp to substitute the #include lines in the files
708         map = self.generator.bld.hnodemap
709         dirnodes = self.generator.bld.hnodedirs
710         def repl(m):
711             if m.group(1):
712                 s = m.group(1)
713
714                 # pokemon headers: gotta catch'em all!
715                 fin = s
716                 if s.startswith('bin/default'):
717                     node = self.generator.bld.srcnode.find_resource(s.replace('bin/default/', ''))
718                     if not node:
719                         Logs.warn('could not find the public header for %r' % s)
720                     elif node.id in map:
721                         fin = map[node.id]
722                     else:
723                         Logs.warn('could not find the public header replacement for build header %r' % s)
724                 else:
725                     # this part is more difficult since the path may be relative to anything
726                     for dirnode in dirnodes:
727                         node = dirnode.find_resource(s)
728                         if node:
729                              if node.id in map:
730                                  fin = map[node.id]
731                                  break
732                              else:
733                                  Logs.warn('could not find the public header replacement for source header %r %r' % (s, node))
734                     else:
735                         Logs.warn('-> could not find the public header for %r' % s)
736
737                 return "#include <%s>" % fin
738             return ''
739
740         txt = re_header.sub(repl, txt)
741
742         # and write the output file
743         f = None
744         try:
745             f = open(self.outputs[0].abspath(self.env), 'w')
746             f.write(txt)
747         finally:
748             if f:
749                 f.close()
750
751 @TaskGen.feature('pubh')
752 def make_public_headers(self):
753     """
754     collect the public headers to process and to install, then
755     create the substitutions (name and contents)
756     """
757
758     if not self.bld.is_install:
759         # install time only (lazy)
760         return
761
762     # keep two variables
763     #    hnodedirs: list of folders for searching the headers
764     #    hnodemap: node ids and replacement string (node objects are unique)
765     try:
766         self.bld.hnodedirs.append(self.path)
767     except AttributeError:
768         self.bld.hnodemap = {}
769         self.bld.hnodedirs = [self.bld.srcnode, self.path]
770
771         for k in 'source4 source4/include lib/talloc lib/tevent/ source4/lib/ldb/include/'.split():
772             node = self.bld.srcnode.find_dir(k)
773             if node:
774                 self.bld.hnodedirs.append(node)
775
776     header_path = getattr(self, 'header_path', None) or ''
777
778     for x in self.to_list(self.headers):
779
780         # too complicated, but what was the original idea?
781         if isinstance(header_path, list):
782             add_dir = ''
783             for (p1, dir) in header_path:
784                 lst = self.to_list(p1)
785                 for p2 in lst:
786                     if fnmatch.fnmatch(x, p2):
787                         add_dir = dir
788                         break
789                 else:
790                     continue
791                 break
792             inst_path = add_dir
793         else:
794             inst_path = header_path
795
796         dest = ''
797         name = x
798         if x.find(':') != -1:
799             s = x.split(':')
800             name = s[0]
801             dest = s[1]
802
803         inn = self.path.find_resource(name)
804
805         if not inn:
806             raise ValueError("could not find the public header %r in %r" % (name, self.path))
807         out = inn.change_ext('.inst.h')
808         self.create_task('header', inn, out)
809
810         if not dest:
811             dest = inn.name
812
813         if inst_path:
814             inst_path = inst_path + '/'
815         inst_path = inst_path + dest
816
817         self.bld.install_as('${INCLUDEDIR}/%s' % inst_path, out, self.env)
818
819         self.bld.hnodemap[inn.id] = inst_path
820
821     # create a hash (not md5) to make sure the headers are re-created if something changes
822     val = 0
823     lst = list(self.bld.hnodemap.keys())
824     lst.sort()
825     for k in lst:
826         val = hash((val, k, self.bld.hnodemap[k]))
827     self.bld.env.HEADER_DEPS = val
828
829 def PUBLIC_HEADERS(bld, public_headers, header_path=None):
830     '''install some headers
831
832     header_path may either be a string that is added to the INCLUDEDIR,
833     or it can be a dictionary of wildcard patterns which map to destination
834     directories relative to INCLUDEDIR
835     '''
836     bld.SET_BUILD_GROUP('final')
837     ret = bld(features=['pubh'], headers=public_headers, header_path=header_path)
838     return ret
839 Build.BuildContext.PUBLIC_HEADERS = PUBLIC_HEADERS
840
841
842 def MANPAGES(bld, manpages):
843     '''build and install manual pages'''
844     bld.env.MAN_XSL = 'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl'
845     for m in manpages.split():
846         source = m + '.xml'
847         bld.SAMBA_GENERATOR(m,
848                             source=source,
849                             target=m,
850                             group='final',
851                             rule='${XSLTPROC} -o ${TGT} --nonet ${MAN_XSL} ${SRC}'
852                             )
853         bld.INSTALL_FILES('${MANDIR}/man%s' % m[-1], m, flat=True)
854 Build.BuildContext.MANPAGES = MANPAGES
855
856
857 #############################################################
858 # give a nicer display when building different types of files
859 def progress_display(self, msg, fname):
860     col1 = Logs.colors(self.color)
861     col2 = Logs.colors.NORMAL
862     total = self.position[1]
863     n = len(str(total))
864     fs = '[%%%dd/%%%dd] %s %%s%%s%%s\n' % (n, n, msg)
865     return fs % (self.position[0], self.position[1], col1, fname, col2)
866
867 def link_display(self):
868     if Options.options.progress_bar != 0:
869         return Task.Task.old_display(self)
870     fname = self.outputs[0].bldpath(self.env)
871     return progress_display(self, 'Linking', fname)
872 Task.TaskBase.classes['cc_link'].display = link_display
873
874 def samba_display(self):
875     if Options.options.progress_bar != 0:
876         return Task.Task.old_display(self)
877
878     targets    = LOCAL_CACHE(self, 'TARGET_TYPE')
879     if self.name in targets:
880         target_type = targets[self.name]
881         type_map = { 'GENERATOR' : 'Generating',
882                      'PROTOTYPE' : 'Generating'
883                      }
884         if target_type in type_map:
885             return progress_display(self, type_map[target_type], self.name)
886
887     if len(self.inputs) == 0:
888         return Task.Task.old_display(self)
889
890     fname = self.inputs[0].bldpath(self.env)
891     if fname[0:3] == '../':
892         fname = fname[3:]
893     ext_loc = fname.rfind('.')
894     if ext_loc == -1:
895         return Task.Task.old_display(self)
896     ext = fname[ext_loc:]
897
898     ext_map = { '.idl' : 'Compiling IDL',
899                 '.et'  : 'Compiling ERRTABLE',
900                 '.asn1': 'Compiling ASN1',
901                 '.c'   : 'Compiling' }
902     if ext in ext_map:
903         return progress_display(self, ext_map[ext], fname)
904     return Task.Task.old_display(self)
905
906 Task.TaskBase.classes['Task'].old_display = Task.TaskBase.classes['Task'].display
907 Task.TaskBase.classes['Task'].display = samba_display
908
909
910 @after('apply_link')
911 @feature('cshlib')
912 def apply_bundle_remove_dynamiclib_patch(self):
913     if self.env['MACBUNDLE'] or getattr(self,'mac_bundle',False):
914         if not getattr(self,'vnum',None):
915             try:
916                 self.env['LINKFLAGS'].remove('-dynamiclib')
917                 self.env['LINKFLAGS'].remove('-single_module')
918             except ValueError:
919                 pass