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