Imported Upstream version 2.1.2
[abartlet/talloc-debian.git] / third_party / waf / wafadmin / 3rdparty / swig.py
1 #! /usr/bin/env python
2 # encoding: UTF-8
3 # Petar Forai
4 # Thomas Nagy 2008
5
6 import re
7 import Task, Utils, Logs
8 from TaskGen import extension
9 from Configure import conf
10 import preproc
11
12 """
13 Welcome in the hell of adding tasks dynamically
14
15 swig interface files may be created at runtime, the module name may be unknown in advance
16
17 rev 5859 is much more simple
18 """
19
20 SWIG_EXTS = ['.swig', '.i']
21
22 swig_str = '${SWIG} ${SWIGFLAGS} ${_CCINCFLAGS} ${_CXXINCFLAGS} ${_CCDEFFLAGS} ${_CXXDEFFLAGS} ${SRC}'
23 cls = Task.simple_task_type('swig', swig_str, color='BLUE', ext_in='.i .h', ext_out='.o .c .cxx', shell=False)
24
25 def runnable_status(self):
26         for t in self.run_after:
27                 if not t.hasrun:
28                         return ASK_LATER
29
30         if not getattr(self, 'init_outputs', None):
31                 self.init_outputs = True
32                 if not getattr(self, 'module', None):
33                         # search the module name
34                         txt = self.inputs[0].read(self.env)
35                         m = re_module.search(txt)
36                         if not m:
37                                 raise ValueError("could not find the swig module name")
38                         self.module = m.group(1)
39
40                 swig_c(self)
41
42                 # add the language-specific output files as nodes
43                 # call funs in the dict swig_langs
44                 for x in self.env['SWIGFLAGS']:
45                         # obtain the language
46                         x = x[1:]
47                         try:
48                                 fun = swig_langs[x]
49                         except KeyError:
50                                 pass
51                         else:
52                                 fun(self)
53
54         return Task.Task.runnable_status(self)
55 setattr(cls, 'runnable_status', runnable_status)
56
57 re_module = re.compile('%module(?:\s*\(.*\))?\s+(.+)', re.M)
58
59 re_1 = re.compile(r'^%module.*?\s+([\w]+)\s*?$', re.M)
60 re_2 = re.compile('%include "(.*)"', re.M)
61 re_3 = re.compile('#include "(.*)"', re.M)
62
63 def scan(self):
64         "scan for swig dependencies, climb the .i files"
65         env = self.env
66
67         lst_src = []
68
69         seen = []
70         to_see = [self.inputs[0]]
71
72         while to_see:
73                 node = to_see.pop(0)
74                 if node.id in seen:
75                         continue
76                 seen.append(node.id)
77                 lst_src.append(node)
78
79                 # read the file
80                 code = node.read(env)
81                 code = preproc.re_nl.sub('', code)
82                 code = preproc.re_cpp.sub(preproc.repl, code)
83
84                 # find .i files and project headers
85                 names = re_2.findall(code) + re_3.findall(code)
86                 for n in names:
87                         for d in self.generator.env.INC_PATHS + [node.parent]:
88                                 u = d.find_resource(n)
89                                 if u:
90                                         to_see.append(u)
91                                         break
92                         else:
93                                 Logs.warn('could not find %r' % n)
94
95         # list of nodes this one depends on, and module name if present
96         if Logs.verbose:
97                 Logs.debug('deps: deps for %s: %s' % (str(self), str(lst_src)))
98         return (lst_src, [])
99 cls.scan = scan
100
101 # provide additional language processing
102 swig_langs = {}
103 def swig(fun):
104         swig_langs[fun.__name__.replace('swig_', '')] = fun
105
106 def swig_c(self):
107         ext = '.swigwrap_%d.c' % self.generator.idx
108         flags = self.env['SWIGFLAGS']
109         if '-c++' in flags:
110                 ext += 'xx'
111         out_node = self.inputs[0].parent.find_or_declare(self.module + ext)
112
113         try:
114                 if '-c++' in flags:
115                         fun = self.generator.cxx_hook
116                 else:
117                         fun = self.generator.c_hook
118         except AttributeError:
119                 raise Utils.WafError('No c%s compiler was found to process swig files' % ('-c++' in flags and '++' or ''))
120
121         task = fun(out_node)
122         task.set_run_after(self)
123
124         ge = self.generator.bld.generator
125         ge.outstanding.insert(0, task)
126         ge.total += 1
127
128         try:
129                 ltask = self.generator.link_task
130         except AttributeError:
131                 pass
132         else:
133                 ltask.inputs.append(task.outputs[0])
134
135         self.outputs.append(out_node)
136
137         if not '-o' in self.env['SWIGFLAGS']:
138                 self.env.append_value('SWIGFLAGS', '-o')
139                 self.env.append_value('SWIGFLAGS', self.outputs[0].abspath(self.env))
140
141 @swig
142 def swig_python(tsk):
143         tsk.set_outputs(tsk.inputs[0].parent.find_or_declare(tsk.module + '.py'))
144
145 @swig
146 def swig_ocaml(tsk):
147         tsk.set_outputs(tsk.inputs[0].parent.find_or_declare(tsk.module + '.ml'))
148         tsk.set_outputs(tsk.inputs[0].parent.find_or_declare(tsk.module + '.mli'))
149
150 @extension(SWIG_EXTS)
151 def i_file(self, node):
152         # the task instance
153         tsk = self.create_task('swig')
154         tsk.set_inputs(node)
155         tsk.module = getattr(self, 'swig_module', None)
156
157         flags = self.to_list(getattr(self, 'swig_flags', []))
158         self.env.append_value('SWIGFLAGS', flags)
159
160         if not '-outdir' in flags:
161                 flags.append('-outdir')
162                 flags.append(node.parent.abspath(self.env))
163
164 @conf
165 def check_swig_version(conf, minver=None):
166         """Check for a minimum swig version like conf.check_swig_version('1.3.28')
167         or conf.check_swig_version((1,3,28)) """
168         reg_swig = re.compile(r'SWIG Version\s(.*)', re.M)
169
170         swig_out = Utils.cmd_output('%s -version' % conf.env['SWIG'])
171
172         swigver = [int(s) for s in reg_swig.findall(swig_out)[0].split('.')]
173         if isinstance(minver, basestring):
174                 minver = [int(s) for s in minver.split(".")]
175         if isinstance(minver, tuple):
176                 minver = [int(s) for s in minver]
177         result = (minver is None) or (minver[:3] <= swigver[:3])
178         swigver_full = '.'.join(map(str, swigver))
179         if result:
180                 conf.env['SWIG_VERSION'] = swigver_full
181         minver_str = '.'.join(map(str, minver))
182         if minver is None:
183                 conf.check_message_custom('swig version', '', swigver_full)
184         else:
185                 conf.check_message('swig version', '>= %s' % (minver_str,), result, option=swigver_full)
186         return result
187
188 def detect(conf):
189         swig = conf.find_program('swig', var='SWIG', mandatory=True)