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