6c3523efa627d441ee5f6a63e1a19c1c67bec919
[samba.git] / buildtools / wafsamba / samba_waf18.py
1 # compatibility layer for building with more recent waf versions
2
3 import os, shlex, sys
4 import Build, Configure, Node, Utils, Options, Logs
5 from waflib import ConfigSet
6 from TaskGen import feature, after
7 from Configure import conf, ConfigurationContext
8
9 from waflib.Tools import bison, flex
10 sys.modules['bison'] = bison
11 sys.modules['flex'] = flex
12
13 for y in (Build.BuildContext, Build.CleanContext, Build.InstallContext, Build.UninstallContext, Build.ListContext):
14     class tmp(y):
15         variant = 'default'
16
17 def pre_build(self):
18     self.cwdx = self.bldnode.parent
19     self.cwd = self.cwdx.abspath()
20     self.bdir = self.bldnode.abspath()
21     return Build.BuildContext.old_pre_build(self)
22 Build.BuildContext.old_pre_build = Build.BuildContext.pre_build
23 Build.BuildContext.pre_build = pre_build
24
25 def abspath(self, env=None):
26     if env and hasattr(self, 'children'):
27         return self.get_bld().abspath()
28     return self.old_abspath()
29 Node.Node.old_abspath = Node.Node.abspath
30 Node.Node.abspath = abspath
31
32 def bldpath(self, env=None):
33     return self.abspath()
34     #return self.path_from(self.ctx.bldnode.parent)
35 Node.Node.bldpath = bldpath
36
37 def srcpath(self, env=None):
38     return self.abspath()
39     #return self.path_from(self.ctx.bldnode.parent)
40 Node.Node.srcpath = srcpath
41
42 def store_fast(self, filename):
43     file = open(filename, 'wb')
44     data = self.get_merged_dict()
45     try:
46         Build.cPickle.dump(data, file, -1)
47     finally:
48         file.close()
49 ConfigSet.ConfigSet.store_fast = store_fast
50
51 def load_fast(self, filename):
52     file = open(filename, 'rb')
53     try:
54         data = Build.cPickle.load(file)
55     finally:
56         file.close()
57     self.table.update(data)
58 ConfigSet.ConfigSet.load_fast = load_fast
59
60 @feature('c', 'cxx', 'd', 'asm', 'fc', 'includes')
61 @after('propagate_uselib_vars', 'process_source')
62 def apply_incpaths(self):
63     lst = self.to_incnodes(self.to_list(getattr(self, 'includes', [])) + self.env['INCLUDES'])
64     self.includes_nodes = lst
65     cwdx = getattr(self.bld, 'cwdx', self.bld.bldnode)
66     self.env['INCPATHS'] = [x.path_from(cwdx) for x in lst]
67
68 @conf
69 def define(self, key, val, quote=True, comment=None):
70    assert key and isinstance(key, str)
71
72    if val is True:
73            val = 1
74    elif val in (False, None):
75            val = 0
76
77    # waf 1.5
78    self.env[key] = val
79
80    if isinstance(val, int) or isinstance(val, float):
81            s = '%s=%s'
82    else:
83            s = quote and '%s="%s"' or '%s=%s'
84    app = s % (key, str(val))
85
86    ban = key + '='
87    lst = self.env.DEFINES
88    for x in lst:
89            if x.startswith(ban):
90                    lst[lst.index(x)] = app
91                    break
92    else:
93            self.env.append_value('DEFINES', app)
94
95    self.env.append_unique('define_key', key)
96
97 # compat15 removes this but we want to keep it
98 @conf
99 def undefine(self, key, from_env=True, comment=None):
100     assert key and isinstance(key, str)
101
102     ban = key + '='
103     self.env.DEFINES = [x for x in self.env.DEFINES if not x.startswith(ban)]
104     self.env.append_unique('define_key', key)
105     # waf 1.5
106     if from_env:
107         self.env[key] = ()
108
109 class ConfigurationContext(Configure.ConfigurationContext):
110     def init_dirs(self):
111         self.setenv('default')
112         self.env.merge_config_header = True
113         return super(ConfigurationContext, self).init_dirs()
114
115 def find_program_samba(self, *k, **kw):
116     kw['mandatory'] = False
117     ret = self.find_program_old(*k, **kw)
118     return ret
119 Configure.ConfigurationContext.find_program_old = Configure.ConfigurationContext.find_program
120 Configure.ConfigurationContext.find_program = find_program_samba
121
122 def PROCESS_SEPARATE_RULE(self, rule):
123     ''' cause waf to process additional script based on `rule'.
124         You should have file named wscript_<stage>_rule in the current directory
125         where stage is either 'configure' or 'build'
126     '''
127     stage = ''
128     if isinstance(self, Configure.ConfigurationContext):
129         stage = 'configure'
130     elif isinstance(self, Build.BuildContext):
131         stage = 'build'
132     script = self.path.find_node('wscript_'+stage+'_'+rule)
133     if script:
134         txt = script.read()
135         bld = self
136         conf = self
137         ctx = self
138         dc = {'ctx': self, 'conf': self, 'bld': self}
139         if getattr(self.__class__, 'pre_recurse', None):
140             dc = self.pre_recurse(script)
141         exec(compile(txt, script.abspath(), 'exec'), dc)
142         if getattr(self.__class__, 'post_recurse', None):
143             dc = self.post_recurse(script)
144
145 Build.BuildContext.PROCESS_SEPARATE_RULE = PROCESS_SEPARATE_RULE
146 ConfigurationContext.PROCESS_SEPARATE_RULE = PROCESS_SEPARATE_RULE
147
148 Build.BuildContext.ENFORCE_GROUP_ORDERING = Utils.nada
149 Build.BuildContext.AUTOCLEANUP_STALE_FILES = Utils.nada
150
151 @conf
152 def check(self, *k, **kw):
153     '''Override the waf defaults to inject --with-directory options'''
154
155     # match the configuration test with speficic options, for example:
156     # --with-libiconv -> Options.options.iconv_open -> "Checking for library iconv"
157     self.validate_c(kw)
158
159     additional_dirs = []
160     if 'msg' in kw:
161         msg = kw['msg']
162         for x in Options.parser.parser.option_list:
163              if getattr(x, 'match', None) and msg in x.match:
164                  d = getattr(Options.options, x.dest, '')
165                  if d:
166                      additional_dirs.append(d)
167
168     # we add the additional dirs twice: once for the test data, and again if the compilation test suceeds below
169     def add_options_dir(dirs, env):
170         for x in dirs:
171              if not x in env.CPPPATH:
172                  env.CPPPATH = [os.path.join(x, 'include')] + env.CPPPATH
173              if not x in env.LIBPATH:
174                  env.LIBPATH = [os.path.join(x, 'lib')] + env.LIBPATH
175
176     add_options_dir(additional_dirs, kw['env'])
177
178     self.start_msg(kw['msg'], **kw)
179     ret = None
180     try:
181         ret = self.run_build(*k, **kw)
182     except self.errors.ConfigurationError:
183         self.end_msg(kw['errmsg'], 'YELLOW', **kw)
184         if Logs.verbose > 1:
185             raise
186         else:
187             self.fatal('The configuration failed')
188     else:
189         kw['success'] = ret
190         # success! time for brandy
191         add_options_dir(additional_dirs, self.env)
192
193     ret = self.post_check(*k, **kw)
194     if not ret:
195         self.end_msg(kw['errmsg'], 'YELLOW', **kw)
196         self.fatal('The configuration failed %r' % ret)
197     else:
198         self.end_msg(self.ret_msg(kw['okmsg'], kw), **kw)
199     return ret
200
201 @conf
202 def CHECK_LIBRARY_SUPPORT(conf, rpath=False, version_script=False, msg=None):
203     '''see if the platform supports building libraries'''
204
205     if msg is None:
206         if rpath:
207             msg = "rpath library support"
208         else:
209             msg = "building library support"
210
211     def build(bld):
212         lib_node = bld.srcnode.make_node('libdir/liblc1.c')
213         lib_node.parent.mkdir()
214         lib_node.write('int lib_func(void) { return 42; }\n', 'w')
215         main_node = bld.srcnode.make_node('main.c')
216         main_node.write('int main(void) {return !(lib_func() == 42);}', 'w')
217         linkflags = []
218         if version_script:
219             script = bld.srcnode.make_node('ldscript')
220             script.write('TEST_1.0A2 { global: *; };\n', 'w')
221             linkflags.append('-Wl,--version-script=%s' % script.abspath())
222         bld(features='c cshlib', source=lib_node, target='lib1', linkflags=linkflags, name='lib1')
223         o = bld(features='c cprogram', source=main_node, target='prog1', uselib_local='lib1')
224         if rpath:
225             o.rpath = [lib_node.parent.abspath()]
226         def run_app(self):
227              args = conf.SAMBA_CROSS_ARGS(msg=msg)
228              env = dict(os.environ)
229              env['LD_LIBRARY_PATH'] = self.inputs[0].parent.abspath() + os.pathsep + env.get('LD_LIBRARY_PATH', '')
230              self.generator.bld.cmd_and_log([self.inputs[0].abspath()] + args, env=env)
231         o.post()
232         bld(rule=run_app, source=o.link_task.outputs[0])
233
234     # ok, so it builds
235     try:
236         conf.check(build_fun=build, msg='Checking for %s' % msg)
237     except conf.errors.ConfigurationError:
238         return False
239     return True
240
241 @conf
242 def CHECK_NEED_LC(conf, msg):
243     '''check if we need -lc'''
244     def build(bld):
245         lib_node = bld.srcnode.make_node('libdir/liblc1.c')
246         lib_node.parent.mkdir()
247         lib_node.write('#include <stdio.h>\nint lib_func(void) { FILE *f = fopen("foo", "r");}\n', 'w')
248         bld(features='c cshlib', source=[lib_node], linkflags=conf.env.EXTRA_LDFLAGS, target='liblc')
249     try:
250         conf.check(build_fun=build, msg=msg, okmsg='-lc is unnecessary', errmsg='-lc is necessary')
251     except conf.errors.ConfigurationError:
252         return False
253     return True
254
255 # already implemented on "waf -v"
256 def order(bld, tgt_list):
257     return True
258 Build.BuildContext.check_group_ordering = order
259
260 @conf
261 def CHECK_CFG(self, *k, **kw):
262     if 'args' in kw:
263         kw['args'] = shlex.split(kw['args'])
264     if not 'mandatory' in kw:
265         kw['mandatory'] = False
266     kw['global_define'] = True
267     return self.check_cfg(*k, **kw)