build: strip -single_module when doing bundle on mac OS X
[Samba/gbeck.git] / buildtools / wafsamba / wafsamba.py
blob35b39d365262392521a48500961f08154af97487
1 # a waf tool to add autoconf-like macros to the configure section
2 # and for SAMBA_ macros for building libraries, binaries etc
4 import Build, os, Options, Task, Utils, cc, TaskGen, fnmatch, re, shutil, Logs, Constants
5 from Configure import conf
6 from Logs import debug
7 from samba_utils import SUBST_VARS_RECURSIVE
8 TaskGen.task_gen.apply_verif = Utils.nada
10 # bring in the other samba modules
11 from samba_optimisation import *
12 from samba_utils import *
13 from samba_version import *
14 from samba_autoconf import *
15 from samba_patterns import *
16 from samba_pidl import *
17 from samba_autoproto import *
18 from samba_python import *
19 from samba_deps import *
20 from samba_bundled import *
21 import samba_install
22 import samba_conftests
23 import samba_abi
24 import tru64cc
25 import irixcc
26 import generic_cc
27 import samba_dist
28 import samba_wildcard
29 import stale_files
30 import symbols
32 # some systems have broken threading in python
33 if os.environ.get('WAF_NOTHREADS') == '1':
34 import nothreads
36 LIB_PATH="shared"
38 os.putenv('PYTHONUNBUFFERED', '1')
41 if Constants.HEXVERSION < 0x105019:
42 Logs.error('''
43 Please use the version of waf that comes with Samba, not
44 a system installed version. See http://wiki.samba.org/index.php/Waf
45 for details.
47 Alternatively, please use ./autogen-waf.sh, and then
48 run ./configure and make as usual. That will call the right version of waf.
49 ''')
50 sys.exit(1)
53 @conf
54 def SAMBA_BUILD_ENV(conf):
55 '''create the samba build environment'''
56 conf.env.BUILD_DIRECTORY = conf.blddir
57 mkdir_p(os.path.join(conf.blddir, LIB_PATH))
58 mkdir_p(os.path.join(conf.blddir, "modules"))
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', 'modules']:
64 link_target = os.path.join(conf.blddir, 'default/' + p)
65 if not os.path.lexists(link_target):
66 os.symlink('../' + p, link_target)
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)
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
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 soname=None,
102 cflags='',
103 external_library=False,
104 realname=None,
105 autoproto=None,
106 group='libraries',
107 depends_on='',
108 local_include=True,
109 vars=None,
110 install_path=None,
111 install=True,
112 pyembed=False,
113 pyext=False,
114 target_type='LIBRARY',
115 bundled_extension=True,
116 link_name=None,
117 abi_file=None,
118 abi_match=None,
119 hide_symbols=False,
120 manpages=None,
121 private_library=False,
122 grouping_library=False,
123 enabled=True):
124 '''define a Samba library'''
126 if not enabled:
127 SET_TARGET_TYPE(bld, libname, 'DISABLED')
128 return
130 source = bld.EXPAND_VARIABLES(source, vars=vars)
132 # remember empty libraries, so we can strip the dependencies
133 if ((source == '') or (source == [])) and deps == '' and public_deps == '':
134 SET_TARGET_TYPE(bld, libname, 'EMPTY')
135 return
137 if BUILTIN_LIBRARY(bld, libname):
138 obj_target = libname
139 else:
140 obj_target = libname + '.objlist'
142 if group == 'libraries':
143 subsystem_group = 'main'
144 else:
145 subsystem_group = group
147 # first create a target for building the object files for this library
148 # by separating in this way, we avoid recompiling the C files
149 # separately for the install library and the build library
150 bld.SAMBA_SUBSYSTEM(obj_target,
151 source = source,
152 deps = deps,
153 public_deps = public_deps,
154 includes = includes,
155 public_headers = public_headers,
156 header_path = header_path,
157 cflags = cflags,
158 group = subsystem_group,
159 autoproto = autoproto,
160 depends_on = depends_on,
161 hide_symbols = hide_symbols,
162 pyext = pyext or (target_type == "PYTHON"),
163 local_include = local_include)
165 if BUILTIN_LIBRARY(bld, libname):
166 return
168 if not SET_TARGET_TYPE(bld, libname, target_type):
169 return
171 # the library itself will depend on that object target
172 deps += ' ' + public_deps
173 deps = TO_LIST(deps)
174 deps.append(obj_target)
176 realname = bld.map_shlib_extension(realname, python=(target_type=='PYTHON'))
177 link_name = bld.map_shlib_extension(link_name, python=(target_type=='PYTHON'))
179 # we don't want any public libraries without version numbers
180 if not private_library and vnum is None and soname is None and target_type != 'PYTHON' and not realname:
181 raise Utils.WafError("public library '%s' must have a vnum" % libname)
183 if target_type == 'PYTHON' or realname or not private_library:
184 bundled_name = libname.replace('_', '-')
185 else:
186 bundled_name = PRIVATE_NAME(bld, libname, bundled_extension, private_library)
188 if private_library:
189 if vnum:
190 Logs.error("vnum is invalid for private libraries")
191 sys.exit(1)
192 vnum = Utils.g_module.VERSION
194 features = 'cc cshlib symlink_lib install_lib'
195 if target_type == 'PYTHON':
196 features += ' pyext'
197 if pyext or pyembed:
198 # this is quite strange. we should add pyext feature for pyext
199 # but that breaks the build. This may be a bug in the waf python tool
200 features += ' pyembed'
201 if abi_file:
202 features += ' abi_check'
204 if abi_file:
205 abi_file = os.path.join(bld.curdir, abi_file)
207 bld.SET_BUILD_GROUP(group)
208 t = bld(
209 features = features,
210 source = [],
211 target = bundled_name,
212 depends_on = depends_on,
213 samba_deps = deps,
214 samba_includes = includes,
215 local_include = local_include,
216 vnum = vnum,
217 soname = soname,
218 install_path = None,
219 samba_inst_path = install_path,
220 name = libname,
221 samba_realname = realname,
222 samba_install = install,
223 abi_file = abi_file,
224 abi_match = abi_match,
225 private_library = private_library,
226 grouping_library=grouping_library
229 if realname and not link_name:
230 link_name = 'shared/%s' % realname
232 if link_name:
233 t.link_name = link_name
235 if pc_files is not None:
236 bld.PKG_CONFIG_FILES(pc_files, vnum=vnum)
238 if manpages is not None and 'XSLTPROC_MANPAGES' in bld.env and bld.env['XSLTPROC_MANPAGES']:
239 bld.MANPAGES(manpages)
242 Build.BuildContext.SAMBA_LIBRARY = SAMBA_LIBRARY
245 #################################################################
246 def SAMBA_BINARY(bld, binname, source,
247 deps='',
248 includes='',
249 public_headers=None,
250 header_path=None,
251 modules=None,
252 ldflags=None,
253 cflags='',
254 autoproto=None,
255 use_hostcc=False,
256 use_global_deps=True,
257 compiler=None,
258 group='binaries',
259 manpages=None,
260 local_include=True,
261 subsystem_name=None,
262 pyembed=False,
263 vars=None,
264 install=True,
265 install_path=None,
266 enabled=True):
267 '''define a Samba binary'''
269 if not enabled:
270 SET_TARGET_TYPE(bld, binname, 'DISABLED')
271 return
273 if not SET_TARGET_TYPE(bld, binname, 'BINARY'):
274 return
276 features = 'cc cprogram symlink_bin install_bin'
277 if pyembed:
278 features += ' pyembed'
280 obj_target = binname + '.objlist'
282 source = bld.EXPAND_VARIABLES(source, vars=vars)
283 source = unique_list(TO_LIST(source))
285 if group == 'binaries':
286 subsystem_group = 'main'
287 else:
288 subsystem_group = group
290 # first create a target for building the object files for this binary
291 # by separating in this way, we avoid recompiling the C files
292 # separately for the install binary and the build binary
293 bld.SAMBA_SUBSYSTEM(obj_target,
294 source = source,
295 deps = deps,
296 includes = includes,
297 cflags = cflags,
298 group = subsystem_group,
299 autoproto = autoproto,
300 subsystem_name = subsystem_name,
301 local_include = local_include,
302 use_hostcc = use_hostcc,
303 pyext = pyembed,
304 use_global_deps= use_global_deps)
306 bld.SET_BUILD_GROUP(group)
308 # the binary itself will depend on that object target
309 deps = TO_LIST(deps)
310 deps.append(obj_target)
312 t = bld(
313 features = features,
314 source = [],
315 target = binname,
316 samba_deps = deps,
317 samba_includes = includes,
318 local_include = local_include,
319 samba_modules = modules,
320 top = True,
321 samba_subsystem= subsystem_name,
322 install_path = None,
323 samba_inst_path= install_path,
324 samba_install = install
327 if manpages is not None and 'XSLTPROC_MANPAGES' in bld.env and bld.env['XSLTPROC_MANPAGES']:
328 bld.MANPAGES(manpages)
330 Build.BuildContext.SAMBA_BINARY = SAMBA_BINARY
333 #################################################################
334 def SAMBA_MODULE(bld, modname, source,
335 deps='',
336 includes='',
337 subsystem=None,
338 init_function=None,
339 autoproto=None,
340 autoproto_extra_source='',
341 aliases=None,
342 cflags='',
343 internal_module=True,
344 local_include=True,
345 vars=None,
346 enabled=True,
347 pyembed=True,
349 '''define a Samba module.'''
351 source = bld.EXPAND_VARIABLES(source, vars=vars)
353 if internal_module or BUILTIN_LIBRARY(bld, modname):
354 bld.SAMBA_SUBSYSTEM(modname, source,
355 deps=deps,
356 includes=includes,
357 autoproto=autoproto,
358 autoproto_extra_source=autoproto_extra_source,
359 cflags=cflags,
360 local_include=local_include,
361 enabled=enabled)
363 bld.ADD_INIT_FUNCTION(subsystem, modname, init_function)
364 return
366 if not enabled:
367 SET_TARGET_TYPE(bld, modname, 'DISABLED')
368 return
370 if aliases is not None:
371 # if we have aliases, then create a private base library, and a set
372 # of modules on top of that library
373 if init_function:
374 cflags += " -D%s=samba_init_module" % init_function
376 basename = modname + '-base'
377 bld.SAMBA_LIBRARY(basename,
378 source,
379 deps=deps,
380 cflags=cflags,
381 autoproto = autoproto,
382 local_include=local_include,
383 vars=vars,
384 pyembed=pyembed,
385 private_library=True
388 aliases = TO_LIST(aliases)
389 aliases.append(modname)
391 for alias in aliases:
392 bld.SAMBA_MODULE(alias,
393 source=[],
394 internal_module=False,
395 subsystem=subsystem,
396 init_function=init_function,
397 deps=basename)
398 return
401 obj_target = modname + '.objlist'
403 realname = modname
404 if subsystem is not None:
405 deps += ' ' + subsystem
406 while realname.startswith("lib"+subsystem+"_"):
407 realname = realname[len("lib"+subsystem+"_"):]
408 while realname.startswith(subsystem+"_"):
409 realname = realname[len(subsystem+"_"):]
411 realname = bld.make_libname(realname)
412 while realname.startswith("lib"):
413 realname = realname[len("lib"):]
415 build_link_name = "modules/%s/%s" % (subsystem, realname)
417 if init_function:
418 cflags += " -D%s=samba_init_module" % init_function
420 bld.SAMBA_LIBRARY(modname,
421 source,
422 deps=deps,
423 cflags=cflags,
424 realname = realname,
425 autoproto = autoproto,
426 local_include=local_include,
427 vars=vars,
428 link_name=build_link_name,
429 install_path="${MODULESDIR}/%s" % subsystem,
430 pyembed=pyembed,
434 Build.BuildContext.SAMBA_MODULE = SAMBA_MODULE
437 #################################################################
438 def SAMBA_SUBSYSTEM(bld, modname, source,
439 deps='',
440 public_deps='',
441 includes='',
442 public_headers=None,
443 header_path=None,
444 cflags='',
445 cflags_end=None,
446 group='main',
447 init_function_sentinal=None,
448 autoproto=None,
449 autoproto_extra_source='',
450 depends_on='',
451 local_include=True,
452 local_include_first=True,
453 subsystem_name=None,
454 enabled=True,
455 use_hostcc=False,
456 use_global_deps=True,
457 vars=None,
458 hide_symbols=False,
459 pyext=False):
460 '''define a Samba subsystem'''
462 if not enabled:
463 SET_TARGET_TYPE(bld, modname, 'DISABLED')
464 return
466 # remember empty subsystems, so we can strip the dependencies
467 if ((source == '') or (source == [])) and deps == '' and public_deps == '':
468 SET_TARGET_TYPE(bld, modname, 'EMPTY')
469 return
471 if not SET_TARGET_TYPE(bld, modname, 'SUBSYSTEM'):
472 return
474 source = bld.EXPAND_VARIABLES(source, vars=vars)
475 source = unique_list(TO_LIST(source))
477 deps += ' ' + public_deps
479 bld.SET_BUILD_GROUP(group)
481 features = 'cc'
482 if pyext:
483 features += ' pyext'
485 t = bld(
486 features = features,
487 source = source,
488 target = modname,
489 samba_cflags = CURRENT_CFLAGS(bld, modname, cflags, hide_symbols=hide_symbols),
490 depends_on = depends_on,
491 samba_deps = TO_LIST(deps),
492 samba_includes = includes,
493 local_include = local_include,
494 local_include_first = local_include_first,
495 samba_subsystem= subsystem_name,
496 samba_use_hostcc = use_hostcc,
497 samba_use_global_deps = use_global_deps
500 if cflags_end is not None:
501 t.samba_cflags.extend(TO_LIST(cflags_end))
503 if autoproto is not None:
504 bld.SAMBA_AUTOPROTO(autoproto, source + TO_LIST(autoproto_extra_source))
505 if public_headers is not None:
506 bld.PUBLIC_HEADERS(public_headers, header_path=header_path)
507 return t
510 Build.BuildContext.SAMBA_SUBSYSTEM = SAMBA_SUBSYSTEM
513 def SAMBA_GENERATOR(bld, name, rule, source='', target='',
514 group='generators', enabled=True,
515 public_headers=None,
516 header_path=None,
517 vars=None,
518 always=False):
519 '''A generic source generator target'''
521 if not SET_TARGET_TYPE(bld, name, 'GENERATOR'):
522 return
524 if not enabled:
525 return
527 bld.SET_BUILD_GROUP(group)
528 t = bld(
529 rule=rule,
530 source=bld.EXPAND_VARIABLES(source, vars=vars),
531 target=target,
532 shell=isinstance(rule, str),
533 on_results=True,
534 before='cc',
535 ext_out='.c',
536 name=name)
538 if always:
539 t.always = True
541 if public_headers is not None:
542 bld.PUBLIC_HEADERS(public_headers, header_path=header_path)
543 return t
544 Build.BuildContext.SAMBA_GENERATOR = SAMBA_GENERATOR
548 @runonce
549 def SETUP_BUILD_GROUPS(bld):
550 '''setup build groups used to ensure that the different build
551 phases happen consecutively'''
552 bld.p_ln = bld.srcnode # we do want to see all targets!
553 bld.env['USING_BUILD_GROUPS'] = True
554 bld.add_group('setup')
555 bld.add_group('build_compiler_source')
556 bld.add_group('base_libraries')
557 bld.add_group('generators')
558 bld.add_group('compiler_prototypes')
559 bld.add_group('compiler_libraries')
560 bld.add_group('build_compilers')
561 bld.add_group('build_source')
562 bld.add_group('prototypes')
563 bld.add_group('main')
564 bld.add_group('symbolcheck')
565 bld.add_group('libraries')
566 bld.add_group('binaries')
567 bld.add_group('syslibcheck')
568 bld.add_group('final')
569 Build.BuildContext.SETUP_BUILD_GROUPS = SETUP_BUILD_GROUPS
572 def SET_BUILD_GROUP(bld, group):
573 '''set the current build group'''
574 if not 'USING_BUILD_GROUPS' in bld.env:
575 return
576 bld.set_group(group)
577 Build.BuildContext.SET_BUILD_GROUP = SET_BUILD_GROUP
581 @conf
582 def ENABLE_TIMESTAMP_DEPENDENCIES(conf):
583 """use timestamps instead of file contents for deps
584 this currently doesn't work"""
585 def h_file(filename):
586 import stat
587 st = os.stat(filename)
588 if stat.S_ISDIR(st[stat.ST_MODE]): raise IOError('not a file')
589 m = Utils.md5()
590 m.update(str(st.st_mtime))
591 m.update(str(st.st_size))
592 m.update(filename)
593 return m.digest()
594 Utils.h_file = h_file
598 t = Task.simple_task_type('copy_script', 'rm -f ${LINK_TARGET} && ln -s ${SRC[0].abspath(env)} ${LINK_TARGET}',
599 shell=True, color='PINK', ext_in='.bin')
600 t.quiet = True
602 @feature('copy_script')
603 @before('apply_link')
604 def copy_script(self):
605 tsk = self.create_task('copy_script', self.allnodes[0])
606 tsk.env.TARGET = self.target
608 def SAMBA_SCRIPT(bld, name, pattern, installdir, installname=None):
609 '''used to copy scripts from the source tree into the build directory
610 for use by selftest'''
612 source = bld.path.ant_glob(pattern)
614 bld.SET_BUILD_GROUP('build_source')
615 for s in TO_LIST(source):
616 iname = s
617 if installname != None:
618 iname = installname
619 target = os.path.join(installdir, iname)
620 tgtdir = os.path.dirname(os.path.join(bld.srcnode.abspath(bld.env), '..', target))
621 mkdir_p(tgtdir)
622 t = bld(features='copy_script',
623 source = s,
624 target = target,
625 always = True,
626 install_path = None)
627 t.env.LINK_TARGET = target
629 Build.BuildContext.SAMBA_SCRIPT = SAMBA_SCRIPT
632 def install_file(bld, destdir, file, chmod=MODE_644, flat=False,
633 python_fixup=False, destname=None, base_name=None):
634 '''install a file'''
635 destdir = bld.EXPAND_VARIABLES(destdir)
636 if not destname:
637 destname = file
638 if flat:
639 destname = os.path.basename(destname)
640 dest = os.path.join(destdir, destname)
641 if python_fixup:
642 # fixup the python path it will use to find Samba modules
643 inst_file = file + '.inst'
644 if bld.env["PYTHONDIR"] not in sys.path:
645 regex = "s|\(sys.path.insert.*\)bin/python\(.*\)$|\\1${PYTHONDIR}\\2|g"
646 else:
647 # Eliminate updating sys.path if the target python dir is already
648 # in python path.
649 regex = "s|sys.path.insert.*bin/python.*$||g"
650 bld.SAMBA_GENERATOR('python_%s' % destname,
651 rule="sed '%s' < ${SRC} > ${TGT}" % regex,
652 source=file,
653 target=inst_file)
654 file = inst_file
655 if base_name:
656 file = os.path.join(base_name, file)
657 bld.install_as(dest, file, chmod=chmod)
660 def INSTALL_FILES(bld, destdir, files, chmod=MODE_644, flat=False,
661 python_fixup=False, destname=None, base_name=None):
662 '''install a set of files'''
663 for f in TO_LIST(files):
664 install_file(bld, destdir, f, chmod=chmod, flat=flat,
665 python_fixup=python_fixup, destname=destname,
666 base_name=base_name)
667 Build.BuildContext.INSTALL_FILES = INSTALL_FILES
670 def INSTALL_WILDCARD(bld, destdir, pattern, chmod=MODE_644, flat=False,
671 python_fixup=False, exclude=None, trim_path=None):
672 '''install a set of files matching a wildcard pattern'''
673 files=TO_LIST(bld.path.ant_glob(pattern))
674 if trim_path:
675 files2 = []
676 for f in files:
677 files2.append(os_path_relpath(f, trim_path))
678 files = files2
680 if exclude:
681 for f in files[:]:
682 if fnmatch.fnmatch(f, exclude):
683 files.remove(f)
684 INSTALL_FILES(bld, destdir, files, chmod=chmod, flat=flat,
685 python_fixup=python_fixup, base_name=trim_path)
686 Build.BuildContext.INSTALL_WILDCARD = INSTALL_WILDCARD
689 def INSTALL_DIRS(bld, destdir, dirs):
690 '''install a set of directories'''
691 destdir = bld.EXPAND_VARIABLES(destdir)
692 dirs = bld.EXPAND_VARIABLES(dirs)
693 for d in TO_LIST(dirs):
694 bld.install_dir(os.path.join(destdir, d))
695 Build.BuildContext.INSTALL_DIRS = INSTALL_DIRS
698 re_header = re.compile('#include[ \t]*"([^"]+)"', re.I | re.M)
699 class header_task(Task.Task):
701 The public headers (the one installed on the system) have both
702 different paths and contents, so the rename is not enough.
704 Intermediate .inst.h files are created because path manipulation
705 may be slow. The substitution is thus performed only once.
708 name = 'header'
709 color = 'PINK'
710 vars = ['INCLUDEDIR', 'HEADER_DEPS']
712 def run(self):
713 txt = self.inputs[0].read(self.env)
715 # hard-coded string, but only present in samba4 (I promise, you won't feel a thing)
716 txt = txt.replace('#if _SAMBA_BUILD_ == 4', '#if 1\n')
718 # use a regexp to substitute the #include lines in the files
719 map = self.generator.bld.hnodemap
720 dirnodes = self.generator.bld.hnodedirs
721 def repl(m):
722 if m.group(1):
723 s = m.group(1)
725 # pokemon headers: gotta catch'em all!
726 fin = s
727 if s.startswith('bin/default'):
728 node = self.generator.bld.srcnode.find_resource(s.replace('bin/default/', ''))
729 if not node:
730 Logs.warn('could not find the public header for %r' % s)
731 elif node.id in map:
732 fin = map[node.id]
733 else:
734 Logs.warn('could not find the public header replacement for build header %r' % s)
735 else:
736 # this part is more difficult since the path may be relative to anything
737 for dirnode in dirnodes:
738 node = dirnode.find_resource(s)
739 if node:
740 if node.id in map:
741 fin = map[node.id]
742 break
743 else:
744 Logs.warn('could not find the public header replacement for source header %r %r' % (s, node))
745 else:
746 Logs.warn('-> could not find the public header for %r' % s)
748 return "#include <%s>" % fin
749 return ''
751 txt = re_header.sub(repl, txt)
753 # and write the output file
754 f = None
755 try:
756 f = open(self.outputs[0].abspath(self.env), 'w')
757 f.write(txt)
758 finally:
759 if f:
760 f.close()
762 @TaskGen.feature('pubh')
763 def make_public_headers(self):
765 collect the public headers to process and to install, then
766 create the substitutions (name and contents)
769 if not self.bld.is_install:
770 # install time only (lazy)
771 return
773 # keep two variables
774 # hnodedirs: list of folders for searching the headers
775 # hnodemap: node ids and replacement string (node objects are unique)
776 try:
777 self.bld.hnodedirs.append(self.path)
778 except AttributeError:
779 self.bld.hnodemap = {}
780 self.bld.hnodedirs = [self.bld.srcnode, self.path]
782 for k in 'source4 source4/include lib/talloc lib/tevent/ source4/lib/ldb/include/'.split():
783 node = self.bld.srcnode.find_dir(k)
784 if node:
785 self.bld.hnodedirs.append(node)
787 header_path = getattr(self, 'header_path', None) or ''
789 for x in self.to_list(self.headers):
791 # too complicated, but what was the original idea?
792 if isinstance(header_path, list):
793 add_dir = ''
794 for (p1, dir) in header_path:
795 lst = self.to_list(p1)
796 for p2 in lst:
797 if fnmatch.fnmatch(x, p2):
798 add_dir = dir
799 break
800 else:
801 continue
802 break
803 inst_path = add_dir
804 else:
805 inst_path = header_path
807 dest = ''
808 name = x
809 if x.find(':') != -1:
810 s = x.split(':')
811 name = s[0]
812 dest = s[1]
814 inn = self.path.find_resource(name)
816 if not inn:
817 raise ValueError("could not find the public header %r in %r" % (name, self.path))
818 out = inn.change_ext('.inst.h')
819 self.create_task('header', inn, out)
821 if not dest:
822 dest = inn.name
824 if inst_path:
825 inst_path = inst_path + '/'
826 inst_path = inst_path + dest
828 self.bld.install_as('${INCLUDEDIR}/%s' % inst_path, out, self.env)
830 self.bld.hnodemap[inn.id] = inst_path
832 # create a hash (not md5) to make sure the headers are re-created if something changes
833 val = 0
834 lst = list(self.bld.hnodemap.keys())
835 lst.sort()
836 for k in lst:
837 val = hash((val, k, self.bld.hnodemap[k]))
838 self.bld.env.HEADER_DEPS = val
840 def PUBLIC_HEADERS(bld, public_headers, header_path=None):
841 '''install some headers
843 header_path may either be a string that is added to the INCLUDEDIR,
844 or it can be a dictionary of wildcard patterns which map to destination
845 directories relative to INCLUDEDIR
847 bld.SET_BUILD_GROUP('final')
848 ret = bld(features=['pubh'], headers=public_headers, header_path=header_path)
849 return ret
850 Build.BuildContext.PUBLIC_HEADERS = PUBLIC_HEADERS
853 def subst_at_vars(task):
854 '''substiture @VAR@ style variables in a file'''
855 src = task.inputs[0].srcpath(task.env)
856 tgt = task.outputs[0].bldpath(task.env)
858 f = open(src, 'r')
859 s = f.read()
860 f.close()
861 # split on the vars
862 a = re.split('(@\w+@)', s)
863 out = []
864 done_var = {}
865 back_sub = [ ('PREFIX', '${prefix}'), ('EXEC_PREFIX', '${exec_prefix}')]
866 for v in a:
867 if re.match('@\w+@', v):
868 vname = v[1:-1]
869 if not vname in task.env and vname.upper() in task.env:
870 vname = vname.upper()
871 if not vname in task.env:
872 Logs.error("Unknown substitution %s in %s" % (v, task.name))
873 sys.exit(1)
874 v = SUBST_VARS_RECURSIVE(task.env[vname], task.env)
875 # now we back substitute the allowed pc vars
876 for (b, m) in back_sub:
877 s = task.env[b]
878 if s == v[0:len(s)]:
879 if not b in done_var:
880 # we don't want to substitute the first usage
881 done_var[b] = True
882 else:
883 v = m + v[len(s):]
884 break
885 out.append(v)
886 contents = ''.join(out)
887 f = open(tgt, 'w')
888 s = f.write(contents)
889 f.close()
890 return 0
893 def PKG_CONFIG_FILES(bld, pc_files, vnum=None):
894 '''install some pkg_config pc files'''
895 dest = '${PKGCONFIGDIR}'
896 dest = bld.EXPAND_VARIABLES(dest)
897 for f in TO_LIST(pc_files):
898 base=os.path.basename(f)
899 t = bld.SAMBA_GENERATOR('PKGCONFIG_%s' % base,
900 rule=subst_at_vars,
901 source=f+'.in',
902 target=f)
903 if vnum:
904 t.env.PACKAGE_VERSION = vnum
905 INSTALL_FILES(bld, dest, f, flat=True, destname=base)
906 Build.BuildContext.PKG_CONFIG_FILES = PKG_CONFIG_FILES
909 def MANPAGES(bld, manpages):
910 '''build and install manual pages'''
911 bld.env.MAN_XSL = 'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl'
912 for m in manpages.split():
913 source = m + '.xml'
914 bld.SAMBA_GENERATOR(m,
915 source=source,
916 target=m,
917 group='final',
918 rule='${XSLTPROC} -o ${TGT} --nonet ${MAN_XSL} ${SRC}'
920 bld.INSTALL_FILES('${MANDIR}/man%s' % m[-1], m, flat=True)
921 Build.BuildContext.MANPAGES = MANPAGES
924 #############################################################
925 # give a nicer display when building different types of files
926 def progress_display(self, msg, fname):
927 col1 = Logs.colors(self.color)
928 col2 = Logs.colors.NORMAL
929 total = self.position[1]
930 n = len(str(total))
931 fs = '[%%%dd/%%%dd] %s %%s%%s%%s\n' % (n, n, msg)
932 return fs % (self.position[0], self.position[1], col1, fname, col2)
934 def link_display(self):
935 if Options.options.progress_bar != 0:
936 return Task.Task.old_display(self)
937 fname = self.outputs[0].bldpath(self.env)
938 return progress_display(self, 'Linking', fname)
939 Task.TaskBase.classes['cc_link'].display = link_display
941 def samba_display(self):
942 if Options.options.progress_bar != 0:
943 return Task.Task.old_display(self)
945 targets = LOCAL_CACHE(self, 'TARGET_TYPE')
946 if self.name in targets:
947 target_type = targets[self.name]
948 type_map = { 'GENERATOR' : 'Generating',
949 'PROTOTYPE' : 'Generating'
951 if target_type in type_map:
952 return progress_display(self, type_map[target_type], self.name)
954 if len(self.inputs) == 0:
955 return Task.Task.old_display(self)
957 fname = self.inputs[0].bldpath(self.env)
958 if fname[0:3] == '../':
959 fname = fname[3:]
960 ext_loc = fname.rfind('.')
961 if ext_loc == -1:
962 return Task.Task.old_display(self)
963 ext = fname[ext_loc:]
965 ext_map = { '.idl' : 'Compiling IDL',
966 '.et' : 'Compiling ERRTABLE',
967 '.asn1': 'Compiling ASN1',
968 '.c' : 'Compiling' }
969 if ext in ext_map:
970 return progress_display(self, ext_map[ext], fname)
971 return Task.Task.old_display(self)
973 Task.TaskBase.classes['Task'].old_display = Task.TaskBase.classes['Task'].display
974 Task.TaskBase.classes['Task'].display = samba_display
977 @after('apply_link')
978 @feature('cshlib')
979 def apply_bundle_remove_dynamiclib_patch(self):
980 if self.env['MACBUNDLE'] or getattr(self,'mac_bundle',False):
981 if not getattr(self,'vnum',None):
982 try:
983 self.env['LINKFLAGS'].remove('-dynamiclib')
984 self.env['LINKFLAGS'].remove('-single_module')
985 except ValueError:
986 pass