build: finer grained rpath checking for binary/install
[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, TaskGen
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
21 LIB_PATH="shared"
22
23 os.putenv('PYTHONUNBUFFERED', '1')
24
25 #################################################################
26 # create the samba build environment
27 @conf
28 def SAMBA_BUILD_ENV(conf):
29     conf.env['BUILD_DIRECTORY'] = conf.blddir
30     mkdir_p(os.path.join(conf.blddir, LIB_PATH))
31     mkdir_p(os.path.join(conf.blddir, 'python/samba/dcerpc'))
32     # this allows all of the bin/shared and bin/python targets
33     # to be expressed in terms of build directory paths
34     for p in ['python','shared']:
35         link_target = os.path.join(conf.blddir, 'default/' + p)
36         if not os.path.lexists(link_target):
37             os.symlink('../' + p, link_target)
38
39
40
41 ################################################################
42 # add an init_function to the list for a subsystem
43 def ADD_INIT_FUNCTION(bld, subsystem, target, init_function):
44     if init_function is None:
45         return
46     bld.ASSERT(subsystem is not None, "You must specify a subsystem for init_function '%s'" % init_function)
47     cache = LOCAL_CACHE(bld, 'INIT_FUNCTIONS')
48     if not subsystem in cache:
49         cache[subsystem] = []
50     cache[subsystem].append( { 'TARGET':target, 'INIT_FUNCTION':init_function } )
51 Build.BuildContext.ADD_INIT_FUNCTION = ADD_INIT_FUNCTION
52
53
54 #################################################################
55 # define a Samba library
56 def SAMBA_LIBRARY(bld, libname, source,
57                   deps='',
58                   public_deps='',
59                   includes='',
60                   public_headers=None,
61                   vnum=None,
62                   cflags='',
63                   external_library=False,
64                   realname=None,
65                   autoproto=None,
66                   group='main',
67                   depends_on='',
68                   local_include=True,
69                   install_path=None,
70                   install=True,
71                   enabled=True):
72
73     if not enabled:
74         SET_TARGET_TYPE(bld, libname, 'DISABLED')
75         return
76
77     # remember empty libraries, so we can strip the dependencies
78     if (source == '') or (source == []):
79         SET_TARGET_TYPE(bld, libname, 'EMPTY')
80         return
81
82     if bld.env.DISABLE_SHARED:
83         obj_target = libname
84     else:
85         obj_target = libname + '.objlist'
86
87     # first create a target for building the object files for this library
88     # by separating in this way, we avoid recompiling the C files
89     # separately for the install library and the build library
90     bld.SAMBA_SUBSYSTEM(obj_target,
91                         source         = source,
92                         deps           = deps,
93                         public_deps    = public_deps,
94                         includes       = includes,
95                         public_headers = public_headers,
96                         cflags         = cflags,
97                         group          = group,
98                         autoproto      = autoproto,
99                         depends_on     = depends_on,
100                         local_include  = local_include)
101
102     if bld.env.DISABLE_SHARED:
103         return
104
105     if not SET_TARGET_TYPE(bld, libname, 'LIBRARY'):
106         return
107
108     # the library itself will depend on that object target
109     deps += ' ' + public_deps
110     deps = TO_LIST(deps)
111     deps.append(obj_target)
112
113     bld.SET_BUILD_GROUP(group)
114     t = bld(
115         features        = 'cc cshlib symlink_lib',
116         source          = [],
117         target          = libname,
118         samba_cflags    = CURRENT_CFLAGS(bld, libname, cflags),
119         depends_on      = depends_on,
120         samba_deps      = deps,
121         samba_includes  = includes,
122         local_include   = local_include,
123         vnum            = vnum,
124         install_path    = None,
125         ldflags         = build_rpath(bld)
126         )
127
128     if install_path is None:
129         install_path = '${LIBDIR}'
130     install_path = SUBST_VARS_RECURSIVE(install_path, bld.env)
131
132     # we don't need the double libraries if rpath is off
133     if (bld.env.RPATH_ON_INSTALL == False and
134         bld.env.RPATH_ON_BUILD == False):
135         install_target = libname
136     else:
137         install_target = libname + '.inst'
138
139     if install and install_target != libname:
140         # create a separate install library, which may have
141         # different rpath settings
142         SET_TARGET_TYPE(bld, install_target, 'LIBRARY')
143         t = bld(
144             features        = 'cc cshlib',
145             source          = [],
146             target          = install_target,
147             samba_cflags    = CURRENT_CFLAGS(bld, libname, cflags),
148             depends_on      = depends_on,
149             samba_deps      = deps,
150             samba_includes  = includes,
151             local_include   = local_include,
152             vnum            = vnum,
153             install_as      = libname,
154             install_path    = None,
155             ldflags         = install_rpath(bld)
156             )
157
158     if install:
159         if vnum:
160             vnum_base = vnum.split('.')[0]
161             install_name = 'lib%s.so.%s' % (libname, vnum)
162             install_link = 'lib%s.so.%s' % (libname, vnum_base)
163         else:
164             install_name = 'lib%s.so' % libname
165             install_link = None
166
167         bld.install_as(os.path.join(install_path, install_name),
168                        'lib%s.inst.so' % libname)
169         if install_link:
170             bld.symlink_as(os.path.join(install_path, install_link), install_name)
171
172     if autoproto is not None:
173         bld.SAMBA_AUTOPROTO(autoproto, source)
174
175 Build.BuildContext.SAMBA_LIBRARY = SAMBA_LIBRARY
176
177
178 #################################################################
179 # define a Samba binary
180 def SAMBA_BINARY(bld, binname, source,
181                  deps='',
182                  includes='',
183                  public_headers=None,
184                  modules=None,
185                  installdir=None,
186                  ldflags=None,
187                  cflags='',
188                  autoproto=None,
189                  use_hostcc=None,
190                  compiler=None,
191                  group='binaries',
192                  manpages=None,
193                  local_include=True,
194                  subsystem_name=None,
195                  needs_python=False,
196                  install=True,
197                  install_path=None):
198
199     if not SET_TARGET_TYPE(bld, binname, 'BINARY'):
200         return
201
202     features = 'cc cprogram'
203     if needs_python:
204         features += ' pyembed'
205
206     bld.SET_BUILD_GROUP(group)
207
208     obj_target = binname + '.objlist'
209
210     # first create a target for building the object files for this binary
211     # by separating in this way, we avoid recompiling the C files
212     # separately for the install binary and the build binary
213     bld.SAMBA_SUBSYSTEM(obj_target,
214                         source         = source,
215                         deps           = deps,
216                         includes       = includes,
217                         cflags         = cflags,
218                         group          = group,
219                         autoproto      = autoproto,
220                         subsystem_name = subsystem_name,
221                         needs_python   = needs_python,
222                         local_include  = local_include)
223
224     # the library itself will depend on that object target
225     deps = TO_LIST(deps)
226     deps.append(obj_target)
227
228     bld(
229         features       = features + ' symlink_bin',
230         source         = [],
231         target         = binname,
232         samba_cflags   = CURRENT_CFLAGS(bld, binname, cflags),
233         samba_deps     = deps,
234         samba_includes = includes,
235         local_include  = local_include,
236         samba_modules  = modules,
237         top            = True,
238         samba_subsystem= subsystem_name,
239         install_path   = None,
240         ldflags        = build_rpath(bld)
241         )
242
243     if install_path is None:
244         install_path = '${BINDIR}'
245     install_path = SUBST_VARS_RECURSIVE(install_path, bld.env)
246
247     # we don't need the double binaries if rpath is off
248     if (bld.env.RPATH_ON_INSTALL == False and
249         bld.env.RPATH_ON_BUILD == False):
250         install_target = binname
251     else:
252         install_target = binname + '.inst'
253
254     if install and install_target != binname:
255         # we create a separate 'install' binary, which
256         # will have different rpath settings
257         SET_TARGET_TYPE(bld, install_target, 'BINARY')
258         t = bld(
259             features       = features,
260             source         = [],
261             target         = install_target,
262             samba_cflags   = CURRENT_CFLAGS(bld, binname, cflags),
263             samba_deps     = deps,
264             samba_includes = includes,
265             local_include  = local_include,
266             samba_modules  = modules,
267             top            = True,
268             samba_subsystem= subsystem_name,
269             install_path   = None,
270             ldflags        = install_rpath(bld)
271             )
272
273     if install:
274         bld.install_as(os.path.join(install_path, binname),
275                        install_target,
276                        chmod=0755)
277
278     # setup the subsystem_name as an alias for the real
279     # binary name, so it can be found when expanding
280     # subsystem dependencies
281     if subsystem_name is not None:
282         bld.TARGET_ALIAS(subsystem_name, binname)
283
284     if autoproto is not None:
285         bld.SAMBA_AUTOPROTO(autoproto, source)
286 Build.BuildContext.SAMBA_BINARY = SAMBA_BINARY
287
288
289 #################################################################
290 # define a Samba module.
291 def SAMBA_MODULE(bld, modname, source,
292                  deps='',
293                  includes='',
294                  subsystem=None,
295                  init_function=None,
296                  autoproto=None,
297                  autoproto_extra_source='',
298                  aliases=None,
299                  cflags='',
300                  internal_module=True,
301                  local_include=True,
302                  enabled=True):
303
304     # we add the init function regardless of whether the module
305     # is enabled or not, as we need to generate a null list if
306     # all disabled
307     bld.ADD_INIT_FUNCTION(subsystem, modname, init_function)
308
309     if internal_module or bld.env.DISABLE_SHARED:
310         # treat internal modules as subsystems for now
311         SAMBA_SUBSYSTEM(bld, modname, source,
312                         deps=deps,
313                         includes=includes,
314                         autoproto=autoproto,
315                         autoproto_extra_source=autoproto_extra_source,
316                         cflags=cflags,
317                         local_include=local_include,
318                         enabled=enabled)
319         return
320
321     if not enabled:
322         SET_TARGET_TYPE(bld, modname, 'DISABLED')
323         return
324
325     # remember empty modules, so we can strip the dependencies
326     if (source == '') or (source == []):
327         SET_TARGET_TYPE(bld, modname, 'EMPTY')
328         return
329
330     if not SET_TARGET_TYPE(bld, modname, 'MODULE'):
331         return
332
333     if subsystem is not None:
334         deps += ' ' + subsystem
335
336     bld.SET_BUILD_GROUP('main')
337     bld(
338         features       = 'cc',
339         source         = source,
340         target         = modname,
341         samba_cflags   = CURRENT_CFLAGS(bld, modname, cflags),
342         samba_includes = includes,
343         local_include  = local_include,
344         samba_deps     = TO_LIST(deps)
345         )
346
347     if autoproto is not None:
348         bld.SAMBA_AUTOPROTO(autoproto, source + ' ' + autoproto_extra_source)
349
350 Build.BuildContext.SAMBA_MODULE = SAMBA_MODULE
351
352
353 #################################################################
354 # define a Samba subsystem
355 def SAMBA_SUBSYSTEM(bld, modname, source,
356                     deps='',
357                     public_deps='',
358                     includes='',
359                     public_headers=None,
360                     cflags='',
361                     cflags_end=None,
362                     group='main',
363                     init_function_sentinal=None,
364                     heimdal_autoproto=None,
365                     heimdal_autoproto_options=None,
366                     heimdal_autoproto_private=None,
367                     autoproto=None,
368                     autoproto_extra_source='',
369                     depends_on='',
370                     local_include=True,
371                     local_include_first=True,
372                     subsystem_name=None,
373                     enabled=True,
374                     needs_python=False):
375
376     if not enabled:
377         SET_TARGET_TYPE(bld, modname, 'DISABLED')
378         return
379
380     # remember empty subsystems, so we can strip the dependencies
381     if (source == '') or (source == []):
382         SET_TARGET_TYPE(bld, modname, 'EMPTY')
383         return
384
385     if not SET_TARGET_TYPE(bld, modname, 'SUBSYSTEM'):
386         return
387
388     deps += ' ' + public_deps
389
390     bld.SET_BUILD_GROUP(group)
391
392     features = 'cc'
393     if needs_python:
394         features += ' pyext'
395
396     t = bld(
397         features       = features,
398         source         = source,
399         target         = modname,
400         samba_cflags   = CURRENT_CFLAGS(bld, modname, cflags),
401         depends_on     = depends_on,
402         samba_deps     = TO_LIST(deps),
403         samba_includes = includes,
404         local_include  = local_include,
405         local_include_first  = local_include_first,
406         samba_subsystem= subsystem_name
407         )
408
409     if cflags_end is not None:
410         t.samba_cflags.extend(TO_LIST(cflags_end))
411
412     if heimdal_autoproto is not None:
413         bld.HEIMDAL_AUTOPROTO(heimdal_autoproto, source, options=heimdal_autoproto_options)
414     if heimdal_autoproto_private is not None:
415         bld.HEIMDAL_AUTOPROTO_PRIVATE(heimdal_autoproto_private, source)
416     if autoproto is not None:
417         bld.SAMBA_AUTOPROTO(autoproto, source + ' ' + autoproto_extra_source)
418     return t
419
420 Build.BuildContext.SAMBA_SUBSYSTEM = SAMBA_SUBSYSTEM
421
422
423 def SAMBA_GENERATOR(bld, name, rule, source, target,
424                     group='build_source', enabled=True):
425     '''A generic source generator target'''
426
427     if not SET_TARGET_TYPE(bld, name, 'GENERATOR'):
428         return
429
430     if not enabled:
431         return
432
433     bld.SET_BUILD_GROUP(group)
434     bld(
435         rule=rule,
436         source=source,
437         target=target,
438         before='cc',
439         ext_out='.c',
440         name=name)
441 Build.BuildContext.SAMBA_GENERATOR = SAMBA_GENERATOR
442
443
444
445 ###############################################################
446 # add a new set of build rules from a subdirectory
447 # the @runonce decorator ensures we don't end up
448 # with duplicate rules
449 def BUILD_SUBDIR(bld, dir):
450     path = os.path.normpath(bld.curdir + '/' + dir)
451     cache = LOCAL_CACHE(bld, 'SUBDIR_LIST')
452     if path in cache: return
453     cache[path] = True
454     debug("build: Processing subdirectory %s" % dir)
455     bld.add_subdirs(dir)
456
457 Build.BuildContext.BUILD_SUBDIR = BUILD_SUBDIR
458
459
460 ##########################################################
461 # add a new top level command to waf
462 def ADD_COMMAND(opt, name, function):
463     Utils.g_module.__dict__[name] = function
464     opt.name = function
465 Options.Handler.ADD_COMMAND = ADD_COMMAND
466
467 ###########################################################
468 # setup build groups used to ensure that the different build
469 # phases happen consecutively
470 @runonce
471 def SETUP_BUILD_GROUPS(bld):
472     bld.p_ln = bld.srcnode # we do want to see all targets!
473     bld.env['USING_BUILD_GROUPS'] = True
474     bld.add_group('setup')
475     bld.add_group('build_compiler_source')
476     bld.add_group('base_libraries')
477     bld.add_group('build_compilers')
478     bld.add_group('build_source')
479     bld.add_group('prototypes')
480     bld.add_group('main')
481     bld.add_group('binaries')
482     bld.add_group('final')
483 Build.BuildContext.SETUP_BUILD_GROUPS = SETUP_BUILD_GROUPS
484
485
486 ###########################################################
487 # set the current build group
488 def SET_BUILD_GROUP(bld, group):
489     if not 'USING_BUILD_GROUPS' in bld.env:
490         return
491     bld.set_group(group)
492 Build.BuildContext.SET_BUILD_GROUP = SET_BUILD_GROUP
493
494
495 def h_file(filename):
496     import stat
497     st = os.stat(filename)
498     if stat.S_ISDIR(st[stat.ST_MODE]): raise IOError('not a file')
499     m = Utils.md5()
500     m.update(str(st.st_mtime))
501     m.update(str(st.st_size))
502     m.update(filename)
503     return m.digest()
504
505 @conf
506 def ENABLE_TIMESTAMP_DEPENDENCIES(conf):
507     Utils.h_file = h_file
508
509
510 ##############################
511 # handle the creation of links for libraries and binaries
512 # note that we use a relative symlink path to allow the whole tree
513 # to me moved/copied elsewhere without breaking the links
514 t = Task.simple_task_type('symlink_lib', 'ln -sf ${LINK_SOURCE} ${LINK_TARGET}',
515                           color='PINK', ext_in='.bin')
516 t.quiet = True
517
518 @feature('symlink_lib')
519 @after('apply_link')
520 def symlink_lib(self):
521     tsk = self.create_task('symlink_lib', self.link_task.outputs[0])
522
523     # calculat the link target and put it in the environment
524     soext=""
525     vnum = getattr(self, 'vnum', None)
526     if vnum is not None:
527         soext = '.' + vnum.split('.')[0]
528
529     link_target = getattr(self, 'link_name', '')
530     if link_target == '':
531         link_target = '%s/lib%s.so%s' % (LIB_PATH, self.sname, soext)
532
533
534     link_source = os_path_relpath(self.link_task.outputs[0].abspath(self.env),
535                                   os.path.join(self.env.BUILD_DIRECTORY, link_target))
536
537     tsk.env.LINK_TARGET = link_target
538     tsk.env.LINK_SOURCE = link_source[3:]
539     debug('task_gen: LINK for %s is %s -> %s',
540           self.name, tsk.env.LINK_SOURCE, tsk.env.LINK_TARGET)
541
542
543 t = Task.simple_task_type('symlink_bin', 'ln -sf ${SRC} ${BIN_TARGET}',
544                           color='PINK', ext_in='.bin')
545 t.quiet = True
546
547 @feature('symlink_bin')
548 @after('apply_link')
549 def symlink_bin(self):
550     if Options.is_install:
551         # we don't want to copy the install binary, as
552         # that has the install rpath, not the build rpath
553         # The rpath of the binaries in bin/default/foo/blah is different
554         # during the install phase, as distros insist on not using rpath in installed binaries
555         return
556     tsk = self.create_task('symlink_bin', self.link_task.outputs[0])
557
558     tsk.env.BIN_TARGET = self.target
559     debug('task_gen: BIN_TARGET for %s is %s', self.name, tsk.env.BIN_TARGET)
560
561
562
563
564 t = Task.simple_task_type('copy_script', 'ln -sf ${SRC[0].abspath(env)} ${LINK_TARGET}',
565                           color='PINK', ext_in='.bin', shell=True)
566 t.quiet = True
567
568 @feature('copy_script')
569 @before('apply_link')
570 def copy_script(self):
571     tsk = self.create_task('copy_script', self.allnodes[0])
572     tsk.env.TARGET = self.target
573
574 def SAMBA_SCRIPT(bld, name, pattern, installdir, installname=None):
575     '''used to copy scripts from the source tree into the build directory
576        for use by selftest'''
577
578     source = bld.path.ant_glob(pattern)
579
580     bld.SET_BUILD_GROUP('build_source')
581     for s in TO_LIST(source):
582         iname = s
583         if installname != None:
584             iname = installname
585         target = os.path.join(installdir, iname)
586         tgtdir = os.path.dirname(os.path.join(bld.srcnode.abspath(bld.env), '..', target))
587         mkdir_p(tgtdir)
588         t = bld(features='copy_script',
589                 source       = s,
590                 target       = target,
591                 always       = True,
592                 install_path = None)
593         t.env.LINK_TARGET = target
594
595 Build.BuildContext.SAMBA_SCRIPT = SAMBA_SCRIPT
596