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