build: added public_headers support
[ira/wip.git] / lib / replace / 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
5 from Configure import conf
6
7 LIB_PATH="shared"
8
9 ####################################################
10 # some autoconf like helpers, to make the transition
11 # to waf a bit easier for those used to autoconf
12 # m4 files
13 @conf
14 def DEFUN(conf, d, v):
15     conf.define(d, v, quote=False)
16     conf.env.append_value('CCDEFINES', d + '=' + str(v))
17
18 @conf
19 def CHECK_HEADERS(conf, list):
20     for hdr in list.split():
21         if conf.check(header_name=hdr):
22             conf.env.hlist.append(hdr)
23
24 @conf
25 def CHECK_TYPES(conf, list):
26     for t in list.split():
27         conf.check(type_name=t, header_name=conf.env.hlist)
28
29 @conf
30 def CHECK_TYPE_IN(conf, t, hdr):
31     if conf.check(header_name=hdr):
32         conf.check(type_name=t, header_name=hdr)
33
34 @conf
35 def CHECK_TYPE(conf, t, alternate):
36     if not conf.check(type_name=t, header_name=conf.env.hlist):
37         conf.DEFUN(t, alternate)
38
39 @conf
40 def CHECK_FUNCS(conf, list):
41     for f in list.split():
42         conf.check(function_name=f, header_name=conf.env.hlist)
43
44 @conf
45 def CHECK_FUNCS_IN(conf, list, library):
46     if conf.check(lib=library, uselib_store=library):
47         for f in list.split():
48             conf.check(function_name=f, lib=library, header_name=conf.env.hlist)
49         conf.env['LIB_' + library.upper()] = library
50
51 #################################################
52 # write out config.h in the right directory
53 @conf
54 def SAMBA_CONFIG_H(conf, path=None):
55     if os.path.normpath(conf.curdir) != os.path.normpath(os.environ.get('PWD')):
56         return
57     if path is None:
58         conf.write_config_header('config.h', top=True)
59     else:
60         conf.write_config_header(path)
61
62
63 ##############################################################
64 # setup a configurable path
65 @conf
66 def CONFIG_PATH(conf, name, default):
67     if not name in conf.env:
68         conf.env[name] = conf.env['PREFIX'] + default
69     conf.define(name, conf.env[name], quote=True)
70
71 ##############################################################
72 # add some CFLAGS to the command line
73 @conf
74 def ADD_CFLAGS(conf, flags):
75     conf.env.append_value('CCFLAGS', flags.split())
76
77
78 ################################################################
79 # magic rpath handling
80 #
81 # we want a different rpath when installing and when building
82 # Note that this should really check if rpath is available on this platform
83 # and it should also honor an --enable-rpath option
84 def set_rpath(bld):
85     import Options
86     if Options.is_install:
87         if bld.env['RPATH_ON_INSTALL']:
88             bld.env['RPATH'] = ['-Wl,-rpath=%s/lib' % bld.env.PREFIX]
89         else:
90             bld.env['RPATH'] = []
91     else:
92         rpath = os.path.normpath('%s/bin/%s' % (bld.curdir, LIB_PATH))
93         bld.env.append_value('RPATH', '-Wl,-rpath=%s' % rpath)
94 Build.BuildContext.set_rpath = set_rpath
95
96 #############################################################
97 # a build assert call
98 def ASSERT(ctx, expression, msg):
99     if not expression:
100         sys.stderr.write("ERROR: %s\n" % msg)
101         raise AssertionError
102 Build.BuildContext.ASSERT = ASSERT
103
104 ################################################################
105 # create a list of files by pre-pending each with a subdir name
106 def SUBDIR(bld, subdir, list):
107     ret = ''
108     for l in list.split():
109         ret = ret + subdir + '/' + l + ' '
110     return ret
111 Build.BuildContext.SUBDIR = SUBDIR
112
113 #################################################################
114 # create the samba build environment
115 @conf
116 def SAMBA_BUILD_ENV(conf):
117     libpath="%s/%s" % (conf.blddir, LIB_PATH)
118     if not os.path.exists(libpath):
119         os.mkdir(libpath)
120
121 ##############################################
122 # remove .. elements from a path list
123 def NORMPATH(bld, ilist):
124     return " ".join([os.path.normpath(p) for p in ilist.split(" ")])
125 Build.BuildContext.NORMPATH = NORMPATH
126
127 ################################################################
128 # this will contain the set of includes needed per Samba library
129 Build.BuildContext.SAMBA_LIBRARY_INCLUDES = {}
130
131 ################################################################
132 # init function list for a subsystem
133 Build.BuildContext.SAMBA_INIT_FUNCTIONS = {}
134
135 ################################################################
136 # add an init_function to the list for a subsystem
137 def ADD_INIT_FUNCTION(bld, subsystem, init_function):
138     if init_function is None:
139         return
140     bld.ASSERT(subsystem is not None, "You must specify a subsystem for init_function '%s'" % init_function)
141     if not subsystem in bld.SAMBA_INIT_FUNCTIONS:
142         bld.SAMBA_INIT_FUNCTIONS[subsystem] = ''
143     bld.SAMBA_INIT_FUNCTIONS[subsystem] += '%s,' % init_function
144 Build.BuildContext.ADD_INIT_FUNCTION = ADD_INIT_FUNCTION
145
146
147 #################################################################
148 # return a include list for a set of library dependencies
149 def SAMBA_LIBRARY_INCLUDE_LIST(bld, deps):
150     ret = bld.curdir + ' '
151     for l in deps.split():
152         if l in bld.SAMBA_LIBRARY_INCLUDES:
153             ret = ret + bld.SAMBA_LIBRARY_INCLUDES[l] + ' '
154     return ret
155 Build.BuildContext.SAMBA_LIBRARY_INCLUDE_LIST = SAMBA_LIBRARY_INCLUDE_LIST
156
157 #################################################################
158 # define a Samba library
159 def SAMBA_LIBRARY(bld, libname, source_list,
160                   deps='',
161                   public_deps='',
162                   include_list='.',
163                   public_headers=None,
164                   vnum=None,
165                   cflags=None,
166                   autoproto=None):
167     # print "Declaring SAMBA_LIBRARY %s" % libname
168     ilist = bld.SAMBA_LIBRARY_INCLUDE_LIST(deps) + bld.SUBDIR(bld.curdir, include_list)
169     ilist = bld.NORMPATH(ilist)
170     bld(
171         features = 'cc cshlib',
172         source = source_list,
173         target=libname,
174         uselib_local = deps,
175         includes='. ' + os.environ.get('PWD') + '/bin/default ' + ilist,
176         vnum=vnum)
177
178     # put a link to the library in bin/shared
179     soext=""
180     if vnum is not None:
181         soext = '.' + vnum.split('.')[0]
182     bld(
183         source = 'lib%s.so' % libname,
184         target = '%s.lnk' % libname,
185         rule = 'ln -sf ../${SRC}%s %s/lib%s.so%s && touch ${TGT}' %
186         (soext, LIB_PATH, libname, soext),
187         shell = True
188         )
189     bld.SAMBA_LIBRARY_INCLUDES[libname] = ilist
190 Build.BuildContext.SAMBA_LIBRARY = SAMBA_LIBRARY
191
192
193 #################################################################
194 # define a Samba binary
195 def SAMBA_BINARY(bld, binname, source_list,
196                  deps='',
197                  syslibs='',
198                  include_list='',
199                  public_headers=None,
200                  modules=None,
201                  installdir=None,
202                  ldflags=None,
203                  cflags=None,
204                  autoproto=None,
205                  manpages=None):
206     ilist = '. ' + os.environ.get('PWD') + '/bin/default ' + bld.SAMBA_LIBRARY_INCLUDE_LIST(deps) + ' ' + include_list
207     ilist = bld.NORMPATH(ilist)
208     ccflags = ''
209
210     if modules is not None:
211         for m in modules.split():
212             bld.ASSERT(m in bld.SAMBA_INIT_FUNCTIONS,
213                        "No init_function defined for module '%s' in binary '%s'" % (m, binname))
214             modlist = bld.SAMBA_INIT_FUNCTIONS[m]
215             ccflags += ' -DSTATIC_%s_MODULES="%s"' % (m, modlist)
216
217     bld(
218         features = 'cc cprogram',
219         source = source_list,
220         target = binname,
221         uselib_local = deps,
222         uselib = syslibs,
223         includes = ilist,
224         ccflags = ccflags,
225         top=True)
226     # put a link to the binary in bin/
227     bld(
228         source = binname,
229         rule = 'ln -sf ${SRC} .',
230         )
231 Build.BuildContext.SAMBA_BINARY = SAMBA_BINARY
232
233
234 #################################################################
235 # define a Samba python module
236 def SAMBA_PYTHON(bld, name, source_list,
237                  deps='',
238                  public_deps='',
239                  realname=''):
240     Logs.debug('runner: PYTHON_SAMBA not implemented')
241     return
242 Build.BuildContext.SAMBA_PYTHON = SAMBA_PYTHON
243
244
245 ################################################################
246 # build a C prototype file automatically
247 def AUTOPROTO(bld, header, source_list):
248     if header is not None:
249         bld(
250             source = source_list,
251             target = header,
252             rule = '../script/mkproto.pl --srcdir=.. --builddir=. --public=/dev/null --private=${TGT} ${SRC}'
253             )
254 Build.BuildContext.AUTOPROTO = AUTOPROTO
255
256
257 #################################################################
258 # define a Samba module.
259 def SAMBA_MODULE(bld, modname, source_list,
260                  deps='',
261                  include_list='.',
262                  subsystem=None,
263                  init_function=None,
264                  autoproto=None,
265                  aliases=None,
266                  cflags=None,
267                  output_type=None):
268     bld.ADD_INIT_FUNCTION(subsystem, init_function)
269     bld.AUTOPROTO(autoproto, source_list)
270     bld.SAMBA_LIBRARY(modname, source_list,
271                       deps=deps, include_list=include_list)
272 Build.BuildContext.SAMBA_MODULE = SAMBA_MODULE
273
274 #################################################################
275 # define a Samba subsystem
276 def SAMBA_SUBSYSTEM(bld, modname, source_list,
277                     deps='',
278                     public_deps='',
279                     include_list='.',
280                     public_headers=None,
281                     autoproto=None,
282                     cflags=None,
283                     init_function_sentinal=None):
284     bld.SAMBA_LIBRARY(modname, source_list,
285                       deps=deps, include_list=include_list)
286 Build.BuildContext.SAMBA_SUBSYSTEM = SAMBA_SUBSYSTEM
287
288
289 ###############################################################
290 # add a new set of build rules from a subdirectory
291 def BUILD_SUBDIR(bld, dir):
292     try:
293         cache = bld.cache_build_subdirs
294     except AttributeError:
295         bld.cache_build_subdirs = cache = {}
296     abs_dir=os.path.normpath(bld.curdir + '/' + dir)
297     if abs_dir in cache:
298         return
299     cache[abs_dir] = True
300     bld.add_subdirs(dir)
301 Build.BuildContext.BUILD_SUBDIR = BUILD_SUBDIR
302
303
304 ############################################################
305 # this overrides the 'waf -v' debug output to be in a nice
306 # unix like format instead of a python list.
307 # Thanks to ita on #waf for this
308 def exec_command(self, cmd, **kw):
309     import Utils, Logs
310     _cmd = cmd
311     if isinstance(cmd, list):
312         _cmd = ' '.join(cmd)
313     Logs.debug('runner: %s' % _cmd)
314     if self.log:
315         self.log.write('%s\n' % cmd)
316         kw['log'] = self.log
317     try:
318         if not kw.get('cwd', None):
319             kw['cwd'] = self.cwd
320     except AttributeError:
321         self.cwd = kw['cwd'] = self.bldnode.abspath()
322     return Utils.exec_command(cmd, **kw)
323 Build.BuildContext.exec_command = exec_command
324
325
326 ######################################################
327 # this is used as a decorator to make functions only
328 # run once. Based on the idea from
329 # http://stackoverflow.com/questions/815110/is-there-a-decorator-to-simply-cache-function-return-values
330 runonce_ret = {}
331 def runonce(function):
332     def wrapper(*args):
333         if args in runonce_ret:
334             return runonce_ret[args]
335         else:
336             ret = function(*args)
337             runonce_ret[args] = ret
338             return ret
339     return wrapper