1#! /usr/bin/env python
2# per rosengren 2011
3
4from waflib.TaskGen import feature, after_method
5from waflib.Task import Task, always_run
6from os.path import basename, isabs
7from os import tmpfile, linesep
8
9def options(opt):
10	grp = opt.add_option_group('Softlink Libraries Options')
11	grp.add_option('--exclude', default='/usr/lib,/lib', help='No symbolic links are created for libs within [%default]')
12
13def configure(cnf):
14	cnf.find_program('ldd')
15	if not cnf.env.SOFTLINK_EXCLUDE:
16		cnf.env.SOFTLINK_EXCLUDE = cnf.options.exclude.split(',')
17
18@feature('softlink_libs')
19@after_method('process_rule')
20def add_finder(self):
21	tgt = self.path.find_or_declare(self.target)
22	self.create_task('sll_finder', tgt=tgt)
23	self.create_task('sll_installer', tgt=tgt)
24	always_run(sll_installer)
25
26class sll_finder(Task):
27	ext_out = 'softlink_libs'
28	def run(self):
29		bld = self.generator.bld
30		linked=[]
31		target_paths = []
32		for g in bld.groups:
33			for tgen in g:
34				# FIXME it might be better to check if there is a link_task (getattr?)
35				target_paths += [tgen.path.get_bld().bldpath()]
36				linked += [t.outputs[0].bldpath()
37					for t in getattr(tgen, 'tasks', [])
38					if t.__class__.__name__ in
39					['cprogram', 'cshlib', 'cxxprogram', 'cxxshlib']]
40		lib_list = []
41		if len(linked):
42			cmd = [self.env.LDD] + linked
43			# FIXME add DYLD_LIBRARY_PATH+PATH for osx+win32
44			ldd_env = {'LD_LIBRARY_PATH': ':'.join(target_paths + self.env.LIBPATH)}
45			# FIXME the with syntax will not work in python 2
46			with tmpfile() as result:
47				self.exec_command(cmd, env=ldd_env, stdout=result)
48				result.seek(0)
49				for line in result.readlines():
50					words = line.split()
51					if len(words) < 3 or words[1] != '=>':
52						continue
53					lib = words[2]
54					if lib == 'not':
55						continue
56					if any([lib.startswith(p) for p in
57							[bld.bldnode.abspath(), '('] +
58							self.env.SOFTLINK_EXCLUDE]):
59						continue
60					if not isabs(lib):
61						continue
62					lib_list.append(lib)
63			lib_list = sorted(set(lib_list))
64		self.outputs[0].write(linesep.join(lib_list + self.env.DYNAMIC_LIBS))
65		return 0
66
67class sll_installer(Task):
68	ext_in = 'softlink_libs'
69	def run(self):
70		tgt = self.outputs[0]
71		self.generator.bld.install_files('${LIBDIR}', tgt, postpone=False)
72		lib_list=tgt.read().split()
73		for lib in lib_list:
74			self.generator.bld.symlink_as('${LIBDIR}/'+basename(lib), lib, postpone=False)
75		return 0
76
77