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