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