wafsamba: remove hpuxcc.py as it's not compatible with waf 2
[samba.git] / buildtools / wafsamba / samba_waf18.py
1 # compatibility layer for building with more recent waf versions
2
3 import os, shlex, sys
4 from waflib import Build, Configure, Node, Utils, Options, Logs, TaskGen
5 from waflib import ConfigSet
6 from waflib.TaskGen import feature, after
7 from waflib.Configure import conf, ConfigurationContext
8
9 from waflib.Tools.flex import decide_ext
10
11 # This version of flexfun runs in tsk.get_cwd() as opposed to the
12 # bld.variant_dir: since input paths adjusted against tsk.get_cwd(), we have to
13 # use tsk.get_cwd() for the work directory as well.
14 def flexfun(tsk):
15     env = tsk.env
16     bld = tsk.generator.bld
17     def to_list(xx):
18         if isinstance(xx, str):
19             return [xx]
20         return xx
21     tsk.last_cmd = lst = []
22     lst.extend(to_list(env.FLEX))
23     lst.extend(to_list(env.FLEXFLAGS))
24     inputs = [a.path_from(tsk.get_cwd()) for a in tsk.inputs]
25     if env.FLEX_MSYS:
26         inputs = [x.replace(os.sep, '/') for x in inputs]
27     lst.extend(inputs)
28     lst = [x for x in lst if x]
29     txt = bld.cmd_and_log(lst, cwd=tsk.get_cwd(), env=env.env or None, quiet=0)
30     tsk.outputs[0].write(txt.replace('\r\n', '\n').replace('\r', '\n')) # issue #1207
31
32 TaskGen.declare_chain(
33     name = 'flex',
34     rule = flexfun, # issue #854
35     ext_in = '.l',
36     decider = decide_ext,
37 )
38
39
40 for y in (Build.BuildContext, Build.CleanContext, Build.InstallContext, Build.UninstallContext, Build.ListContext):
41     class tmp(y):
42         variant = 'default'
43
44 def pre_build(self):
45     self.cwdx = self.bldnode.parent
46     self.cwd = self.cwdx.abspath()
47     self.bdir = self.bldnode.abspath()
48     return Build.BuildContext.old_pre_build(self)
49 Build.BuildContext.old_pre_build = Build.BuildContext.pre_build
50 Build.BuildContext.pre_build = pre_build
51
52 def abspath(self, env=None):
53     if env and hasattr(self, 'children'):
54         return self.get_bld().abspath()
55     return self.old_abspath()
56 Node.Node.old_abspath = Node.Node.abspath
57 Node.Node.abspath = abspath
58
59 def bldpath(self, env=None):
60     return self.abspath()
61     #return self.path_from(self.ctx.bldnode.parent)
62 Node.Node.bldpath = bldpath
63
64 def srcpath(self, env=None):
65     return self.abspath()
66     #return self.path_from(self.ctx.bldnode.parent)
67 Node.Node.srcpath = srcpath
68
69 def store_fast(self, filename):
70     file = open(filename, 'wb')
71     data = self.get_merged_dict()
72     try:
73         Build.cPickle.dump(data, file, -1)
74     finally:
75         file.close()
76 ConfigSet.ConfigSet.store_fast = store_fast
77
78 def load_fast(self, filename):
79     file = open(filename, 'rb')
80     try:
81         data = Build.cPickle.load(file)
82     finally:
83         file.close()
84     self.table.update(data)
85 ConfigSet.ConfigSet.load_fast = load_fast
86
87 @feature('c', 'cxx', 'd', 'asm', 'fc', 'includes')
88 @after('propagate_uselib_vars', 'process_source')
89 def apply_incpaths(self):
90     lst = self.to_incnodes(self.to_list(getattr(self, 'includes', [])) + self.env['INCLUDES'])
91     self.includes_nodes = lst
92     cwdx = getattr(self.bld, 'cwdx', self.bld.bldnode)
93     self.env['INCPATHS'] = [x.path_from(cwdx) for x in lst]
94
95 @conf
96 def define(self, key, val, quote=True, comment=None):
97    assert key and isinstance(key, str)
98
99    if val is None:
100        val = ()
101    elif isinstance(val, bool):
102        val = int(val)
103
104    # waf 1.5
105    self.env[key] = val
106
107    if isinstance(val, int) or isinstance(val, float):
108            s = '%s=%s'
109    else:
110            s = quote and '%s="%s"' or '%s=%s'
111    app = s % (key, str(val))
112
113    ban = key + '='
114    lst = self.env.DEFINES
115    for x in lst:
116            if x.startswith(ban):
117                    lst[lst.index(x)] = app
118                    break
119    else:
120            self.env.append_value('DEFINES', app)
121
122    self.env.append_unique('define_key', key)
123
124 # compat15 removes this but we want to keep it
125 @conf
126 def undefine(self, key, from_env=True, comment=None):
127     assert key and isinstance(key, str)
128
129     ban = key + '='
130     self.env.DEFINES = [x for x in self.env.DEFINES if not x.startswith(ban)]
131     self.env.append_unique('define_key', key)
132     # waf 1.5
133     if from_env:
134         self.env[key] = ()
135
136 def install_dir(self, path):
137         if not path:
138                 return []
139
140         destpath = Utils.subst_vars(path, self.env)
141
142         if self.is_install > 0:
143                 Logs.info('* creating %s', destpath)
144                 Utils.check_dir(destpath)
145         elif self.is_install < 0:
146                 Logs.info('* removing %s', destpath)
147                 try:
148                         os.remove(destpath)
149                 except OSError:
150                         pass
151 Build.BuildContext.install_dir = install_dir
152
153 class ConfigurationContext(Configure.ConfigurationContext):
154     def init_dirs(self):
155         self.setenv('default')
156         self.env.merge_config_header = True
157         return super(ConfigurationContext, self).init_dirs()
158
159 def find_program_samba(self, *k, **kw):
160     kw['mandatory'] = False
161     ret = self.find_program_old(*k, **kw)
162     return ret
163 Configure.ConfigurationContext.find_program_old = Configure.ConfigurationContext.find_program
164 Configure.ConfigurationContext.find_program = find_program_samba
165
166 Build.BuildContext.ENFORCE_GROUP_ORDERING = Utils.nada
167 Build.BuildContext.AUTOCLEANUP_STALE_FILES = Utils.nada
168
169 @conf
170 def check(self, *k, **kw):
171     '''Override the waf defaults to inject --with-directory options'''
172
173     # match the configuration test with speficic options, for example:
174     # --with-libiconv -> Options.options.iconv_open -> "Checking for library iconv"
175     self.validate_c(kw)
176
177     additional_dirs = []
178     if 'msg' in kw:
179         msg = kw['msg']
180         for x in Options.OptionsContext.parser.parser.option_list:
181              if getattr(x, 'match', None) and msg in x.match:
182                  d = getattr(Options.options, x.dest, '')
183                  if d:
184                      additional_dirs.append(d)
185
186     # we add the additional dirs twice: once for the test data, and again if the compilation test suceeds below
187     def add_options_dir(dirs, env):
188         for x in dirs:
189              if not x in env.CPPPATH:
190                  env.CPPPATH = [os.path.join(x, 'include')] + env.CPPPATH
191              if not x in env.LIBPATH:
192                  env.LIBPATH = [os.path.join(x, 'lib')] + env.LIBPATH
193
194     add_options_dir(additional_dirs, kw['env'])
195
196     self.start_msg(kw['msg'], **kw)
197     ret = None
198     try:
199         ret = self.run_build(*k, **kw)
200     except self.errors.ConfigurationError:
201         self.end_msg(kw['errmsg'], 'YELLOW', **kw)
202         if Logs.verbose > 1:
203             raise
204         else:
205             self.fatal('The configuration failed')
206     else:
207         kw['success'] = ret
208         # success! time for brandy
209         add_options_dir(additional_dirs, self.env)
210
211     ret = self.post_check(*k, **kw)
212     if not ret:
213         self.end_msg(kw['errmsg'], 'YELLOW', **kw)
214         self.fatal('The configuration failed %r' % ret)
215     else:
216         self.end_msg(self.ret_msg(kw['okmsg'], kw), **kw)
217     return ret
218
219 @conf
220 def CHECK_LIBRARY_SUPPORT(conf, rpath=False, version_script=False, msg=None):
221     '''see if the platform supports building libraries'''
222
223     if msg is None:
224         if rpath:
225             msg = "rpath library support"
226         else:
227             msg = "building library support"
228
229     def build(bld):
230         lib_node = bld.srcnode.make_node('libdir/liblc1.c')
231         lib_node.parent.mkdir()
232         lib_node.write('int lib_func(void) { return 42; }\n', 'w')
233         main_node = bld.srcnode.make_node('main.c')
234         main_node.write('int main(void) {return !(lib_func() == 42);}', 'w')
235         linkflags = []
236         if version_script:
237             script = bld.srcnode.make_node('ldscript')
238             script.write('TEST_1.0A2 { global: *; };\n', 'w')
239             linkflags.append('-Wl,--version-script=%s' % script.abspath())
240         bld(features='c cshlib', source=lib_node, target='lib1', linkflags=linkflags, name='lib1')
241         o = bld(features='c cprogram', source=main_node, target='prog1', uselib_local='lib1')
242         if rpath:
243             o.rpath = [lib_node.parent.abspath()]
244         def run_app(self):
245              args = conf.SAMBA_CROSS_ARGS(msg=msg)
246              env = dict(os.environ)
247              env['LD_LIBRARY_PATH'] = self.inputs[0].parent.abspath() + os.pathsep + env.get('LD_LIBRARY_PATH', '')
248              self.generator.bld.cmd_and_log([self.inputs[0].abspath()] + args, env=env)
249         o.post()
250         bld(rule=run_app, source=o.link_task.outputs[0])
251
252     # ok, so it builds
253     try:
254         conf.check(build_fun=build, msg='Checking for %s' % msg)
255     except conf.errors.ConfigurationError:
256         return False
257     return True
258
259 @conf
260 def CHECK_NEED_LC(conf, msg):
261     '''check if we need -lc'''
262     def build(bld):
263         lib_node = bld.srcnode.make_node('libdir/liblc1.c')
264         lib_node.parent.mkdir()
265         lib_node.write('#include <stdio.h>\nint lib_func(void) { FILE *f = fopen("foo", "r");}\n', 'w')
266         bld(features='c cshlib', source=[lib_node], linkflags=conf.env.EXTRA_LDFLAGS, target='liblc')
267     try:
268         conf.check(build_fun=build, msg=msg, okmsg='-lc is unnecessary', errmsg='-lc is necessary')
269     except conf.errors.ConfigurationError:
270         return False
271     return True
272
273 # already implemented on "waf -v"
274 def order(bld, tgt_list):
275     return True
276 Build.BuildContext.check_group_ordering = order
277
278 @conf
279 def CHECK_CFG(self, *k, **kw):
280     if 'args' in kw:
281         kw['args'] = shlex.split(kw['args'])
282     if not 'mandatory' in kw:
283         kw['mandatory'] = False
284     kw['global_define'] = True
285     return self.check_cfg(*k, **kw)
286
287 def cmd_output(cmd, **kw):
288
289     silent = False
290     if 'silent' in kw:
291         silent = kw['silent']
292         del(kw['silent'])
293
294     if 'e' in kw:
295         tmp = kw['e']
296         del(kw['e'])
297         kw['env'] = tmp
298
299     kw['shell'] = isinstance(cmd, str)
300     kw['stdout'] = Utils.subprocess.PIPE
301     if silent:
302         kw['stderr'] = Utils.subprocess.PIPE
303
304     try:
305         p = Utils.subprocess.Popen(cmd, **kw)
306         output = p.communicate()[0]
307     except OSError as e:
308         raise ValueError(str(e))
309
310     if p.returncode:
311         if not silent:
312             msg = "command execution failed: %s -> %r" % (cmd, str(output))
313             raise ValueError(msg)
314         output = ''
315     return output
316 Utils.cmd_output = cmd_output
317
318
319 @TaskGen.feature('c', 'cxx', 'd')
320 @TaskGen.before('apply_incpaths', 'propagate_uselib_vars')
321 @TaskGen.after('apply_link', 'process_source')
322 def apply_uselib_local(self):
323     """
324     process the uselib_local attribute
325     execute after apply_link because of the execution order set on 'link_task'
326     """
327     env = self.env
328     from waflib.Tools.ccroot import stlink_task
329
330     # 1. the case of the libs defined in the project (visit ancestors first)
331     # the ancestors external libraries (uselib) will be prepended
332     self.uselib = self.to_list(getattr(self, 'uselib', []))
333     self.includes = self.to_list(getattr(self, 'includes', []))
334     names = self.to_list(getattr(self, 'uselib_local', []))
335     get = self.bld.get_tgen_by_name
336     seen = set()
337     seen_uselib = set()
338     tmp = Utils.deque(names) # consume a copy of the list of names
339     if tmp:
340         if Logs.verbose:
341             Logs.warn('compat: "uselib_local" is deprecated, replace by "use"')
342     while tmp:
343         lib_name = tmp.popleft()
344         # visit dependencies only once
345         if lib_name in seen:
346             continue
347
348         y = get(lib_name)
349         y.post()
350         seen.add(lib_name)
351
352         # object has ancestors to process (shared libraries): add them to the end of the list
353         if getattr(y, 'uselib_local', None):
354             for x in self.to_list(getattr(y, 'uselib_local', [])):
355                 obj = get(x)
356                 obj.post()
357                 if getattr(obj, 'link_task', None):
358                     if not isinstance(obj.link_task, stlink_task):
359                         tmp.append(x)
360
361         # link task and flags
362         if getattr(y, 'link_task', None):
363
364             link_name = y.target[y.target.rfind(os.sep) + 1:]
365             if isinstance(y.link_task, stlink_task):
366                 env.append_value('STLIB', [link_name])
367             else:
368                 # some linkers can link against programs
369                 env.append_value('LIB', [link_name])
370
371             # the order
372             self.link_task.set_run_after(y.link_task)
373
374             # for the recompilation
375             self.link_task.dep_nodes += y.link_task.outputs
376
377             # add the link path too
378             tmp_path = y.link_task.outputs[0].parent.bldpath()
379             if not tmp_path in env['LIBPATH']:
380                 env.prepend_value('LIBPATH', [tmp_path])
381
382         # add ancestors uselib too - but only propagate those that have no staticlib defined
383         for v in self.to_list(getattr(y, 'uselib', [])):
384             if v not in seen_uselib:
385                 seen_uselib.add(v)
386                 if not env['STLIB_' + v]:
387                     if not v in self.uselib:
388                         self.uselib.insert(0, v)
389
390         # if the library task generator provides 'export_includes', add to the include path
391         # the export_includes must be a list of paths relative to the other library
392         if getattr(y, 'export_includes', None):
393             self.includes.extend(y.to_incnodes(y.export_includes))
394
395 @TaskGen.feature('cprogram', 'cxxprogram', 'cstlib', 'cxxstlib', 'cshlib', 'cxxshlib', 'dprogram', 'dstlib', 'dshlib')
396 @TaskGen.after('apply_link')
397 def apply_objdeps(self):
398     "add the .o files produced by some other object files in the same manner as uselib_local"
399     names = getattr(self, 'add_objects', [])
400     if not names:
401         return
402     names = self.to_list(names)
403
404     get = self.bld.get_tgen_by_name
405     seen = []
406     while names:
407         x = names[0]
408
409         # visit dependencies only once
410         if x in seen:
411             names = names[1:]
412             continue
413
414         # object does not exist ?
415         y = get(x)
416
417         # object has ancestors to process first ? update the list of names
418         if getattr(y, 'add_objects', None):
419             added = 0
420             lst = y.to_list(y.add_objects)
421             lst.reverse()
422             for u in lst:
423                 if u in seen:
424                     continue
425                 added = 1
426                 names = [u]+names
427             if added:
428                 continue # list of names modified, loop
429
430         # safe to process the current object
431         y.post()
432         seen.append(x)
433
434         for t in getattr(y, 'compiled_tasks', []):
435             self.link_task.inputs.extend(t.outputs)
436
437 @TaskGen.after('apply_link')
438 def process_obj_files(self):
439     if not hasattr(self, 'obj_files'):
440         return
441     for x in self.obj_files:
442         node = self.path.find_resource(x)
443         self.link_task.inputs.append(node)
444
445 @TaskGen.taskgen_method
446 def add_obj_file(self, file):
447     """Small example on how to link object files as if they were source
448     obj = bld.create_obj('cc')
449     obj.add_obj_file('foo.o')"""
450     if not hasattr(self, 'obj_files'):
451         self.obj_files = []
452     if not 'process_obj_files' in self.meths:
453         self.meths.append('process_obj_files')
454     self.obj_files.append(file)