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