diff options
author | Jelmer Vernooij <jelmer@samba.org> | 2015-03-25 11:13:40 +0000 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2015-03-26 22:47:22 +0100 |
commit | 90ec37cf90035576bcab4d7b36214c9c19a52d24 (patch) | |
tree | a05aa9b735ca6c2005dfd1812df33bd416b1d455 /third_party/waf/wafadmin/Tools/d.py | |
parent | 32cbbed979b931eeb5127629248a94d7e6f3fcfb (diff) | |
download | samba-90ec37cf90035576bcab4d7b36214c9c19a52d24.tar.gz |
Move waf into third_party/.
Signed-Off-By: Jelmer Vernooij <jelmer@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Diffstat (limited to 'third_party/waf/wafadmin/Tools/d.py')
-rw-r--r-- | third_party/waf/wafadmin/Tools/d.py | 534 |
1 files changed, 534 insertions, 0 deletions
diff --git a/third_party/waf/wafadmin/Tools/d.py b/third_party/waf/wafadmin/Tools/d.py new file mode 100644 index 00000000000..2c2e94857e3 --- /dev/null +++ b/third_party/waf/wafadmin/Tools/d.py @@ -0,0 +1,534 @@ +#!/usr/bin/env python +# encoding: utf-8 +# Carlos Rafael Giani, 2007 (dv) +# Thomas Nagy, 2007-2008 (ita) + +import os, sys, re, optparse +import ccroot # <- leave this +import TaskGen, Utils, Task, Configure, Logs, Build +from Logs import debug, error +from TaskGen import taskgen, feature, after, before, extension +from Configure import conftest + +EXT_D = ['.d', '.di', '.D'] +D_METHS = ['apply_core', 'apply_vnum', 'apply_objdeps'] # additional d methods + +DLIB = """ +version(D_Version2) { + import std.stdio; + int main() { + writefln("phobos2"); + return 0; + } +} else { + version(Tango) { + import tango.stdc.stdio; + int main() { + printf("tango"); + return 0; + } + } else { + import std.stdio; + int main() { + writefln("phobos1"); + return 0; + } + } +} +""" + +def filter_comments(filename): + txt = Utils.readf(filename) + i = 0 + buf = [] + max = len(txt) + begin = 0 + while i < max: + c = txt[i] + if c == '"' or c == "'": # skip a string or character literal + buf.append(txt[begin:i]) + delim = c + i += 1 + while i < max: + c = txt[i] + if c == delim: break + elif c == '\\': # skip the character following backslash + i += 1 + i += 1 + i += 1 + begin = i + elif c == '/': # try to replace a comment with whitespace + buf.append(txt[begin:i]) + i += 1 + if i == max: break + c = txt[i] + if c == '+': # eat nesting /+ +/ comment + i += 1 + nesting = 1 + c = None + while i < max: + prev = c + c = txt[i] + if prev == '/' and c == '+': + nesting += 1 + c = None + elif prev == '+' and c == '/': + nesting -= 1 + if nesting == 0: break + c = None + i += 1 + elif c == '*': # eat /* */ comment + i += 1 + c = None + while i < max: + prev = c + c = txt[i] + if prev == '*' and c == '/': break + i += 1 + elif c == '/': # eat // comment + i += 1 + while i < max and txt[i] != '\n': + i += 1 + else: # no comment + begin = i - 1 + continue + i += 1 + begin = i + buf.append(' ') + else: + i += 1 + buf.append(txt[begin:]) + return buf + +class d_parser(object): + def __init__(self, env, incpaths): + #self.code = '' + #self.module = '' + #self.imports = [] + + self.allnames = [] + + self.re_module = re.compile("module\s+([^;]+)") + self.re_import = re.compile("import\s+([^;]+)") + self.re_import_bindings = re.compile("([^:]+):(.*)") + self.re_import_alias = re.compile("[^=]+=(.+)") + + self.env = env + + self.nodes = [] + self.names = [] + + self.incpaths = incpaths + + def tryfind(self, filename): + found = 0 + for n in self.incpaths: + found = n.find_resource(filename.replace('.', '/') + '.d') + if found: + self.nodes.append(found) + self.waiting.append(found) + break + if not found: + if not filename in self.names: + self.names.append(filename) + + def get_strings(self, code): + #self.imports = [] + self.module = '' + lst = [] + + # get the module name (if present) + + mod_name = self.re_module.search(code) + if mod_name: + self.module = re.sub('\s+', '', mod_name.group(1)) # strip all whitespaces + + # go through the code, have a look at all import occurrences + + # first, lets look at anything beginning with "import" and ending with ";" + import_iterator = self.re_import.finditer(code) + if import_iterator: + for import_match in import_iterator: + import_match_str = re.sub('\s+', '', import_match.group(1)) # strip all whitespaces + + # does this end with an import bindings declaration? + # (import bindings always terminate the list of imports) + bindings_match = self.re_import_bindings.match(import_match_str) + if bindings_match: + import_match_str = bindings_match.group(1) + # if so, extract the part before the ":" (since the module declaration(s) is/are located there) + + # split the matching string into a bunch of strings, separated by a comma + matches = import_match_str.split(',') + + for match in matches: + alias_match = self.re_import_alias.match(match) + if alias_match: + # is this an alias declaration? (alias = module name) if so, extract the module name + match = alias_match.group(1) + + lst.append(match) + return lst + + def start(self, node): + self.waiting = [node] + # while the stack is not empty, add the dependencies + while self.waiting: + nd = self.waiting.pop(0) + self.iter(nd) + + def iter(self, node): + path = node.abspath(self.env) # obtain the absolute path + code = "".join(filter_comments(path)) # read the file and filter the comments + names = self.get_strings(code) # obtain the import strings + for x in names: + # optimization + if x in self.allnames: continue + self.allnames.append(x) + + # for each name, see if it is like a node or not + self.tryfind(x) + +def scan(self): + "look for .d/.di the .d source need" + env = self.env + gruik = d_parser(env, env['INC_PATHS']) + gruik.start(self.inputs[0]) + + if Logs.verbose: + debug('deps: nodes found for %s: %s %s' % (str(self.inputs[0]), str(gruik.nodes), str(gruik.names))) + #debug("deps found for %s: %s" % (str(node), str(gruik.deps)), 'deps') + return (gruik.nodes, gruik.names) + +def get_target_name(self): + "for d programs and libs" + v = self.env + tp = 'program' + for x in self.features: + if x in ['dshlib', 'dstaticlib']: + tp = x.lstrip('d') + return v['D_%s_PATTERN' % tp] % self.target + +d_params = { +'dflags': '', +'importpaths':'', +'libs':'', +'libpaths':'', +'generate_headers':False, +} + +@feature('d') +@before('apply_type_vars') +def init_d(self): + for x in d_params: + setattr(self, x, getattr(self, x, d_params[x])) + +class d_taskgen(TaskGen.task_gen): + def __init__(self, *k, **kw): + TaskGen.task_gen.__init__(self, *k, **kw) + + # COMPAT + if len(k) > 1: + self.features.append('d' + k[1]) + +# okay, we borrow a few methods from ccroot +TaskGen.bind_feature('d', D_METHS) + +@feature('d') +@before('apply_d_libs') +def init_d(self): + Utils.def_attrs(self, + dflags='', + importpaths='', + libs='', + libpaths='', + uselib='', + uselib_local='', + generate_headers=False, # set to true if you want .di files as well as .o + compiled_tasks=[], + add_objects=[], + link_task=None) + +@feature('d') +@after('apply_d_link', 'init_d') +@before('apply_vnum', 'apply_d_vars') +def apply_d_libs(self): + """after apply_link because of 'link_task' + after default_cc because of the attribute 'uselib'""" + env = self.env + + # 1. the case of the libs defined in the project (visit ancestors first) + # the ancestors external libraries (uselib) will be prepended + self.uselib = self.to_list(self.uselib) + names = self.to_list(self.uselib_local) + + seen = set([]) + tmp = Utils.deque(names) # consume a copy of the list of names + while tmp: + lib_name = tmp.popleft() + # visit dependencies only once + if lib_name in seen: + continue + + y = self.name_to_obj(lib_name) + if not y: + raise Utils.WafError('object %r was not found in uselib_local (required by %r)' % (lib_name, self.name)) + y.post() + seen.add(lib_name) + + # object has ancestors to process (shared libraries): add them to the end of the list + if getattr(y, 'uselib_local', None): + lst = y.to_list(y.uselib_local) + if 'dshlib' in y.features or 'dprogram' in y.features: + lst = [x for x in lst if not 'dstaticlib' in self.name_to_obj(x).features] + tmp.extend(lst) + + # link task and flags + if getattr(y, 'link_task', None): + + link_name = y.target[y.target.rfind(os.sep) + 1:] + if 'dstaticlib' in y.features or 'dshlib' in y.features: + env.append_unique('DLINKFLAGS', env.DLIB_ST % link_name) + env.append_unique('DLINKFLAGS', env.DLIBPATH_ST % y.link_task.outputs[0].parent.bldpath(env)) + + # the order + self.link_task.set_run_after(y.link_task) + + # for the recompilation + dep_nodes = getattr(self.link_task, 'dep_nodes', []) + self.link_task.dep_nodes = dep_nodes + y.link_task.outputs + + # add ancestors uselib too - but only propagate those that have no staticlib + for v in self.to_list(y.uselib): + if not v in self.uselib: + self.uselib.insert(0, v) + + # if the library task generator provides 'export_incdirs', add to the include path + # the export_incdirs must be a list of paths relative to the other library + if getattr(y, 'export_incdirs', None): + for x in self.to_list(y.export_incdirs): + node = y.path.find_dir(x) + if not node: + raise Utils.WafError('object %r: invalid folder %r in export_incdirs' % (y.target, x)) + self.env.append_unique('INC_PATHS', node) + +@feature('dprogram', 'dshlib', 'dstaticlib') +@after('apply_core') +def apply_d_link(self): + link = getattr(self, 'link', None) + if not link: + if 'dstaticlib' in self.features: link = 'static_link' + else: link = 'd_link' + + outputs = [t.outputs[0] for t in self.compiled_tasks] + self.link_task = self.create_task(link, outputs, self.path.find_or_declare(get_target_name(self))) + +@feature('d') +@after('apply_core') +def apply_d_vars(self): + env = self.env + dpath_st = env['DPATH_ST'] + lib_st = env['DLIB_ST'] + libpath_st = env['DLIBPATH_ST'] + + importpaths = self.to_list(self.importpaths) + libpaths = [] + libs = [] + uselib = self.to_list(self.uselib) + + for i in uselib: + if env['DFLAGS_' + i]: + env.append_unique('DFLAGS', env['DFLAGS_' + i]) + + for x in self.features: + if not x in ['dprogram', 'dstaticlib', 'dshlib']: + continue + x.lstrip('d') + d_shlib_dflags = env['D_' + x + '_DFLAGS'] + if d_shlib_dflags: + env.append_unique('DFLAGS', d_shlib_dflags) + + # add import paths + for i in uselib: + if env['DPATH_' + i]: + for entry in self.to_list(env['DPATH_' + i]): + if not entry in importpaths: + importpaths.append(entry) + + # now process the import paths + for path in importpaths: + if os.path.isabs(path): + env.append_unique('_DIMPORTFLAGS', dpath_st % path) + else: + node = self.path.find_dir(path) + self.env.append_unique('INC_PATHS', node) + env.append_unique('_DIMPORTFLAGS', dpath_st % node.srcpath(env)) + env.append_unique('_DIMPORTFLAGS', dpath_st % node.bldpath(env)) + + # add library paths + for i in uselib: + if env['LIBPATH_' + i]: + for entry in self.to_list(env['LIBPATH_' + i]): + if not entry in libpaths: + libpaths.append(entry) + libpaths = self.to_list(self.libpaths) + libpaths + + # now process the library paths + # apply same path manipulation as used with import paths + for path in libpaths: + if not os.path.isabs(path): + node = self.path.find_resource(path) + if not node: + raise Utils.WafError('could not find libpath %r from %r' % (path, self)) + path = node.abspath(self.env) + + env.append_unique('DLINKFLAGS', libpath_st % path) + + # add libraries + for i in uselib: + if env['LIB_' + i]: + for entry in self.to_list(env['LIB_' + i]): + if not entry in libs: + libs.append(entry) + libs.extend(self.to_list(self.libs)) + + # process user flags + for flag in self.to_list(self.dflags): + env.append_unique('DFLAGS', flag) + + # now process the libraries + for lib in libs: + env.append_unique('DLINKFLAGS', lib_st % lib) + + # add linker flags + for i in uselib: + dlinkflags = env['DLINKFLAGS_' + i] + if dlinkflags: + for linkflag in dlinkflags: + env.append_unique('DLINKFLAGS', linkflag) + +@feature('dshlib') +@after('apply_d_vars') +def add_shlib_d_flags(self): + for linkflag in self.env['D_shlib_LINKFLAGS']: + self.env.append_unique('DLINKFLAGS', linkflag) + +@extension(EXT_D) +def d_hook(self, node): + # create the compilation task: cpp or cc + task = self.create_task(self.generate_headers and 'd_with_header' or 'd') + try: obj_ext = self.obj_ext + except AttributeError: obj_ext = '_%d.o' % self.idx + + task.inputs = [node] + task.outputs = [node.change_ext(obj_ext)] + self.compiled_tasks.append(task) + + if self.generate_headers: + header_node = node.change_ext(self.env['DHEADER_ext']) + task.outputs += [header_node] + +d_str = '${D_COMPILER} ${DFLAGS} ${_DIMPORTFLAGS} ${D_SRC_F}${SRC} ${D_TGT_F}${TGT}' +d_with_header_str = '${D_COMPILER} ${DFLAGS} ${_DIMPORTFLAGS} \ +${D_HDR_F}${TGT[1].bldpath(env)} \ +${D_SRC_F}${SRC} \ +${D_TGT_F}${TGT[0].bldpath(env)}' +link_str = '${D_LINKER} ${DLNK_SRC_F}${SRC} ${DLNK_TGT_F}${TGT} ${DLINKFLAGS}' + +def override_exec(cls): + """stupid dmd wants -of stuck to the file name""" + old_exec = cls.exec_command + def exec_command(self, *k, **kw): + if isinstance(k[0], list): + lst = k[0] + for i in xrange(len(lst)): + if lst[i] == '-of': + del lst[i] + lst[i] = '-of' + lst[i] + break + return old_exec(self, *k, **kw) + cls.exec_command = exec_command + +cls = Task.simple_task_type('d', d_str, 'GREEN', before='static_link d_link', shell=False) +cls.scan = scan +override_exec(cls) + +cls = Task.simple_task_type('d_with_header', d_with_header_str, 'GREEN', before='static_link d_link', shell=False) +override_exec(cls) + +cls = Task.simple_task_type('d_link', link_str, color='YELLOW', shell=False) +override_exec(cls) + +# for feature request #104 +@taskgen +def generate_header(self, filename, install_path): + if not hasattr(self, 'header_lst'): self.header_lst = [] + self.meths.append('process_header') + self.header_lst.append([filename, install_path]) + +@before('apply_core') +def process_header(self): + env = self.env + for i in getattr(self, 'header_lst', []): + node = self.path.find_resource(i[0]) + + if not node: + raise Utils.WafError('file not found on d obj '+i[0]) + + task = self.create_task('d_header') + task.set_inputs(node) + task.set_outputs(node.change_ext('.di')) + +d_header_str = '${D_COMPILER} ${D_HEADER} ${SRC}' +Task.simple_task_type('d_header', d_header_str, color='BLUE', shell=False) + +@conftest +def d_platform_flags(conf): + v = conf.env + binfmt = v.DEST_BINFMT or Utils.unversioned_sys_platform_to_binary_format( + v.DEST_OS or Utils.unversioned_sys_platform()) + if binfmt == 'pe': + v['D_program_PATTERN'] = '%s.exe' + v['D_shlib_PATTERN'] = 'lib%s.dll' + v['D_staticlib_PATTERN'] = 'lib%s.a' + else: + v['D_program_PATTERN'] = '%s' + v['D_shlib_PATTERN'] = 'lib%s.so' + v['D_staticlib_PATTERN'] = 'lib%s.a' + +@conftest +def check_dlibrary(conf): + ret = conf.check_cc(features='d dprogram', fragment=DLIB, mandatory=True, compile_filename='test.d', execute=True) + conf.env.DLIBRARY = ret.strip() + +# quick test # +if __name__ == "__main__": + #Logs.verbose = 2 + + try: arg = sys.argv[1] + except IndexError: arg = "file.d" + + print("".join(filter_comments(arg))) + # TODO + paths = ['.'] + + #gruik = filter() + #gruik.start(arg) + + #code = "".join(gruik.buf) + + #print "we have found the following code" + #print code + + #print "now parsing" + #print "-------------------------------------------" + """ + parser_ = d_parser() + parser_.start(arg) + + print "module: %s" % parser_.module + print "imports: ", + for imp in parser_.imports: + print imp + " ", + print +""" |