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