3 # WARNING! Do not edit! https://waf.io/book/index.html#_obtaining_the_waf_file
8 # Thomas Nagy 2008-2010 (ita)
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
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
22 SWIG_EXTS = ['.swig', '.i']
24 re_module = re.compile('%module(?:\s*\(.*\))?\s+(.+)', re.M)
26 re_1 = re.compile(r'^%module.*?\s+([\w]+)\s*?$', re.M)
27 re_2 = re.compile('[#%]include [<"](.*)[">]', re.M)
29 class swig(Task.Task):
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']
35 def runnable_status(self):
36 for t in self.run_after:
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)
47 raise ValueError("could not find the swig module name")
48 self.module = m.group(1)
52 # add the language-specific output files as nodes
53 # call funs in the dict swig_langs
54 for x in self.env['SWIGFLAGS']:
64 return super(swig, self).runnable_status()
67 "scan for swig dependencies, climb the .i files"
72 to_see = [self.inputs[0]]
83 code = c_preproc.re_nl.sub('', code)
84 code = c_preproc.re_cpp.sub(c_preproc.repl, code)
86 # find .i files and project headers
87 names = re_2.findall(code)
89 for d in self.generator.includes_nodes + [node.parent]:
90 u = d.find_resource(n)
96 return (lst_src, missing)
98 # provide additional language processing
101 swig_langs[fun.__name__.replace('swig_', '')] = fun
106 ext = '.swigwrap_%d.c' % self.generator.idx
107 flags = self.env['SWIGFLAGS']
110 out_node = self.inputs[0].parent.find_or_declare(self.module + ext)
113 c_tsk = self.generator.cxx_hook(out_node)
115 c_tsk = self.generator.c_hook(out_node)
117 c_tsk.set_run_after(self)
119 ge = self.generator.bld.producer
120 ge.outstanding.append(c_tsk)
124 ltask = self.generator.link_task
125 except AttributeError:
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)
135 self.outputs.append(out_node)
137 if not '-o' in self.env['SWIGFLAGS']:
138 self.env.append_value('SWIGFLAGS', ['-o', self.outputs[0].abspath()])
141 def swig_python(tsk):
142 node = tsk.inputs[0].parent
145 tsk.set_outputs(node.find_or_declare(tsk.module+'.py'))
149 node = tsk.inputs[0].parent
152 tsk.set_outputs(node.find_or_declare(tsk.module+'.ml'))
153 tsk.set_outputs(node.find_or_declare(tsk.module+'.mli'))
155 @extension(*SWIG_EXTS)
156 def i_file(self, node):
158 tsk = self.create_task('swig')
160 tsk.module = getattr(self, 'swig_module', None)
162 flags = self.to_list(getattr(self, 'swig_flags', []))
163 tsk.env.append_value('SWIGFLAGS', flags)
166 if '-outdir' in flags:
167 outdir = flags[flags.index('-outdir')+1]
168 outdir = tsk.generator.bld.bldnode.make_node(outdir)
172 @feature('c', 'cxx', 'd', 'fc', 'asm')
173 @after_method('apply_link', 'process_source')
174 def enforce_swig_before_link(self):
176 link_task = self.link_task
177 except AttributeError:
181 if x.__class__.__name__ == 'swig':
182 link_task.run_after.add(x)
185 def check_swig_version(conf, minver=None):
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.
190 If successful, SWIG_VERSION is defined as 'MAJOR.MINOR'
191 (eg. '1.3') of the actual swig version found.
193 :param minver: minimum version
194 :type minver: tuple of int
195 :return: swig version
198 assert minver is None or isinstance(minver, tuple)
199 swigbin = conf.env['SWIG']
201 conf.fatal('could not find the swig executable')
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('.')])
210 # Compare swig version with the minimum required
211 result = (minver is None) or (swigver_tuple >= minver)
214 # Define useful environment variables
215 swigver = '.'.join([str(x) for x in swigver_tuple[:2]])
216 conf.env['SWIG_VERSION'] = swigver
219 swigver_full = '.'.join(map(str, swigver_tuple[:3]))
221 conf.msg('Checking for swig version', swigver_full)
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')
227 conf.fatal('The swig version is too old, expecting %r' % (minver,))
232 conf.find_program('swig', var='SWIG')
233 conf.env.SWIGPATH_ST = '-I%s'
234 conf.env.SWIGDEF_ST = '-D%s'