build: fixed error message for incorrect waf version
[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, sys, 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 run ./configure and make as usual. That will
50 call the right version of waf.''')
51     sys.exit(1)
52
53
54 @conf
55 def SAMBA_BUILD_ENV(conf):
56     '''create the samba build environment'''
57     conf.env.BUILD_DIRECTORY = conf.blddir
58     mkdir_p(os.path.join(conf.blddir, LIB_PATH))
59     mkdir_p(os.path.join(conf.blddir, LIB_PATH, "private"))
60     mkdir_p(os.path.join(conf.blddir, "modules"))
61     mkdir_p(os.path.join(conf.blddir, 'python/samba/dcerpc'))
62     # this allows all of the bin/shared and bin/python targets
63     # to be expressed in terms of build directory paths
64     mkdir_p(os.path.join(conf.blddir, 'default'))
65     for p in ['python','shared', 'modules']:
66         link_target = os.path.join(conf.blddir, 'default/' + p)
67         if not os.path.lexists(link_target):
68             os.symlink('../' + p, link_target)
69
70     # get perl to put the blib files in the build directory
71     blib_bld = os.path.join(conf.blddir, 'default/pidl/blib')
72     blib_src = os.path.join(conf.srcdir, 'pidl/blib')
73     mkdir_p(blib_bld + '/man1')
74     mkdir_p(blib_bld + '/man3')
75     if os.path.islink(blib_src):
76         os.unlink(blib_src)
77     elif os.path.exists(blib_src):
78         shutil.rmtree(blib_src)
79
80
81 def ADD_INIT_FUNCTION(bld, subsystem, target, init_function):
82     '''add an init_function to the list for a subsystem'''
83     if init_function is None:
84         return
85     bld.ASSERT(subsystem is not None, "You must specify a subsystem for init_function '%s'" % init_function)
86     cache = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
87     if not subsystem in cache:
88         cache[subsystem] = []
89     cache[subsystem].append( { 'TARGET':target, 'INIT_FUNCTION':init_function } )
90 Build.BuildContext.ADD_INIT_FUNCTION = ADD_INIT_FUNCTION
91
92
93
94 #################################################################
95 def SAMBA_LIBRARY(bld, libname, source,
96                   deps='',
97                   public_deps='',
98                   includes='',
99                   public_headers=None,
100                   header_path=None,
101                   pc_files=None,
102                   vnum=None,
103                   soname=None,
104                   cflags='',
105                   ldflags='',
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_directory=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     ldflags = TO_LIST(ldflags)
192
193     features = 'cc cshlib symlink_lib install_lib'
194     if target_type == 'PYTHON':
195         features += ' pyext'
196     if pyext or pyembed:
197         # this is quite strange. we should add pyext feature for pyext
198         # but that breaks the build. This may be a bug in the waf python tool
199         features += ' pyembed'
200
201     if abi_directory:
202         features += ' abi_check'
203
204     vscript = None
205     if bld.env.HAVE_LD_VERSION_SCRIPT:
206         if private_library:
207             version = "%s_%s" % (Utils.g_module.APPNAME, Utils.g_module.VERSION)
208         elif vnum:
209             version = "%s_%s" % (libname, vnum)
210         else:
211             version = None
212         if version:
213             vscript = "%s.vscript" % libname
214             bld.ABI_VSCRIPT(libname, abi_directory, version, vscript,
215                             abi_match)
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 def copy_and_fix_python_path(task):
624     pattern='sys.path.insert(0, "bin/python")'
625     if task.env["PYTHONARCHDIR"] in sys.path and task.env["PYTHONDIR"] in sys.path:
626         replacement = ""
627     elif task.env["PYTHONARCHDIR"] == task.env["PYTHONDIR"]:
628         replacement="""sys.path.insert(0, "%s")""" % task.env["PYTHONDIR"]
629     else:
630         replacement="""sys.path.insert(0, "%s")
631 sys.path.insert(1, "%s")""" % (task.env["PYTHONARCHDIR"], task.env["PYTHONDIR"])
632
633     installed_location=task.outputs[0].bldpath(task.env)
634     source_file = open(task.inputs[0].srcpath(task.env))
635     installed_file = open(installed_location, 'w')
636     for line in source_file:
637         newline = line
638         if pattern in line:
639             newline = line.replace(pattern, replacement)
640         installed_file.write(newline)
641     installed_file.close()
642     os.chmod(installed_location, 0755)
643     return 0
644
645
646 def install_file(bld, destdir, file, chmod=MODE_644, flat=False,
647                  python_fixup=False, destname=None, base_name=None):
648     '''install a file'''
649     destdir = bld.EXPAND_VARIABLES(destdir)
650     if not destname:
651         destname = file
652         if flat:
653             destname = os.path.basename(destname)
654     dest = os.path.join(destdir, destname)
655     if python_fixup:
656         # fixup the python path it will use to find Samba modules
657         inst_file = file + '.inst'
658         bld.SAMBA_GENERATOR('python_%s' % destname,
659                             rule=copy_and_fix_python_path,
660                             source=file,
661                             target=inst_file)
662         file = inst_file
663     if base_name:
664         file = os.path.join(base_name, file)
665     bld.install_as(dest, file, chmod=chmod)
666
667
668 def INSTALL_FILES(bld, destdir, files, chmod=MODE_644, flat=False,
669                   python_fixup=False, destname=None, base_name=None):
670     '''install a set of files'''
671     for f in TO_LIST(files):
672         install_file(bld, destdir, f, chmod=chmod, flat=flat,
673                      python_fixup=python_fixup, destname=destname,
674                      base_name=base_name)
675 Build.BuildContext.INSTALL_FILES = INSTALL_FILES
676
677
678 def INSTALL_WILDCARD(bld, destdir, pattern, chmod=MODE_644, flat=False,
679                      python_fixup=False, exclude=None, trim_path=None):
680     '''install a set of files matching a wildcard pattern'''
681     files=TO_LIST(bld.path.ant_glob(pattern))
682     if trim_path:
683         files2 = []
684         for f in files:
685             files2.append(os_path_relpath(f, trim_path))
686         files = files2
687
688     if exclude:
689         for f in files[:]:
690             if fnmatch.fnmatch(f, exclude):
691                 files.remove(f)
692     INSTALL_FILES(bld, destdir, files, chmod=chmod, flat=flat,
693                   python_fixup=python_fixup, base_name=trim_path)
694 Build.BuildContext.INSTALL_WILDCARD = INSTALL_WILDCARD
695
696
697 def INSTALL_DIRS(bld, destdir, dirs):
698     '''install a set of directories'''
699     destdir = bld.EXPAND_VARIABLES(destdir)
700     dirs = bld.EXPAND_VARIABLES(dirs)
701     for d in TO_LIST(dirs):
702         bld.install_dir(os.path.join(destdir, d))
703 Build.BuildContext.INSTALL_DIRS = INSTALL_DIRS
704
705
706 re_header = re.compile('#include[ \t]*"([^"]+)"', re.I | re.M)
707 class header_task(Task.Task):
708     """
709     The public headers (the one installed on the system) have both
710     different paths and contents, so the rename is not enough.
711
712     Intermediate .inst.h files are created because path manipulation
713     may be slow. The substitution is thus performed only once.
714     """
715
716     name = 'header'
717     color = 'PINK'
718     vars = ['INCLUDEDIR', 'HEADER_DEPS']
719
720     def run(self):
721         txt = self.inputs[0].read(self.env)
722
723         # hard-coded string, but only present in samba4 (I promise, you won't feel a thing)
724         txt = txt.replace('#if _SAMBA_BUILD_ == 4', '#if 1\n')
725
726         # use a regexp to substitute the #include lines in the files
727         map = self.generator.bld.hnodemap
728         dirnodes = self.generator.bld.hnodedirs
729         def repl(m):
730             if m.group(1):
731                 s = m.group(1)
732
733                 # pokemon headers: gotta catch'em all!
734                 fin = s
735                 if s.startswith('bin/default'):
736                     node = self.generator.bld.srcnode.find_resource(s.replace('bin/default/', ''))
737                     if not node:
738                         Logs.warn('could not find the public header for %r' % s)
739                     elif node.id in map:
740                         fin = map[node.id]
741                     else:
742                         Logs.warn('could not find the public header replacement for build header %r' % s)
743                 else:
744                     # this part is more difficult since the path may be relative to anything
745                     for dirnode in dirnodes:
746                         node = dirnode.find_resource(s)
747                         if node:
748                              if node.id in map:
749                                  fin = map[node.id]
750                                  break
751                              else:
752                                  Logs.warn('could not find the public header replacement for source header %r %r' % (s, node))
753                     else:
754                         Logs.warn('-> could not find the public header for %r' % s)
755
756                 return "#include <%s>" % fin
757             return ''
758
759         txt = re_header.sub(repl, txt)
760
761         # and write the output file
762         f = None
763         try:
764             f = open(self.outputs[0].abspath(self.env), 'w')
765             f.write(txt)
766         finally:
767             if f:
768                 f.close()
769
770 @TaskGen.feature('pubh')
771 def make_public_headers(self):
772     """
773     collect the public headers to process and to install, then
774     create the substitutions (name and contents)
775     """
776
777     if not self.bld.is_install:
778         # install time only (lazy)
779         return
780
781     # keep two variables
782     #    hnodedirs: list of folders for searching the headers
783     #    hnodemap: node ids and replacement string (node objects are unique)
784     try:
785         self.bld.hnodedirs.append(self.path)
786     except AttributeError:
787         self.bld.hnodemap = {}
788         self.bld.hnodedirs = [self.bld.srcnode, self.path]
789
790         for k in 'source4 source4/include lib/talloc lib/tevent/ source4/lib/ldb/include/'.split():
791             node = self.bld.srcnode.find_dir(k)
792             if node:
793                 self.bld.hnodedirs.append(node)
794
795     header_path = getattr(self, 'header_path', None) or ''
796
797     for x in self.to_list(self.headers):
798
799         # too complicated, but what was the original idea?
800         if isinstance(header_path, list):
801             add_dir = ''
802             for (p1, dir) in header_path:
803                 lst = self.to_list(p1)
804                 for p2 in lst:
805                     if fnmatch.fnmatch(x, p2):
806                         add_dir = dir
807                         break
808                 else:
809                     continue
810                 break
811             inst_path = add_dir
812         else:
813             inst_path = header_path
814
815         dest = ''
816         name = x
817         if x.find(':') != -1:
818             s = x.split(':')
819             name = s[0]
820             dest = s[1]
821
822         inn = self.path.find_resource(name)
823
824         if not inn:
825             raise ValueError("could not find the public header %r in %r" % (name, self.path))
826         out = inn.change_ext('.inst.h')
827         self.create_task('header', inn, out)
828
829         if not dest:
830             dest = inn.name
831
832         if inst_path:
833             inst_path = inst_path + '/'
834         inst_path = inst_path + dest
835
836         self.bld.install_as('${INCLUDEDIR}/%s' % inst_path, out, self.env)
837
838         self.bld.hnodemap[inn.id] = inst_path
839
840     # create a hash (not md5) to make sure the headers are re-created if something changes
841     val = 0
842     lst = list(self.bld.hnodemap.keys())
843     lst.sort()
844     for k in lst:
845         val = hash((val, k, self.bld.hnodemap[k]))
846     self.bld.env.HEADER_DEPS = val
847
848 def PUBLIC_HEADERS(bld, public_headers, header_path=None):
849     '''install some headers
850
851     header_path may either be a string that is added to the INCLUDEDIR,
852     or it can be a dictionary of wildcard patterns which map to destination
853     directories relative to INCLUDEDIR
854     '''
855     bld.SET_BUILD_GROUP('final')
856     ret = bld(features=['pubh'], headers=public_headers, header_path=header_path)
857     return ret
858 Build.BuildContext.PUBLIC_HEADERS = PUBLIC_HEADERS
859
860
861 def MANPAGES(bld, manpages):
862     '''build and install manual pages'''
863     bld.env.MAN_XSL = 'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl'
864     for m in manpages.split():
865         source = m + '.xml'
866         bld.SAMBA_GENERATOR(m,
867                             source=source,
868                             target=m,
869                             group='final',
870                             rule='${XSLTPROC} -o ${TGT} --nonet ${MAN_XSL} ${SRC}'
871                             )
872         bld.INSTALL_FILES('${MANDIR}/man%s' % m[-1], m, flat=True)
873 Build.BuildContext.MANPAGES = MANPAGES
874
875
876 #############################################################
877 # give a nicer display when building different types of files
878 def progress_display(self, msg, fname):
879     col1 = Logs.colors(self.color)
880     col2 = Logs.colors.NORMAL
881     total = self.position[1]
882     n = len(str(total))
883     fs = '[%%%dd/%%%dd] %s %%s%%s%%s\n' % (n, n, msg)
884     return fs % (self.position[0], self.position[1], col1, fname, col2)
885
886 def link_display(self):
887     if Options.options.progress_bar != 0:
888         return Task.Task.old_display(self)
889     fname = self.outputs[0].bldpath(self.env)
890     return progress_display(self, 'Linking', fname)
891 Task.TaskBase.classes['cc_link'].display = link_display
892
893 def samba_display(self):
894     if Options.options.progress_bar != 0:
895         return Task.Task.old_display(self)
896
897     targets    = LOCAL_CACHE(self, 'TARGET_TYPE')
898     if self.name in targets:
899         target_type = targets[self.name]
900         type_map = { 'GENERATOR' : 'Generating',
901                      'PROTOTYPE' : 'Generating'
902                      }
903         if target_type in type_map:
904             return progress_display(self, type_map[target_type], self.name)
905
906     if len(self.inputs) == 0:
907         return Task.Task.old_display(self)
908
909     fname = self.inputs[0].bldpath(self.env)
910     if fname[0:3] == '../':
911         fname = fname[3:]
912     ext_loc = fname.rfind('.')
913     if ext_loc == -1:
914         return Task.Task.old_display(self)
915     ext = fname[ext_loc:]
916
917     ext_map = { '.idl' : 'Compiling IDL',
918                 '.et'  : 'Compiling ERRTABLE',
919                 '.asn1': 'Compiling ASN1',
920                 '.c'   : 'Compiling' }
921     if ext in ext_map:
922         return progress_display(self, ext_map[ext], fname)
923     return Task.Task.old_display(self)
924
925 Task.TaskBase.classes['Task'].old_display = Task.TaskBase.classes['Task'].display
926 Task.TaskBase.classes['Task'].display = samba_display
927
928
929 @after('apply_link')
930 @feature('cshlib')
931 def apply_bundle_remove_dynamiclib_patch(self):
932     if self.env['MACBUNDLE'] or getattr(self,'mac_bundle',False):
933         if not getattr(self,'vnum',None):
934             try:
935                 self.env['LINKFLAGS'].remove('-dynamiclib')
936                 self.env['LINKFLAGS'].remove('-single_module')
937             except ValueError:
938                 pass