1 # compatibility layer for building with more recent waf versions
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
9 from waflib
.Tools
.flex
import decide_ext
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.
16 bld
= tsk
.generator
.bld
18 if isinstance(xx
, str):
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
]
26 inputs
= [x
.replace(os
.sep
, '/') for x
in 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
32 TaskGen
.declare_chain(
34 rule
= flexfun
, # issue #854
40 for y
in (Build
.BuildContext
, Build
.CleanContext
, Build
.InstallContext
, Build
.UninstallContext
, Build
.ListContext
):
45 self
.cwdx
= self
.bldnode
.parent
46 self
.cwd
= self
.cwdx
.abspath()
47 return Build
.BuildContext
.old_pre_build(self
)
48 Build
.BuildContext
.old_pre_build
= Build
.BuildContext
.pre_build
49 Build
.BuildContext
.pre_build
= pre_build
51 def abspath(self
, env
=None):
52 if env
and hasattr(self
, 'children'):
53 return self
.get_bld().abspath()
54 return self
.old_abspath()
55 Node
.Node
.old_abspath
= Node
.Node
.abspath
56 Node
.Node
.abspath
= abspath
58 def bldpath(self
, env
=None):
60 #return self.path_from(self.ctx.bldnode.parent)
61 Node
.Node
.bldpath
= bldpath
63 def srcpath(self
, env
=None):
65 #return self.path_from(self.ctx.bldnode.parent)
66 Node
.Node
.srcpath
= srcpath
68 def store_fast(self
, filename
):
69 file = open(filename
, 'wb')
70 data
= self
.get_merged_dict()
72 Build
.cPickle
.dump(data
, file, -1)
75 ConfigSet
.ConfigSet
.store_fast
= store_fast
77 def load_fast(self
, filename
):
78 file = open(filename
, 'rb')
80 data
= Build
.cPickle
.load(file)
83 self
.table
.update(data
)
84 ConfigSet
.ConfigSet
.load_fast
= load_fast
86 @feature('c', 'cxx', 'd', 'asm', 'fc', 'includes')
87 @after('propagate_uselib_vars', 'process_source')
88 def apply_incpaths(self
):
89 lst
= self
.to_incnodes(self
.to_list(getattr(self
, 'includes', [])) + self
.env
['INCLUDES'])
90 self
.includes_nodes
= lst
91 cwdx
= getattr(self
.bld
, 'cwdx', self
.bld
.bldnode
)
92 self
.env
['INCPATHS'] = [x
.path_from(cwdx
) for x
in lst
]
95 def define(self
, key
, val
, quote
=True, comment
=None):
96 assert key
and isinstance(key
, str)
100 elif isinstance(val
, bool):
106 if isinstance(val
, int) or isinstance(val
, float):
109 s
= quote
and '%s="%s"' or '%s=%s'
110 app
= s
% (key
, str(val
))
113 lst
= self
.env
.DEFINES
115 if x
.startswith(ban
):
116 lst
[lst
.index(x
)] = app
119 self
.env
.append_value('DEFINES', app
)
121 self
.env
.append_unique('define_key', key
)
123 # compat15 removes this but we want to keep it
125 def undefine(self
, key
, from_env
=True, comment
=None):
126 assert key
and isinstance(key
, str)
129 self
.env
.DEFINES
= [x
for x
in self
.env
.DEFINES
if not x
.startswith(ban
)]
130 self
.env
.append_unique('define_key', key
)
135 class ConfigurationContext(Configure
.ConfigurationContext
):
137 self
.setenv('default')
138 self
.env
.merge_config_header
= True
139 return super(ConfigurationContext
, self
).init_dirs()
141 def find_program_samba(self
, *k
, **kw
):
142 kw
['mandatory'] = False
143 ret
= self
.find_program_old(*k
, **kw
)
145 Configure
.ConfigurationContext
.find_program_old
= Configure
.ConfigurationContext
.find_program
146 Configure
.ConfigurationContext
.find_program
= find_program_samba
148 Build
.BuildContext
.ENFORCE_GROUP_ORDERING
= Utils
.nada
149 Build
.BuildContext
.AUTOCLEANUP_STALE_FILES
= Utils
.nada
152 def check(self
, *k
, **kw
):
153 '''Override the waf defaults to inject --with-directory options'''
155 # match the configuration test with speficic options, for example:
156 # --with-libiconv -> Options.options.iconv_open -> "Checking for library iconv"
162 for x
in Options
.OptionsContext
.parser
.parser
.option_list
:
163 if getattr(x
, 'match', None) and msg
in x
.match
:
164 d
= getattr(Options
.options
, x
.dest
, '')
166 additional_dirs
.append(d
)
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
):
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
176 add_options_dir(additional_dirs
, kw
['env'])
178 self
.start_msg(kw
['msg'], **kw
)
181 ret
= self
.run_build(*k
, **kw
)
182 except self
.errors
.ConfigurationError
:
183 self
.end_msg(kw
['errmsg'], 'YELLOW', **kw
)
187 self
.fatal('The configuration failed')
190 # success! time for brandy
191 add_options_dir(additional_dirs
, self
.env
)
193 ret
= self
.post_check(*k
, **kw
)
195 self
.end_msg(kw
['errmsg'], 'YELLOW', **kw
)
196 self
.fatal('The configuration failed %r' % ret
)
198 self
.end_msg(self
.ret_msg(kw
['okmsg'], kw
), **kw
)
202 def CHECK_LIBRARY_SUPPORT(conf
, rpath
=False, version_script
=False, msg
=None):
203 '''see if the platform supports building libraries'''
207 msg
= "rpath library support"
209 msg
= "building library support"
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')
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')
225 o
.rpath
= [lib_node
.parent
.abspath()]
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
)
232 bld(rule
=run_app
, source
=o
.link_task
.outputs
[0])
236 conf
.check(build_fun
=build
, msg
='Checking for %s' % msg
)
237 except conf
.errors
.ConfigurationError
:
242 def CHECK_NEED_LC(conf
, msg
):
243 '''check if we need -lc'''
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')
250 conf
.check(build_fun
=build
, msg
=msg
, okmsg
='-lc is unnecessary', errmsg
='-lc is necessary')
251 except conf
.errors
.ConfigurationError
:
255 # already implemented on "waf -v"
256 def order(bld
, tgt_list
):
258 Build
.BuildContext
.check_group_ordering
= order
261 def CHECK_CFG(self
, *k
, **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
)
269 def cmd_output(cmd
, **kw
):
273 silent
= kw
['silent']
281 kw
['shell'] = isinstance(cmd
, str)
282 kw
['stdout'] = Utils
.subprocess
.PIPE
284 kw
['stderr'] = Utils
.subprocess
.PIPE
287 p
= Utils
.subprocess
.Popen(cmd
, **kw
)
288 output
= p
.communicate()[0]
290 raise ValueError(str(e
))
294 msg
= "command execution failed: %s -> %r" % (cmd
, str(output
))
295 raise ValueError(msg
)
298 Utils
.cmd_output
= cmd_output
301 @TaskGen.feature('c', 'cxx', 'd')
302 @TaskGen.before('apply_incpaths', 'propagate_uselib_vars')
303 @TaskGen.after('apply_link', 'process_source')
304 def apply_uselib_local(self
):
306 process the uselib_local attribute
307 execute after apply_link because of the execution order set on 'link_task'
310 from waflib
.Tools
.ccroot
import stlink_task
312 # 1. the case of the libs defined in the project (visit ancestors first)
313 # the ancestors external libraries (uselib) will be prepended
314 self
.uselib
= self
.to_list(getattr(self
, 'uselib', []))
315 self
.includes
= self
.to_list(getattr(self
, 'includes', []))
316 names
= self
.to_list(getattr(self
, 'uselib_local', []))
317 get
= self
.bld
.get_tgen_by_name
320 tmp
= Utils
.deque(names
) # consume a copy of the list of names
323 Logs
.warn('compat: "uselib_local" is deprecated, replace by "use"')
325 lib_name
= tmp
.popleft()
326 # visit dependencies only once
334 # object has ancestors to process (shared libraries): add them to the end of the list
335 if getattr(y
, 'uselib_local', None):
336 for x
in self
.to_list(getattr(y
, 'uselib_local', [])):
339 if getattr(obj
, 'link_task', None):
340 if not isinstance(obj
.link_task
, stlink_task
):
343 # link task and flags
344 if getattr(y
, 'link_task', None):
346 link_name
= y
.target
[y
.target
.rfind(os
.sep
) + 1:]
347 if isinstance(y
.link_task
, stlink_task
):
348 env
.append_value('STLIB', [link_name
])
350 # some linkers can link against programs
351 env
.append_value('LIB', [link_name
])
354 self
.link_task
.set_run_after(y
.link_task
)
356 # for the recompilation
357 self
.link_task
.dep_nodes
+= y
.link_task
.outputs
359 # add the link path too
360 tmp_path
= y
.link_task
.outputs
[0].parent
.bldpath()
361 if not tmp_path
in env
['LIBPATH']:
362 env
.prepend_value('LIBPATH', [tmp_path
])
364 # add ancestors uselib too - but only propagate those that have no staticlib defined
365 for v
in self
.to_list(getattr(y
, 'uselib', [])):
366 if v
not in seen_uselib
:
368 if not env
['STLIB_' + v
]:
369 if not v
in self
.uselib
:
370 self
.uselib
.insert(0, v
)
372 # if the library task generator provides 'export_includes', add to the include path
373 # the export_includes must be a list of paths relative to the other library
374 if getattr(y
, 'export_includes', None):
375 self
.includes
.extend(y
.to_incnodes(y
.export_includes
))
377 @TaskGen.feature('cprogram', 'cxxprogram', 'cstlib', 'cxxstlib', 'cshlib', 'cxxshlib', 'dprogram', 'dstlib', 'dshlib')
378 @TaskGen.after('apply_link')
379 def apply_objdeps(self
):
380 "add the .o files produced by some other object files in the same manner as uselib_local"
381 names
= getattr(self
, 'add_objects', [])
384 names
= self
.to_list(names
)
386 get
= self
.bld
.get_tgen_by_name
391 # visit dependencies only once
396 # object does not exist ?
399 # object has ancestors to process first ? update the list of names
400 if getattr(y
, 'add_objects', None):
402 lst
= y
.to_list(y
.add_objects
)
410 continue # list of names modified, loop
412 # safe to process the current object
416 for t
in getattr(y
, 'compiled_tasks', []):
417 self
.link_task
.inputs
.extend(t
.outputs
)
419 @TaskGen.after('apply_link')
420 def process_obj_files(self
):
421 if not hasattr(self
, 'obj_files'):
423 for x
in self
.obj_files
:
424 node
= self
.path
.find_resource(x
)
425 self
.link_task
.inputs
.append(node
)
427 @TaskGen.taskgen_method
428 def add_obj_file(self
, file):
429 """Small example on how to link object files as if they were source
430 obj = bld.create_obj('cc')
431 obj.add_obj_file('foo.o')"""
432 if not hasattr(self
, 'obj_files'):
434 if not 'process_obj_files' in self
.meths
:
435 self
.meths
.append('process_obj_files')
436 self
.obj_files
.append(file)