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