build: try faster includes processing
[kai/samba.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
5 from Configure import conf
6 from Logs import debug
7
8 # bring in the other samba modules
9 from samba_utils import *
10 from samba_autoconf import *
11 from samba_patterns import *
12 from samba_pidl import *
13 from samba_errtable import *
14 from samba_asn1 import *
15 from samba_autoproto import *
16 from samba_python import *
17 from samba_deps import *
18
19 LIB_PATH="shared"
20
21
22
23 #################################################################
24 # create the samba build environment
25 @conf
26 def SAMBA_BUILD_ENV(conf):
27     conf.env['BUILD_DIRECTORY'] = conf.blddir
28     mkdir_p(os.path.join(conf.blddir, LIB_PATH))
29     mkdir_p(os.path.join(conf.blddir, 'python/samba/dcerpc'))
30     # this allows all of the bin/shared and bin/python targets
31     # to be expressed in terms of build directory paths
32     for p in ['python','shared']:
33         link_target = os.path.join(conf.blddir, 'default/' + p)
34         if not os.path.lexists(link_target):
35             os.symlink('../' + p, link_target)
36
37
38
39 ################################################################
40 # add an init_function to the list for a subsystem
41 def ADD_INIT_FUNCTION(bld, subsystem, target, init_function):
42     if init_function is None:
43         return
44     bld.ASSERT(subsystem is not None, "You must specify a subsystem for init_function '%s'" % init_function)
45     cache = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
46     if not subsystem in cache:
47         cache[subsystem] = []
48     cache[subsystem].append( { 'TARGET':target, 'INIT_FUNCTION':init_function } )
49 Build.BuildContext.ADD_INIT_FUNCTION = ADD_INIT_FUNCTION
50
51
52 #################################################################
53 # define a Samba library
54 def SAMBA_LIBRARY(bld, libname, source,
55                   deps='',
56                   public_deps='',
57                   includes='',
58                   public_headers=None,
59                   vnum=None,
60                   cflags='',
61                   external_library=False,
62                   realname=None,
63                   autoproto=None,
64                   group='main',
65                   depends_on='',
66                   local_include=True):
67
68     # remember empty libraries, so we can strip the dependencies
69     if (source == '') or (source == []):
70         SET_TARGET_TYPE(bld, libname, 'EMPTY')
71         return
72
73     if not SET_TARGET_TYPE(bld, libname, 'LIBRARY'):
74         return
75
76     deps += ' ' + public_deps
77
78     # this print below should show that we're runnig this code
79     bld.SET_BUILD_GROUP(group)
80     t = bld(
81         features        = 'cc cshlib symlink_lib',
82         source          = source,
83         target          = libname,
84         samba_cflags    = CURRENT_CFLAGS(bld, libname, cflags),
85         depends_on      = depends_on,
86         samba_deps      = TO_LIST(deps),
87         samba_includes  = includes,
88         local_include   = local_include,
89         vnum            = vnum
90         )
91     if autoproto is not None:
92         bld.SAMBA_AUTOPROTO(autoproto, source)
93
94 Build.BuildContext.SAMBA_LIBRARY = SAMBA_LIBRARY
95
96 #################################################################
97 # define a Samba binary
98 def SAMBA_BINARY(bld, binname, source,
99                  deps='',
100                  includes='',
101                  public_headers=None,
102                  modules=None,
103                  installdir=None,
104                  ldflags=None,
105                  cflags='',
106                  autoproto=None,
107                  use_hostcc=None,
108                  compiler=None,
109                  group='binaries',
110                  manpages=None,
111                  local_include=True,
112                  subsystem_name=None,
113                  needs_python=False):
114
115     if not SET_TARGET_TYPE(bld, binname, 'BINARY'):
116         return
117
118     features = 'cc cprogram copy_bin'
119     if needs_python:
120         features += ' pyembed'
121
122     bld.SET_BUILD_GROUP(group)
123     bld(
124         features       = features,
125         source         = source,
126         target         = binname,
127         samba_cflags   = CURRENT_CFLAGS(bld, binname, cflags),
128         samba_deps     = TO_LIST(deps),
129         samba_includes = includes,
130         local_include  = local_include,
131         samba_modules  = modules,
132         top            = True,
133         samba_subsystem= subsystem_name
134         )
135
136     # setup the subsystem_name as an alias for the real
137     # binary name, so it can be found when expanding
138     # subsystem dependencies
139     if subsystem_name is not None:
140         bld.TARGET_ALIAS(subsystem_name, binname)
141
142     if autoproto is not None:
143         bld.SAMBA_AUTOPROTO(autoproto, source)
144 Build.BuildContext.SAMBA_BINARY = SAMBA_BINARY
145
146
147 #################################################################
148 # define a Samba module.
149 def SAMBA_MODULE(bld, modname, source,
150                  deps='',
151                  includes='',
152                  subsystem=None,
153                  init_function=None,
154                  autoproto=None,
155                  autoproto_extra_source='',
156                  aliases=None,
157                  cflags='',
158                  internal_module=True,
159                  local_include=True,
160                  enabled=True):
161
162     if internal_module:
163         # treat internal modules as subsystems for now
164         SAMBA_SUBSYSTEM(bld, modname, source,
165                         deps=deps,
166                         includes=includes,
167                         autoproto=autoproto,
168                         autoproto_extra_source=autoproto_extra_source,
169                         cflags=cflags,
170                         local_include=local_include,
171                         enabled=enabled)
172         # even though we're treating it as a subsystem, we need to
173         # add it to the init_function list
174         # TODO: we should also create an implicit dependency
175         # between the subsystem target and this target
176         if enabled:
177             bld.ADD_INIT_FUNCTION(subsystem, modname, init_function)
178         return
179
180     if not enabled:
181         SET_TARGET_TYPE(bld, modname, 'DISABLED')
182         return
183
184     # remember empty modules, so we can strip the dependencies
185     if (source == '') or (source == []):
186         SET_TARGET_TYPE(bld, modname, 'EMPTY')
187         return
188
189     if not SET_TARGET_TYPE(bld, modname, 'MODULE'):
190         return
191
192
193     bld.ADD_INIT_FUNCTION(subsystem, modname, init_function)
194
195     if subsystem is not None:
196         deps += ' ' + subsystem
197
198     bld.SET_BUILD_GROUP('main')
199     bld(
200         features       = 'cc',
201         source         = source,
202         target         = modname,
203         samba_cflags   = CURRENT_CFLAGS(bld, modname, cflags),
204         samba_includes = includes,
205         local_include  = local_include,
206         samba_deps     = TO_LIST(deps)
207         )
208
209     if autoproto is not None:
210         bld.SAMBA_AUTOPROTO(autoproto, source + ' ' + autoproto_extra_source)
211
212 Build.BuildContext.SAMBA_MODULE = SAMBA_MODULE
213
214
215 #################################################################
216 # define a Samba subsystem
217 def SAMBA_SUBSYSTEM(bld, modname, source,
218                     deps='',
219                     public_deps='',
220                     includes='',
221                     public_headers=None,
222                     cflags='',
223                     group='main',
224                     config_option=None,
225                     init_function_sentinal=None,
226                     heimdal_autoproto=None,
227                     heimdal_autoproto_options=None,
228                     heimdal_autoproto_private=None,
229                     autoproto=None,
230                     autoproto_extra_source='',
231                     depends_on='',
232                     local_include=True,
233                     local_include_first=True,
234                     subsystem_name=None,
235                     enabled=True,
236                     needs_python=False):
237
238     if not enabled:
239         SET_TARGET_TYPE(bld, modname, 'DISABLED')
240         return
241
242     # remember empty subsystems, so we can strip the dependencies
243     if (source == '') or (source == []):
244         SET_TARGET_TYPE(bld, modname, 'EMPTY')
245         return
246
247     if not SET_TARGET_TYPE(bld, modname, 'SUBSYSTEM'):
248         return
249
250     deps += ' ' + public_deps
251
252     bld.SET_BUILD_GROUP(group)
253
254     features = 'cc'
255     if needs_python:
256         features += ' pyext'
257
258     t = bld(
259         features       = features,
260         source         = source,
261         target         = modname,
262         samba_cflags   = CURRENT_CFLAGS(bld, modname, cflags),
263         depends_on     = depends_on,
264         samba_deps     = TO_LIST(deps),
265         samba_includes = includes,
266         local_include  = local_include,
267         local_include_first  = local_include_first,
268         samba_subsystem= subsystem_name
269         )
270
271     if heimdal_autoproto is not None:
272         bld.HEIMDAL_AUTOPROTO(heimdal_autoproto, source, options=heimdal_autoproto_options)
273     if heimdal_autoproto_private is not None:
274         bld.HEIMDAL_AUTOPROTO_PRIVATE(heimdal_autoproto_private, source)
275     if autoproto is not None:
276         bld.SAMBA_AUTOPROTO(autoproto, source + ' ' + autoproto_extra_source)
277     return t
278
279 Build.BuildContext.SAMBA_SUBSYSTEM = SAMBA_SUBSYSTEM
280
281
282 def SAMBA_GENERATOR(bld, name, rule, source, target,
283                     group='build_source'):
284     '''A generic source generator target'''
285
286     if not SET_TARGET_TYPE(bld, name, 'GENERATOR'):
287         return
288
289     bld.SET_BUILD_GROUP(group)
290     bld(
291         rule=rule,
292         source=source,
293         target=target,
294         before='cc',
295         ext_out='.c')
296 Build.BuildContext.SAMBA_GENERATOR = SAMBA_GENERATOR
297
298
299
300 ###############################################################
301 # add a new set of build rules from a subdirectory
302 # the @runonce decorator ensures we don't end up
303 # with duplicate rules
304 def BUILD_SUBDIR(bld, dir):
305     path = os.path.normpath(bld.curdir + '/' + dir)
306     cache = LOCAL_CACHE(bld, 'SUBDIR_LIST')
307     if path in cache: return
308     cache[path] = True
309     debug("build: Processing subdirectory %s" % dir)
310     bld.add_subdirs(dir)
311
312 Build.BuildContext.BUILD_SUBDIR = BUILD_SUBDIR
313
314
315 ##########################################################
316 # add a new top level command to waf
317 def ADD_COMMAND(opt, name, function):
318     Utils.g_module.__dict__[name] = function
319     opt.name = function
320 Options.Handler.ADD_COMMAND = ADD_COMMAND
321
322 ###########################################################
323 # setup build groups used to ensure that the different build
324 # phases happen consecutively
325 @runonce
326 def SETUP_BUILD_GROUPS(bld):
327     bld.p_ln = bld.srcnode # we do want to see all targets!
328     bld.env['USING_BUILD_GROUPS'] = True
329     bld.add_group('setup')
330     bld.add_group('base_libraries')
331     bld.add_group('build_compilers')
332     bld.add_group('build_source')
333     bld.add_group('prototypes')
334     bld.add_group('main')
335     bld.add_group('binaries')
336     bld.add_group('final')
337 Build.BuildContext.SETUP_BUILD_GROUPS = SETUP_BUILD_GROUPS
338
339
340 ###########################################################
341 # set the current build group
342 def SET_BUILD_GROUP(bld, group):
343     if not 'USING_BUILD_GROUPS' in bld.env:
344         return
345     bld.set_group(group)
346 Build.BuildContext.SET_BUILD_GROUP = SET_BUILD_GROUP
347
348
349 def h_file(filename):
350     import stat
351     st = os.stat(filename)
352     if stat.S_ISDIR(st[stat.ST_MODE]): raise IOError('not a file')
353     m = Utils.md5()
354     m.update(str(st.st_mtime))
355     m.update(str(st.st_size))
356     m.update(filename)
357     return m.digest()
358
359 @conf
360 def ENABLE_TIMESTAMP_DEPENDENCIES(conf):
361     Utils.h_file = h_file
362
363
364 ##############################
365 # handle the creation of links for libraries and binaries
366 # note that we use a relative symlink path to allow the whole tree
367 # to me moved/copied elsewhere without breaking the links
368 t = Task.simple_task_type('symlink_lib', 'ln -sf ${LINK_SOURCE} ${LINK_TARGET}',
369                           color='PINK', ext_in='.bin')
370 t.quiet = True
371
372 @feature('symlink_lib')
373 @after('apply_link')
374 def symlink_lib(self):
375     tsk = self.create_task('symlink_lib', self.link_task.outputs[0])
376
377     # calculat the link target and put it in the environment
378     soext=""
379     vnum = getattr(self, 'vnum', None)
380     if vnum is not None:
381         soext = '.' + vnum.split('.')[0]
382
383     link_target = getattr(self, 'link_name', '')
384     if link_target == '':
385         link_target = '%s/lib%s.so%s' % (LIB_PATH, self.sname, soext)
386
387
388     link_source = os_path_relpath(self.link_task.outputs[0].abspath(self.env),
389                                   os.path.join(self.env.BUILD_DIRECTORY, link_target))
390
391     tsk.env.LINK_TARGET = link_target
392     tsk.env.LINK_SOURCE = link_source[3:]
393     debug('task_gen: LINK for %s is %s -> %s',
394           self.name, tsk.env.LINK_SOURCE, tsk.env.LINK_TARGET)
395
396 # for binaries we need to copy the executable to avoid the rpath changing
397 # in the local bin/ directory on install
398 t = Task.simple_task_type('copy_bin', 'rm -f ${BIN_TARGET} && cp ${SRC} ${BIN_TARGET}', color='PINK',
399                           ext_in='.bin', shell=True)
400 t.quiet = True
401
402 @feature('copy_bin')
403 @after('apply_link')
404 def copy_bin(self):
405     if Options.is_install:
406         # we don't want to copy the install binary, as
407         # that has the install rpath, not the build rpath
408         # The rpath of the binaries in bin/default/foo/blah is different
409         # during the install phase, as distros insist on not using rpath in installed binaries
410         return
411     tsk = self.create_task('copy_bin', self.link_task.outputs[0])
412
413     tsk.env.BIN_TARGET = self.target
414     debug('task_gen: BIN_TARGET for %s is %s', self.name, tsk.env.BIN_TARGET)
415
416
417
418
419 t = Task.simple_task_type('copy_script', 'ln -sf ${SRC[0].abspath(env)} ${LINK_TARGET}',
420                           color='PINK', ext_in='.bin', shell=True)
421 t.quiet = True
422
423 @feature('copy_script')
424 @before('apply_link')
425 def copy_script(self):
426     tsk = self.create_task('copy_script', self.allnodes[0])
427     tsk.env.TARGET = self.target
428
429 def SAMBA_SCRIPT(bld, name, pattern, installdir, installname=None):
430     '''used to copy scripts from the source tree into the build directory
431        for use by selftest'''
432
433     source = bld.path.ant_glob(pattern)
434
435     bld.SET_BUILD_GROUP('build_source')
436     for s in TO_LIST(source):
437         iname = s
438         if installname != None:
439             iname = installname
440         target = os.path.join(installdir, iname)
441         tgtdir = os.path.dirname(os.path.join(bld.srcnode.abspath(bld.env), '..', target))
442         mkdir_p(tgtdir)
443         t = bld(features='copy_script',
444                 source=s,
445                 target = target,
446                 always=True)
447         t.env.LINK_TARGET = target
448
449 Build.BuildContext.SAMBA_SCRIPT = SAMBA_SCRIPT
450