third_party:waf: update to upstream 2.0.4 release
[amitay/samba.git] / third_party / waf / waflib / extras / swig.py
1 #! /usr/bin/env python
2 # encoding: utf-8
3 # WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
4
5 #! /usr/bin/env python
6 # encoding: UTF-8
7 # Petar Forai
8 # Thomas Nagy 2008-2010 (ita)
9
10 import re
11 from waflib import Task, Logs
12 from waflib.TaskGen import extension, feature, after_method
13 from waflib.Configure import conf
14 from waflib.Tools import c_preproc
15
16 """
17 tasks have to be added dynamically:
18 - swig interface files may be created at runtime
19 - the module name may be unknown in advance
20 """
21
22 SWIG_EXTS = ['.swig', '.i']
23
24 re_module = re.compile('%module(?:\s*\(.*\))?\s+(.+)', re.M)
25
26 re_1 = re.compile(r'^%module.*?\s+([\w]+)\s*?$', re.M)
27 re_2 = re.compile('[#%]include [<"](.*)[">]', re.M)
28
29 class swig(Task.Task):
30         color   = 'BLUE'
31         run_str = '${SWIG} ${SWIGFLAGS} ${SWIGPATH_ST:INCPATHS} ${SWIGDEF_ST:DEFINES} ${SRC}'
32         ext_out = ['.h'] # might produce .h files although it is not mandatory
33         vars = ['SWIG_VERSION', 'SWIGDEPS']
34
35         def runnable_status(self):
36                 for t in self.run_after:
37                         if not t.hasrun:
38                                 return Task.ASK_LATER
39
40                 if not getattr(self, 'init_outputs', None):
41                         self.init_outputs = True
42                         if not getattr(self, 'module', None):
43                                 # search the module name
44                                 txt = self.inputs[0].read()
45                                 m = re_module.search(txt)
46                                 if not m:
47                                         raise ValueError("could not find the swig module name")
48                                 self.module = m.group(1)
49
50                         swig_c(self)
51
52                         # add the language-specific output files as nodes
53                         # call funs in the dict swig_langs
54                         for x in self.env['SWIGFLAGS']:
55                                 # obtain the language
56                                 x = x[1:]
57                                 try:
58                                         fun = swig_langs[x]
59                                 except KeyError:
60                                         pass
61                                 else:
62                                         fun(self)
63
64                 return super(swig, self).runnable_status()
65
66         def scan(self):
67                 "scan for swig dependencies, climb the .i files"
68                 lst_src = []
69
70                 seen = []
71                 missing = []
72                 to_see = [self.inputs[0]]
73
74                 while to_see:
75                         node = to_see.pop(0)
76                         if node in seen:
77                                 continue
78                         seen.append(node)
79                         lst_src.append(node)
80
81                         # read the file
82                         code = node.read()
83                         code = c_preproc.re_nl.sub('', code)
84                         code = c_preproc.re_cpp.sub(c_preproc.repl, code)
85
86                         # find .i files and project headers
87                         names = re_2.findall(code)
88                         for n in names:
89                                 for d in self.generator.includes_nodes + [node.parent]:
90                                         u = d.find_resource(n)
91                                         if u:
92                                                 to_see.append(u)
93                                                 break
94                                 else:
95                                         missing.append(n)
96                 return (lst_src, missing)
97
98 # provide additional language processing
99 swig_langs = {}
100 def swigf(fun):
101         swig_langs[fun.__name__.replace('swig_', '')] = fun
102         return fun
103 swig.swigf = swigf
104
105 def swig_c(self):
106         ext = '.swigwrap_%d.c' % self.generator.idx
107         flags = self.env['SWIGFLAGS']
108         if '-c++' in flags:
109                 ext += 'xx'
110         out_node = self.inputs[0].parent.find_or_declare(self.module + ext)
111
112         if '-c++' in flags:
113                 c_tsk = self.generator.cxx_hook(out_node)
114         else:
115                 c_tsk = self.generator.c_hook(out_node)
116
117         c_tsk.set_run_after(self)
118
119         ge = self.generator.bld.producer
120         ge.outstanding.append(c_tsk)
121         ge.total += 1
122
123         try:
124                 ltask = self.generator.link_task
125         except AttributeError:
126                 pass
127         else:
128                 ltask.set_run_after(c_tsk)
129                 # setting input nodes does not declare the build order
130                 # because the build already started
131                 ltask.inputs.append(c_tsk.outputs[0])
132                 # set the build order after the build started:
133                 ge.revdeps[c_tsk].add(ltask)
134
135         self.outputs.append(out_node)
136
137         if not '-o' in self.env['SWIGFLAGS']:
138                 self.env.append_value('SWIGFLAGS', ['-o', self.outputs[0].abspath()])
139
140 @swigf
141 def swig_python(tsk):
142         node = tsk.inputs[0].parent
143         if tsk.outdir:
144                 node = tsk.outdir
145         tsk.set_outputs(node.find_or_declare(tsk.module+'.py'))
146
147 @swigf
148 def swig_ocaml(tsk):
149         node = tsk.inputs[0].parent
150         if tsk.outdir:
151                 node = tsk.outdir
152         tsk.set_outputs(node.find_or_declare(tsk.module+'.ml'))
153         tsk.set_outputs(node.find_or_declare(tsk.module+'.mli'))
154
155 @extension(*SWIG_EXTS)
156 def i_file(self, node):
157         # the task instance
158         tsk = self.create_task('swig')
159         tsk.set_inputs(node)
160         tsk.module = getattr(self, 'swig_module', None)
161
162         flags = self.to_list(getattr(self, 'swig_flags', []))
163         tsk.env.append_value('SWIGFLAGS', flags)
164
165         tsk.outdir = None
166         if '-outdir' in flags:
167                 outdir = flags[flags.index('-outdir')+1]
168                 outdir = tsk.generator.bld.bldnode.make_node(outdir)
169                 outdir.mkdir()
170                 tsk.outdir = outdir
171
172 @feature('c', 'cxx', 'd', 'fc', 'asm')
173 @after_method('apply_link', 'process_source')
174 def enforce_swig_before_link(self):
175         try:
176                 link_task = self.link_task
177         except AttributeError:
178                 pass
179         else:
180                 for x in self.tasks:
181                         if x.__class__.__name__ == 'swig':
182                                 link_task.run_after.add(x)
183
184 @conf
185 def check_swig_version(conf, minver=None):
186         """
187         Check if the swig tool is found matching a given minimum version.
188         minver should be a tuple, eg. to check for swig >= 1.3.28 pass (1,3,28) as minver.
189
190         If successful, SWIG_VERSION is defined as 'MAJOR.MINOR'
191         (eg. '1.3') of the actual swig version found.
192
193         :param minver: minimum version
194         :type minver: tuple of int
195         :return: swig version
196         :rtype: tuple of int
197         """
198         assert minver is None or isinstance(minver, tuple)
199         swigbin = conf.env['SWIG']
200         if not swigbin:
201                 conf.fatal('could not find the swig executable')
202
203         # Get swig version string
204         cmd = swigbin + ['-version']
205         Logs.debug('swig: Running swig command %r', cmd)
206         reg_swig = re.compile(r'SWIG Version\s(.*)', re.M)
207         swig_out = conf.cmd_and_log(cmd)
208         swigver_tuple = tuple([int(s) for s in reg_swig.findall(swig_out)[0].split('.')])
209
210         # Compare swig version with the minimum required
211         result = (minver is None) or (swigver_tuple >= minver)
212
213         if result:
214                 # Define useful environment variables
215                 swigver = '.'.join([str(x) for x in swigver_tuple[:2]])
216                 conf.env['SWIG_VERSION'] = swigver
217
218         # Feedback
219         swigver_full = '.'.join(map(str, swigver_tuple[:3]))
220         if minver is None:
221                 conf.msg('Checking for swig version', swigver_full)
222         else:
223                 minver_str = '.'.join(map(str, minver))
224                 conf.msg('Checking for swig version >= %s' % (minver_str,), swigver_full, color=result and 'GREEN' or 'YELLOW')
225
226         if not result:
227                 conf.fatal('The swig version is too old, expecting %r' % (minver,))
228
229         return swigver_tuple
230
231 def configure(conf):
232         conf.find_program('swig', var='SWIG')
233         conf.env.SWIGPATH_ST = '-I%s'
234         conf.env.SWIGDEF_ST = '-D%s'
235