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