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