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