build: smarter list splitting
[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, Logs, sys, Configure, Options, string, Task, Utils, optparse
5 from Configure import conf
6 from Logs import debug
7 from TaskGen import extension
8
9 # bring in the other samba modules
10 from samba_utils import *
11 # should be enabled from the above?
12 from samba_autoconf import *
13 from samba_patterns import *
14 from samba_pidl import *
15 from samba_asn1 import *
16 from samba_autoproto import *
17
18 LIB_PATH="shared"
19
20
21 #################################################################
22 # create the samba build environment
23 @conf
24 def SAMBA_BUILD_ENV(conf):
25     libpath="%s/%s" % (conf.blddir, LIB_PATH)
26     conf.env['BUILD_DIRECTORY'] = conf.blddir
27     if not os.path.exists(libpath):
28         os.mkdir(libpath)
29
30 ################################################################
31 # add an init_function to the list for a subsystem
32 def ADD_INIT_FUNCTION(bld, subsystem, init_function):
33     if init_function is None:
34         return
35     bld.ASSERT(subsystem is not None, "You must specify a subsystem for init_function '%s'" % init_function)
36     cache = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
37     if not subsystem in cache:
38         cache[subsystem] = ''
39     cache[subsystem] += '%s,' % init_function
40 Build.BuildContext.ADD_INIT_FUNCTION = ADD_INIT_FUNCTION
41
42 ################################################################
43 # recursively build the dependency list for a target
44 def FULL_DEPENDENCIES(bld, cache, target, chain, path):
45     if not target in cache:
46         return {}
47     deps = cache[target].copy()
48     for t in cache[target]:
49         bld.ASSERT(t not in chain, "Circular dependency for %s: %s->%s" % (t, path, t));
50         c2 = chain.copy()
51         c2[t] = True
52         dict_concat(deps, FULL_DEPENDENCIES(bld, cache, t, c2, "%s->%s" % (path, t)))
53     return deps
54
55 ############################################################
56 # check our build dependencies for circular dependencies
57 def CHECK_TARGET_DEPENDENCY(bld, target):
58     cache = LOCAL_CACHE(bld, 'LIB_DEPS')
59     return FULL_DEPENDENCIES(bld, cache, target, { target:True }, target)
60
61 ############################################################
62 # check that all dependencies have been declared
63 def CHECK_DEPENDENCIES(bld):
64     cache = LOCAL_CACHE(bld, 'LIB_DEPS')
65     target_cache = LOCAL_CACHE(bld, 'TARGET_TYPE')
66     debug('deps: Checking dependencies')
67     for t in cache:
68         deps = CHECK_TARGET_DEPENDENCY(bld, t)
69         for d in deps:
70             if not d in target_cache:
71                 print "WARNING: Dependency '%s' of target '%s' not declared" % (d, t)
72             #ASSERT(bld, d in target_cache,
73             #       "Dependency '%s' of target '%s' not declared" % (d, t))
74     debug("deps: Dependencies checked for %u targets" % len(target_cache))
75 Build.BuildContext.CHECK_DEPENDENCIES = CHECK_DEPENDENCIES
76
77
78 ############################################################
79 # pre-declare a target as being of a particular type
80 def PREDECLARE(bld, target, type):
81     cache = LOCAL_CACHE(bld, 'PREDECLARED_TARGET')
82     target_cache = LOCAL_CACHE(bld, 'TARGET_TYPE')
83     ASSERT(bld, not target in target_cache, "Target '%s' is already declared" % target)
84     ASSERT(bld, not target in cache, "Target '%s' already predeclared" % target)
85     cache[target] = type
86 Build.BuildContext.PREDECLARE = PREDECLARE
87
88
89
90 ################################################################
91 # add to the dependency list. Return a new dependency list with
92 # any circular dependencies removed
93 # returns a tuple containing (systemdeps, localdeps, add_objects)
94 def ADD_DEPENDENCIES(bld, name, deps):
95     debug('deps: Calculating dependencies for %s' % name)
96     lib_deps = LOCAL_CACHE(bld, 'LIB_DEPS')
97     if not name in lib_deps:
98         lib_deps[name] = {}
99     list = to_list(deps)
100     list2 = []
101     for d in list:
102         lib_deps[name][d] = True;
103         try:
104             CHECK_TARGET_DEPENDENCY(bld, name)
105             list2.append(d)
106         except AssertionError:
107             sys.stderr.write("Removing dependency %s from target %s\n" % (d, name))
108             del(lib_deps[name][d])
109
110     target_cache = LOCAL_CACHE(bld, 'TARGET_TYPE')
111
112     # extract out the system dependencies
113     sysdeps = []
114     localdeps = []
115     add_objects = []
116     cache = LOCAL_CACHE(bld, 'EMPTY_TARGETS')
117     predeclare = LOCAL_CACHE(bld, 'PREDECLARED_TARGET')
118     for d in list2:
119         recurse = False
120         # strip out any dependencies on empty libraries
121         if d in cache:
122             debug("deps: Removing empty dependency '%s' from '%s'" % (d, name))
123             continue
124         type = None
125
126         if d in target_cache:
127             type = target_cache[d]
128         elif d in predeclare:
129             type = predeclare[d]
130         else:
131             type = 'SUBSYSTEM'
132             LOCAL_CACHE_SET(bld, 'ASSUMED_TARGET', d, type)
133
134         if type == 'SYSLIB':
135             sysdeps.append(d)
136         elif type == 'LIBRARY':
137             localdeps.append(d)
138         elif type == 'SUBSYSTEM':
139             add_objects.append(d)
140             recurse = True
141         elif type == 'MODULE':
142             add_objects.append(d)
143             recurse = True
144         elif type == 'PYTHON':
145             pass
146         elif type == 'ASN1':
147             pass
148         elif type == 'BINARY':
149             pass
150         else:
151             ASSERT(bld, False, "Unknown target type '%s' for dependency %s" % (
152                     type, d))
153
154         # for some types we have to build the list recursively
155         if recurse and (d in lib_deps):
156             rec_deps = ' '.join(lib_deps[d].keys())
157             (rec_sysdeps, rec_localdeps, rec_add_objects) = ADD_DEPENDENCIES(bld, d, rec_deps)
158             sysdeps.extend(to_list(rec_sysdeps))
159             localdeps.extend(to_list(rec_localdeps))
160             add_objects.extend(to_list(rec_add_objects))
161
162     debug('deps: Dependencies for %s: sysdeps: %u  localdeps: %u  add_objects=%u' % (
163             name, len(sysdeps), len(localdeps), len(add_objects)))
164     return (' '.join(sysdeps), ' '.join(localdeps), ' '.join(add_objects))
165
166
167 #################################################################
168 # return a include list for a set of library dependencies
169 def SAMBA_LIBRARY_INCLUDE_LIST(bld, deps):
170     ret = bld.curdir + ' '
171     cache = LOCAL_CACHE(bld, 'INCLUDE_LIST')
172     for l in to_list(deps):
173         if l in cache:
174             ret = ret + cache[l] + ' '
175     if 'EXTRA_INCLUDES' in bld.env:
176         ret += ' ' + ' '.join(bld.env['EXTRA_INCLUDES'])
177     return ret
178 Build.BuildContext.SAMBA_LIBRARY_INCLUDE_LIST = SAMBA_LIBRARY_INCLUDE_LIST
179
180 #################################################################
181 # define a Samba library
182 def SAMBA_LIBRARY(bld, libname, source,
183                   deps='',
184                   public_deps='',
185                   includes='.',
186                   public_headers=None,
187                   vnum=None,
188                   cflags='',
189                   output_type=None,
190                   realname=None,
191                   autoproto=None,
192                   group='main',
193                   depends_on=''):
194     if not SET_TARGET_TYPE(bld, libname, 'LIBRARY'):
195         return
196
197     # remember empty libraries, so we can strip the dependencies
198     if (source == '') or (source == []):
199         LOCAL_CACHE_SET(bld, 'EMPTY_TARGETS', libname, True)
200         return
201
202     (sysdeps, localdeps, add_objects) = ADD_DEPENDENCIES(bld, libname, deps)
203
204     ilist = bld.SUBDIR(bld.curdir, includes) + ' ' + bld.SAMBA_LIBRARY_INCLUDE_LIST(deps)
205     ilist = bld.NORMPATH(ilist)
206
207     # this print below should show that we're runnig this code
208     print "Setting build group for library %s to %s" % (libname, group), bld.path
209     bld.SET_BUILD_GROUP(group)   # <- here
210     bld(
211         features = 'cc cshlib',
212         source = source,
213         target=libname,
214         uselib_local = localdeps,
215         uselib = sysdeps,
216         add_objects = add_objects,
217         ccflags = CURRENT_CFLAGS(bld, cflags),
218         includes=ilist + ' . #',
219         depends_on=depends_on,
220         vnum=vnum)
221
222     # I have to set it each time? I expect it to be still
223     # set from the few lines above
224
225     # put a link to the library in bin/shared
226     soext=""
227     if vnum is not None:
228         soext = '.' + vnum.split('.')[0]
229
230     t = bld(
231         source = 'lib%s.so' % libname,
232         rule = 'ln -sf ../${SRC}%s %s/lib%s.so%s' % (soext, LIB_PATH, libname, soext),
233 #        rule = 'ln -sf ../%s.so%s %s/lib%s.so%s' % (libname, soext, LIB_PATH, libname, soext),
234         shell = True,
235         after = 'cc_link',
236         always = True,
237         name = 'fff' + libname,
238         )
239     #print t.rule
240     LOCAL_CACHE_SET(bld, 'INCLUDE_LIST', libname, ilist)
241
242 Build.BuildContext.SAMBA_LIBRARY = SAMBA_LIBRARY
243
244 #################################################################
245 # define a Samba binary
246 def SAMBA_BINARY(bld, binname, source,
247                  deps='',
248                  includes='',
249                  public_headers=None,
250                  modules=None,
251                  installdir=None,
252                  ldflags=None,
253                  cflags='',
254                  autoproto=None,
255                  use_hostcc=None,
256                  compiler=None,
257                  group='main',
258                  manpages=None):
259     ilist = includes + ' ' + bld.SAMBA_LIBRARY_INCLUDE_LIST(deps)
260     ilist = bld.NORMPATH(ilist)
261
262     if not SET_TARGET_TYPE(bld, binname, 'BINARY'):
263         return
264
265     (sysdeps, localdeps, add_objects) = ADD_DEPENDENCIES(bld, binname, deps)
266
267     cache = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
268     if modules is not None:
269         for m in to_list(modules):
270             bld.ASSERT(m in cache,
271                        "No init_function defined for module '%s' in binary '%s'" % (m, binname))
272             cflags += ' -DSTATIC_%s_MODULES="%s"' % (m, cache[m])
273
274     bld.SET_BUILD_GROUP(group)
275     bld(
276         features = 'cc cprogram',
277         source = source,
278         target = binname,
279         uselib_local = localdeps,
280         uselib = sysdeps,
281         includes = ilist + ' . #',
282         ccflags = CURRENT_CFLAGS(bld, cflags),
283         add_objects = add_objects,
284         top=True)
285
286     if not Options.is_install:
287         bld(
288             source = binname,
289             rule = 'rm -f %s && cp ${SRC} .' % (binname),
290             shell = True,
291             after = 'cc_link',
292             always = True,
293             ext_in = '.bin',
294             name = binname + ".copy",
295             depends_on = binname
296             )
297 Build.BuildContext.SAMBA_BINARY = SAMBA_BINARY
298
299
300 #################################################################
301 # define a Samba python module
302 def SAMBA_PYTHON(bld, name, source,
303                  deps='',
304                  public_deps='',
305                  realname=''):
306
307     if not SET_TARGET_TYPE(bld, name, 'PYTHON'):
308         return
309
310     (sysdeps, localdeps, add_objects) = ADD_DEPENDENCIES(bld, name, deps)
311
312     return
313 Build.BuildContext.SAMBA_PYTHON = SAMBA_PYTHON
314
315 #################################################################
316 # define a Samba ET target
317 def SAMBA_ERRTABLE(bld, name, source,
318                options='',
319                directory=''):
320 #    print "Skipping ERRTABLE rule for %s with source=%s" % (name, source)
321 #    return
322     if not SET_TARGET_TYPE(bld, name, 'ET'):
323         return
324     bld.SET_BUILD_GROUP('build_source')
325     bld(
326         features = 'cc',
327         source   = source,
328         target   = name,
329         includes = '# #source4/heimdal_build #source4 #lib/replace'
330     )
331 Build.BuildContext.SAMBA_ERRTABLE = SAMBA_ERRTABLE
332
333 #################################################################
334 # define a Samba module.
335 def SAMBA_MODULE(bld, modname, source,
336                  deps='',
337                  includes='.',
338                  subsystem=None,
339                  init_function=None,
340                  autoproto=None,
341                  aliases=None,
342                  cflags='',
343                  output_type=None):
344
345     if not SET_TARGET_TYPE(bld, modname, 'MODULE'):
346         return
347
348     # remember empty modules, so we can strip the dependencies
349     if (source == '') or (source == []):
350         LOCAL_CACHE_SET(bld, 'EMPTY_TARGETS', modname, True)
351         return
352
353     (sysdeps, localdeps, add_objects) = ADD_DEPENDENCIES(bld, modname, deps)
354
355     ilist = bld.SUBDIR(bld.curdir, includes) + ' ' + bld.SAMBA_LIBRARY_INCLUDE_LIST(deps)
356     ilist = bld.NORMPATH(ilist)
357     bld.SET_BUILD_GROUP('main')
358     bld(
359         features = 'cc',
360         source = source,
361         target=modname,
362         ccflags = CURRENT_CFLAGS(bld, cflags),
363         includes=ilist + ' . #')
364 Build.BuildContext.SAMBA_MODULE = SAMBA_MODULE
365
366
367 #################################################################
368 # define a Samba subsystem
369 def SAMBA_SUBSYSTEM(bld, modname, source,
370                     deps='',
371                     public_deps='',
372                     includes='.',
373                     public_headers=None,
374                     cflags='',
375                     group='main',
376                     config_option=None,
377                     init_function_sentinal=None,
378                     heimdal_autoproto=None,
379                     heimdal_autoproto_private=None,
380                     autoproto=None,
381                     depends_on=''):
382
383     if not SET_TARGET_TYPE(bld, modname, 'SUBSYSTEM'):
384         return
385
386     # if the caller specifies a config_option, then we create a blank
387     # subsystem if that configuration option was found at configure time
388     if (config_option is not None) and bld.CONFIG_SET(config_option):
389             source = ''
390
391     # remember empty subsystems, so we can strip the dependencies
392     if (source == '') or (source == []):
393         LOCAL_CACHE_SET(bld, 'EMPTY_TARGETS', modname, True)
394         return
395
396     (sysdeps, localdeps, add_objects) = ADD_DEPENDENCIES(bld, modname, deps)
397
398     ilist = bld.SUBDIR(bld.curdir, includes) + ' ' + bld.SAMBA_LIBRARY_INCLUDE_LIST(deps)
399     ilist = bld.NORMPATH(ilist)
400     bld.SET_BUILD_GROUP(group)
401     t = bld(
402         features = 'cc',
403         source = source,
404         target=modname,
405         ccflags = CURRENT_CFLAGS(bld, cflags),
406         includes=ilist + ' . #',
407         depends_on=depends_on)
408     LOCAL_CACHE_SET(bld, 'INCLUDE_LIST', modname, ilist)
409
410     if heimdal_autoproto is not None:
411         bld.HEIMDAL_AUTOPROTO(heimdal_autoproto, source)
412     if heimdal_autoproto_private is not None:
413         bld.HEIMDAL_AUTOPROTO_PRIVATE(heimdal_autoproto_private, source)
414     if autoproto is not None:
415         bld.SAMBA_AUTOPROTO(autoproto, source)
416     return t
417
418 Build.BuildContext.SAMBA_SUBSYSTEM = SAMBA_SUBSYSTEM
419
420
421 ###############################################################
422 # add a new set of build rules from a subdirectory
423 # the @runonce decorator ensures we don't end up
424 # with duplicate rules
425 def BUILD_SUBDIR(bld, dir):
426     path = os.path.normpath(bld.curdir + '/' + dir)
427     cache = LOCAL_CACHE(bld, 'SUBDIR_LIST')
428     if path in cache: return
429     cache[path] = True
430     debug("build: Processing subdirectory %s" % dir)
431     bld.add_subdirs(dir)
432
433 Build.BuildContext.BUILD_SUBDIR = BUILD_SUBDIR
434
435
436 ##########################################################
437 # add a new top level command to waf
438 def ADD_COMMAND(opt, name, function):
439     Utils.g_module.__dict__[name] = function
440     opt.name = function
441 Options.Handler.ADD_COMMAND = ADD_COMMAND
442
443 ###########################################################
444 # setup build groups used to ensure that the different build
445 # phases happen consecutively
446 @runonce
447 def SETUP_BUILD_GROUPS(bld):
448     bld.p_ln = bld.srcnode # we do want to see all targets!
449     bld.env['USING_BUILD_GROUPS'] = True
450     bld.add_group('setup')
451     bld.add_group('base_libraries')
452     bld.add_group('build_compilers')
453     bld.add_group('build_source')
454     bld.add_group('prototypes')
455     bld.add_group('main')
456     bld.add_group('final')
457 Build.BuildContext.SETUP_BUILD_GROUPS = SETUP_BUILD_GROUPS
458
459
460 ###########################################################
461 # set the current build group
462 def SET_BUILD_GROUP(bld, group):
463     if not 'USING_BUILD_GROUPS' in bld.env:
464         return
465     bld.set_group(group)
466 Build.BuildContext.SET_BUILD_GROUP = SET_BUILD_GROUP
467