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