#! /usr/bin/env python

top = '.'
out = 'build'

def set_options(opt):
	opt.tool_options('compiler_cc')

def configure(conf):
	conf.check_tool('compiler_cc')

def build(bld):
	bld(features='cc cshlib', vnum='1.2.3', source='a.c', target='mylib')


# warn against changed symbols

import os, re
import Task, Utils, Logs
from TaskGen import feature, after

re_syms = re.compile("((\\.|\\w)+)\n", re.M)
def filter_symbols(txt):
	lst = set([])
	for m in re_syms.finditer(txt):
		lst.add(m.group(1))
	lst = list(lst)
	lst.sort()
	return lst

def get_syms(task, outp):
	ret = Utils.cmd_output(['objdump', '-t', task.inputs[0].name], cwd=task.inputs[0].parent.abspath(task.env))
	ret = filter_symbols(ret)
	f = None
	try:
		f = open(outp, 'w')
		f.write('\n'.join(ret) + '\n')
	finally:
		if f:
			f.close()

	return ret

def dump_fun(self):
	ret = get_syms(self, self.env.SYM_FILE)

def diff_fun(self):
	outp = self.outputs[0].abspath(self.env)
	ret = set(get_syms(self, outp))
	ref = set(self.inputs[1].read(self.env).split())
	diff = ref ^ ret
	if diff:
		old = []
		new = []
		for x in diff:
			if x in ref:
				old.append(x)
			else:
				new.append(x)
		raise Utils.WafError('symbols in %s have changed: old/added %r <-> %r' % (self.outputs[0].name, old, new))

cls = Task.task_type_from_func('put_sym', dump_fun, vars=[], ext_in='.bin')
cls.quiet = True
Task.always_run(cls)

cls = Task.task_type_from_func('check_sym', diff_fun, vars=[], ext_in='.bin')
#Task.always_run(cls) # <- not always

@feature('cshlib')
@after('apply_vnum')
def check_symbols(self):
	if not self.vnum:
		return

	d = self.bld.srcnode.abspath() + os.sep + 'cache_symbols'
	try:
		lst = os.listdir(d)
	except:
		os.makedirs(d)

	symfile = d + os.sep + self.link_task.outputs[0].name + '.' + self.vnum + '.sym'

	binary = self.link_task.outputs[0]
	cache_sym = self.bld.root.find_resource(symfile)
	if cache_sym:
		self.create_task('check_sym', [binary, cache_sym], binary.parent.find_or_declare(binary.name + '.sym'))
	else:
		tsk = self.create_task('put_sym', binary)
		tsk.env.SYM_FILE = symfile

