From e7a29b6b9b2f842314244c23c14d8f8f560904e1 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 17 Mar 2019 17:23:45 +0100 Subject: Upgrade to waf 2.0.15 --- Build.py | 11 ++-- ConfigSet.py | 4 +- Configure.py | 3 +- Context.py | 14 ++--- Logs.py | 4 +- Runner.py | 8 ++- Scripting.py | 10 +++- Task.py | 58 ++++++++++++--------- TaskGen.py | 4 +- Tools/c_config.py | 4 +- Tools/c_preproc.py | 6 +-- Tools/ccroot.py | 19 ++++++- Tools/d_scan.py | 8 +-- Tools/fc.py | 22 ++++++-- Tools/fc_config.py | 4 +- Tools/fc_scan.py | 12 +++-- Tools/ifort.py | 2 +- Tools/javaw.py | 131 ++++++++++++++++++++++++++++++++++++++++++++--- Tools/md5_tstamp.py | 3 +- Tools/msvc.py | 16 +++--- Tools/python.py | 4 ++ Tools/qt5.py | 8 +-- Tools/waf_unit_test.py | 2 +- Tools/winres.py | 4 +- Utils.py | 18 +++++-- ansiterm.py | 2 +- extras/buildcopy.py | 7 ++- extras/cpplint.py | 6 +-- extras/cython.py | 13 ++--- extras/distnet.py | 2 +- extras/erlang.py | 2 +- extras/fast_partial.py | 2 +- extras/fc_nfort.py | 52 +++++++++++++++++++ extras/gccdeps.py | 6 +-- extras/kde4.py | 2 +- extras/ocaml.py | 2 +- extras/parallel_debug.py | 9 ++-- extras/pgicc.py | 2 +- extras/protoc.py | 92 +++++++++++++-------------------- extras/pyqt5.py | 4 +- extras/qt4.py | 6 +-- extras/remote.py | 2 +- extras/run_do_script.py | 2 +- extras/swig.py | 4 +- 44 files changed, 413 insertions(+), 183 deletions(-) create mode 100644 extras/fc_nfort.py diff --git a/Build.py b/Build.py index 1afcba6..8143dbc 100644 --- a/Build.py +++ b/Build.py @@ -104,7 +104,7 @@ class BuildContext(Context.Context): """Amount of jobs to run in parallel""" self.targets = Options.options.targets - """List of targets to build (default: \*)""" + """List of targets to build (default: \\*)""" self.keep = Options.options.keep """Whether the build should continue past errors""" @@ -1055,12 +1055,16 @@ class inst(Task.Task): """ Returns the destination path where files will be installed, pre-pending `destdir`. + Relative paths will be interpreted relative to `PREFIX` if no `destdir` is given. + :rtype: string """ if isinstance(self.install_to, Node.Node): dest = self.install_to.abspath() else: - dest = Utils.subst_vars(self.install_to, self.env) + dest = os.path.normpath(Utils.subst_vars(self.install_to, self.env)) + if not os.path.isabs(dest): + dest = os.path.join(self.env.PREFIX, dest) if destdir and Options.options.destdir: dest = os.path.join(Options.options.destdir, os.path.splitdrive(dest)[1].lstrip(os.sep)) return dest @@ -1314,7 +1318,8 @@ class CleanContext(BuildContext): lst = [] for env in self.all_envs.values(): lst.extend(self.root.find_or_declare(f) for f in env[CFG_FILES]) - for n in self.bldnode.ant_glob('**/*', excl='.lock* *conf_check_*/** config.log c4che/*', quiet=True): + excluded_dirs = '.lock* *conf_check_*/** config.log %s/*' % CACHE_DIR + for n in self.bldnode.ant_glob('**/*', excl=excluded_dirs, quiet=True): if n in lst: continue n.delete() diff --git a/ConfigSet.py b/ConfigSet.py index b300bb5..901fba6 100644 --- a/ConfigSet.py +++ b/ConfigSet.py @@ -11,7 +11,7 @@ The values put in :py:class:`ConfigSet` must be serializable (dicts, lists, stri import copy, re, os from waflib import Logs, Utils -re_imp = re.compile('^(#)*?([^#=]*?)\ =\ (.*?)$', re.M) +re_imp = re.compile(r'^(#)*?([^#=]*?)\ =\ (.*?)$', re.M) class ConfigSet(object): """ @@ -312,7 +312,7 @@ class ConfigSet(object): :type filename: string """ tbl = self.table - code = Utils.readf(filename, m='rU') + code = Utils.readf(filename, m='r') for m in re_imp.finditer(code): g = m.group tbl[g(2)] = eval(g(3)) diff --git a/Configure.py b/Configure.py index d0a4793..db09c0e 100644 --- a/Configure.py +++ b/Configure.py @@ -125,7 +125,7 @@ class ConfigurationContext(Context.Context): self.bldnode.mkdir() if not os.path.isdir(self.bldnode.abspath()): - conf.fatal('Could not create the build directory %s' % self.bldnode.abspath()) + self.fatal('Could not create the build directory %s' % self.bldnode.abspath()) def execute(self): """ @@ -180,6 +180,7 @@ class ConfigurationContext(Context.Context): env.hash = self.hash env.files = self.files env.environ = dict(self.environ) + env.launch_dir = Context.launch_dir if not (self.env.NO_LOCK_IN_RUN or env.environ.get('NO_LOCK_IN_RUN') or getattr(Options.options, 'no_lock_in_run')): env.store(os.path.join(Context.run_dir, Options.lockfile)) diff --git a/Context.py b/Context.py index bb47c92..876ea46 100644 --- a/Context.py +++ b/Context.py @@ -11,13 +11,13 @@ from waflib import Utils, Errors, Logs import waflib.Node # the following 3 constants are updated on each new release (do not touch) -HEXVERSION=0x2000b00 +HEXVERSION=0x2000f00 """Constant updated on new releases""" -WAFVERSION="2.0.11" +WAFVERSION="2.0.15" """Constant updated on new releases""" -WAFREVISION="a97f6fb0941091b4966b625f15ec32fa783a8bec" +WAFREVISION="503db290b73ef738a495e0d116d6f8ee0b98dcc2" """Git revision when the waf version is updated""" ABI = 20 @@ -266,7 +266,7 @@ class Context(ctx): cache[node] = True self.pre_recurse(node) try: - function_code = node.read('rU', encoding) + function_code = node.read('r', encoding) exec(compile(function_code, node.abspath(), 'exec'), self.exec_dict) finally: self.post_recurse(node) @@ -613,7 +613,7 @@ class Context(ctx): is typically called once for a programming language group, see for example :py:mod:`waflib.Tools.compiler_c` - :param var: glob expression, for example 'cxx\_\*.py' + :param var: glob expression, for example 'cxx\\_\\*.py' :type var: string :param ban: list of exact file names to exclude :type ban: list of string @@ -662,7 +662,7 @@ def load_module(path, encoding=None): module = imp.new_module(WSCRIPT_FILE) try: - code = Utils.readf(path, m='rU', encoding=encoding) + code = Utils.readf(path, m='r', encoding=encoding) except EnvironmentError: raise Errors.WafError('Could not read the file %r' % path) @@ -678,7 +678,7 @@ def load_module(path, encoding=None): def load_tool(tool, tooldir=None, ctx=None, with_sys_path=True): """ - Importx a Waf tool as a python module, and stores it in the dict :py:const:`waflib.Context.Context.tools` + Imports a Waf tool as a python module, and stores it in the dict :py:const:`waflib.Context.Context.tools` :type tool: string :param tool: Name of the tool diff --git a/Logs.py b/Logs.py index 2a47516..11dc34f 100644 --- a/Logs.py +++ b/Logs.py @@ -276,9 +276,9 @@ def error(*k, **kw): def warn(*k, **kw): """ - Wraps logging.warn + Wraps logging.warning """ - log.warn(*k, **kw) + log.warning(*k, **kw) def info(*k, **kw): """ diff --git a/Runner.py b/Runner.py index 261084d..5d27669 100644 --- a/Runner.py +++ b/Runner.py @@ -37,6 +37,8 @@ class PriorityTasks(object): return len(self.lst) def __iter__(self): return iter(self.lst) + def __str__(self): + return 'PriorityTasks: [%s]' % '\n '.join(str(x) for x in self.lst) def clear(self): self.lst = [] def append(self, task): @@ -181,10 +183,12 @@ class Parallel(object): The reverse dependency graph of dependencies obtained from Task.run_after """ - self.spawner = Spawner(self) + self.spawner = None """ Coordinating daemon thread that spawns thread consumers """ + if self.numjobs > 1: + self.spawner = Spawner(self) def get_next_task(self): """ @@ -254,6 +258,8 @@ class Parallel(object): self.outstanding.append(x) break else: + if self.stop or self.error: + break raise Errors.WafError('Broken revdeps detected on %r' % self.incomplete) else: tasks = next(self.biter) diff --git a/Scripting.py b/Scripting.py index 749d4f2..ae17a8b 100644 --- a/Scripting.py +++ b/Scripting.py @@ -216,7 +216,10 @@ def parse_options(): ctx = Context.create_context('options') ctx.execute() if not Options.commands: - Options.commands.append(default_cmd) + if isinstance(default_cmd, list): + Options.commands.extend(default_cmd) + else: + Options.commands.append(default_cmd) if Options.options.whelp: ctx.parser.print_help() sys.exit(0) @@ -280,7 +283,7 @@ def distclean_dir(dirname): pass try: - shutil.rmtree('c4che') + shutil.rmtree(Build.CACHE_DIR) except OSError: pass @@ -598,12 +601,15 @@ def autoconfigure(execute_method): cmd = env.config_cmd or 'configure' if Configure.autoconfig == 'clobber': tmp = Options.options.__dict__ + launch_dir_tmp = Context.launch_dir if env.options: Options.options.__dict__ = env.options + Context.launch_dir = env.launch_dir try: run_command(cmd) finally: Options.options.__dict__ = tmp + Context.launch_dir = launch_dir_tmp else: run_command(cmd) run_command(self.cmd) diff --git a/Task.py b/Task.py index 0fc449d..cb49a73 100644 --- a/Task.py +++ b/Task.py @@ -50,6 +50,9 @@ def f(tsk): bld = gen.bld cwdx = tsk.get_cwd() p = env.get_flat + def to_list(xx): + if isinstance(xx, str): return [xx] + return xx tsk.last_cmd = cmd = \'\'\' %s \'\'\' % s return tsk.exec_command(cmd, cwd=cwdx, env=env.env or None) ''' @@ -77,7 +80,8 @@ def f(tsk): COMPILE_TEMPLATE_SIG_VARS = ''' def f(tsk): - super(tsk.__class__, tsk).sig_vars() + sig = tsk.generator.bld.hash_env_vars(tsk.env, tsk.vars) + tsk.m.update(sig) env = tsk.env gen = tsk.generator bld = gen.bld @@ -159,10 +163,10 @@ class Task(evil): """File extensions that objects of this task class may create""" before = [] - """List of task class names to execute before instances of this class""" + """The instances of this class are executed before the instances of classes whose names are in this list""" after = [] - """List of task class names to execute after instances of this class""" + """The instances of this class are executed after the instances of classes whose names are in this list""" hcode = Utils.SIG_NIL """String representing an additional hash for the class representation""" @@ -302,25 +306,31 @@ class Task(evil): if hasattr(self, 'stderr'): kw['stderr'] = self.stderr - # workaround for command line length limit: - # http://support.microsoft.com/kb/830473 - if not isinstance(cmd, str) and (len(repr(cmd)) >= 8192 if Utils.is_win32 else len(cmd) > 200000): - cmd, args = self.split_argfile(cmd) - try: - (fd, tmp) = tempfile.mkstemp() - os.write(fd, '\r\n'.join(args).encode()) - os.close(fd) - if Logs.verbose: - Logs.debug('argfile: @%r -> %r', tmp, args) - return self.generator.bld.exec_command(cmd + ['@' + tmp], **kw) - finally: + if not isinstance(cmd, str): + if Utils.is_win32: + # win32 compares the resulting length http://support.microsoft.com/kb/830473 + too_long = sum([len(arg) for arg in cmd]) + len(cmd) > 8192 + else: + # non-win32 counts the amount of arguments (200k) + too_long = len(cmd) > 200000 + + if too_long and getattr(self, 'allow_argsfile', True): + # Shunt arguments to a temporary file if the command is too long. + cmd, args = self.split_argfile(cmd) try: - os.remove(tmp) - except OSError: - # anti-virus and indexers can keep files open -_- - pass - else: - return self.generator.bld.exec_command(cmd, **kw) + (fd, tmp) = tempfile.mkstemp() + os.write(fd, '\r\n'.join(args).encode()) + os.close(fd) + if Logs.verbose: + Logs.debug('argfile: @%r -> %r', tmp, args) + return self.generator.bld.exec_command(cmd + ['@' + tmp], **kw) + finally: + try: + os.remove(tmp) + except OSError: + # anti-virus and indexers can keep files open -_- + pass + return self.generator.bld.exec_command(cmd, **kw) def process(self): """ @@ -776,6 +786,8 @@ class Task(evil): Used by :py:meth:`waflib.Task.Task.signature`; it hashes :py:attr:`waflib.Task.Task.env` variables/values When overriding this method, and if scriptlet expressions are used, make sure to follow the code in :py:meth:`waflib.Task.Task.compile_sig_vars` to enable dependencies on scriptlet results. + + This method may be replaced on subclasses by the metaclass to force dependencies on scriptlet code. """ sig = self.generator.bld.hash_env_vars(self.env, self.vars) self.m.update(sig) @@ -1038,7 +1050,7 @@ def funex(c): exec(c, dc) return dc['f'] -re_cond = re.compile('(?P\w+)|(?P\|)|(?P&)') +re_cond = re.compile(r'(?P\w+)|(?P\|)|(?P&)') re_novar = re.compile(r'^(SRC|TGT)\W+.*?$') reg_act = re.compile(r'(?P\\)|(?P\$\$)|(?P\$\{(?P\w+)(?P.*?)\})', re.M) def compile_fun_shell(line): @@ -1193,7 +1205,7 @@ def compile_fun_noshell(line): # plain code such as ${tsk.inputs[0].abspath()} call = '%s%s' % (var, code) add_dvar(call) - app('gen.to_list(%s)' % call) + app('to_list(%s)' % call) else: # a plain variable such as # a plain variable like ${AR} app('to_list(env[%r])' % var) diff --git a/TaskGen.py b/TaskGen.py index a74e643..532b7d5 100644 --- a/TaskGen.py +++ b/TaskGen.py @@ -74,7 +74,7 @@ class task_gen(object): else: self.bld = kw['bld'] self.env = self.bld.env.derive() - self.path = self.bld.path # emulate chdir when reading scripts + self.path = kw.get('path', self.bld.path) # by default, emulate chdir when reading scripts # Provide a unique index per folder # This is part of a measure to prevent output file name collisions @@ -727,7 +727,7 @@ def sequence_order(self): self.bld.prev = self -re_m4 = re.compile('@(\w+)@', re.M) +re_m4 = re.compile(r'@(\w+)@', re.M) class subst_pc(Task.Task): """ diff --git a/Tools/c_config.py b/Tools/c_config.py index d2b3c0d..d546be9 100644 --- a/Tools/c_config.py +++ b/Tools/c_config.py @@ -250,9 +250,9 @@ def exec_cfg(self, kw): :type atleast_pkgconfig_version: string :param package: package name, for example *gtk+-2.0* :type package: string - :param uselib_store: if the test is successful, define HAVE\_*name*. It is also used to define *conf.env.FLAGS_name* variables. + :param uselib_store: if the test is successful, define HAVE\\_*name*. It is also used to define *conf.env.FLAGS_name* variables. :type uselib_store: string - :param modversion: if provided, return the version of the given module and define *name*\_VERSION + :param modversion: if provided, return the version of the given module and define *name*\\_VERSION :type modversion: string :param args: arguments to give to *package* when retrieving flags :type args: list of string diff --git a/Tools/c_preproc.py b/Tools/c_preproc.py index 7e04b4a..68e5f5a 100644 --- a/Tools/c_preproc.py +++ b/Tools/c_preproc.py @@ -75,13 +75,13 @@ re_lines = re.compile( re.IGNORECASE | re.MULTILINE) """Match #include lines""" -re_mac = re.compile("^[a-zA-Z_]\w*") +re_mac = re.compile(r"^[a-zA-Z_]\w*") """Match macro definitions""" re_fun = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*[(]') """Match macro functions""" -re_pragma_once = re.compile('^\s*once\s*', re.IGNORECASE) +re_pragma_once = re.compile(r'^\s*once\s*', re.IGNORECASE) """Match #pragma once statements""" re_nl = re.compile('\\\\\r*\n', re.MULTILINE) @@ -660,7 +660,7 @@ def extract_macro(txt): # empty define, assign an empty token return (v, [[], [('T','')]]) -re_include = re.compile('^\s*(<(?:.*)>|"(?:.*)")') +re_include = re.compile(r'^\s*(<(?:.*)>|"(?:.*)")') def extract_include(txt, defs): """ Process a line in the form:: diff --git a/Tools/ccroot.py b/Tools/ccroot.py index cfef8bf..579d5b2 100644 --- a/Tools/ccroot.py +++ b/Tools/ccroot.py @@ -111,7 +111,7 @@ def apply_incpaths(self): tg = bld(features='includes', includes='.') The folders only need to be relative to the current directory, the equivalent build directory is - added automatically (for headers created in the build directory). This enable using a build directory + added automatically (for headers created in the build directory). This enables using a build directory or not (``top == out``). This method will add a list of nodes read by :py:func:`waflib.Tools.ccroot.to_incnodes` in ``tg.env.INCPATHS``, @@ -238,6 +238,17 @@ def rm_tgt(cls): setattr(cls, 'run', wrap) rm_tgt(stlink_task) +@feature('skip_stlib_link_deps') +@before_method('process_use') +def apply_skip_stlib_link_deps(self): + """ + This enables an optimization in the :py:func:wafilb.Tools.ccroot.processes_use: method that skips dependency and + link flag optimizations for targets that generate static libraries (via the :py:class:Tools.ccroot.stlink_task task). + The actual behavior is implemented in :py:func:wafilb.Tools.ccroot.processes_use: method so this feature only tells waf + to enable the new behavior. + """ + self.env.SKIP_STLIB_LINK_DEPS = True + @feature('c', 'cxx', 'd', 'fc', 'asm') @after_method('process_source') def apply_link(self): @@ -386,7 +397,11 @@ def process_use(self): y = self.bld.get_tgen_by_name(x) var = y.tmp_use_var if var and link_task: - if var == 'LIB' or y.tmp_use_stlib or x in names: + if self.env.SKIP_STLIB_LINK_DEPS and isinstance(link_task, stlink_task): + # If the skip_stlib_link_deps feature is enabled then we should + # avoid adding lib deps to the stlink_task instance. + pass + elif var == 'LIB' or y.tmp_use_stlib or x in names: self.env.append_value(var, [y.target[y.target.rfind(os.sep) + 1:]]) self.link_task.dep_nodes.extend(y.link_task.outputs) tmp_path = y.link_task.outputs[0].parent.path_from(self.get_cwd()) diff --git a/Tools/d_scan.py b/Tools/d_scan.py index 14c6c31..4e807a6 100644 --- a/Tools/d_scan.py +++ b/Tools/d_scan.py @@ -93,8 +93,8 @@ class d_parser(object): self.allnames = [] - self.re_module = re.compile("module\s+([^;]+)") - self.re_import = re.compile("import\s+([^;]+)") + self.re_module = re.compile(r"module\s+([^;]+)") + self.re_import = re.compile(r"import\s+([^;]+)") self.re_import_bindings = re.compile("([^:]+):(.*)") self.re_import_alias = re.compile("[^=]+=(.+)") @@ -138,7 +138,7 @@ class d_parser(object): mod_name = self.re_module.search(code) if mod_name: - self.module = re.sub('\s+', '', mod_name.group(1)) # strip all whitespaces + self.module = re.sub(r'\s+', '', mod_name.group(1)) # strip all whitespaces # go through the code, have a look at all import occurrences @@ -146,7 +146,7 @@ class d_parser(object): 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 + import_match_str = re.sub(r'\s+', '', import_match.group(1)) # strip all whitespaces # does this end with an import bindings declaration? # (import bindings always terminate the list of imports) diff --git a/Tools/fc.py b/Tools/fc.py index d9e8d8c..fd4d39c 100644 --- a/Tools/fc.py +++ b/Tools/fc.py @@ -28,10 +28,24 @@ def modfile(conf, name): Turns a module name into the right module file name. Defaults to all lower case. """ - return {'lower' :name.lower() + '.mod', - 'lower.MOD' :name.lower() + '.MOD', - 'UPPER.mod' :name.upper() + '.mod', - 'UPPER' :name.upper() + '.MOD'}[conf.env.FC_MOD_CAPITALIZATION or 'lower'] + if name.find(':') >= 0: + # Depending on a submodule! + separator = conf.env.FC_SUBMOD_SEPARATOR or '@' + # Ancestors of the submodule will be prefixed to the + # submodule name, separated by a colon. + modpath = name.split(':') + # Only the ancestor (actual) module and the submodule name + # will be used for the filename. + modname = modpath[0] + separator + modpath[-1] + suffix = conf.env.FC_SUBMOD_SUFFIX or '.smod' + else: + modname = name + suffix = '.mod' + + return {'lower' :modname.lower() + suffix.lower(), + 'lower.MOD' :modname.lower() + suffix.upper(), + 'UPPER.mod' :modname.upper() + suffix.lower(), + 'UPPER' :modname.upper() + suffix.upper()}[conf.env.FC_MOD_CAPITALIZATION or 'lower'] def get_fortran_tasks(tsk): """ diff --git a/Tools/fc_config.py b/Tools/fc_config.py index 222f3a5..dc5e5c9 100644 --- a/Tools/fc_config.py +++ b/Tools/fc_config.py @@ -178,8 +178,8 @@ def check_fortran_dummy_main(self, *k, **kw): # ------------------------------------------------------------------------ GCC_DRIVER_LINE = re.compile('^Driving:') -POSIX_STATIC_EXT = re.compile('\S+\.a') -POSIX_LIB_FLAGS = re.compile('-l\S+') +POSIX_STATIC_EXT = re.compile(r'\S+\.a') +POSIX_LIB_FLAGS = re.compile(r'-l\S+') @conf def is_link_verbose(self, txt): diff --git a/Tools/fc_scan.py b/Tools/fc_scan.py index 12cb0fc..0824c92 100644 --- a/Tools/fc_scan.py +++ b/Tools/fc_scan.py @@ -5,13 +5,15 @@ import re -INC_REGEX = """(?:^|['">]\s*;)\s*(?:|#\s*)INCLUDE\s+(?:\w+_)?[<"'](.+?)(?=["'>])""" -USE_REGEX = """(?:^|;)\s*USE(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(\w+)""" -MOD_REGEX = """(?:^|;)\s*MODULE(?!\s*PROCEDURE)(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(\w+)""" +INC_REGEX = r"""(?:^|['">]\s*;)\s*(?:|#\s*)INCLUDE\s+(?:\w+_)?[<"'](.+?)(?=["'>])""" +USE_REGEX = r"""(?:^|;)\s*USE(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(\w+)""" +MOD_REGEX = r"""(?:^|;)\s*MODULE(?!\s+(?:PROCEDURE|SUBROUTINE|FUNCTION))\s+(\w+)""" +SMD_REGEX = r"""(?:^|;)\s*SUBMODULE\s*\(([\w:]+)\)\s*(\w+)""" re_inc = re.compile(INC_REGEX, re.I) re_use = re.compile(USE_REGEX, re.I) re_mod = re.compile(MOD_REGEX, re.I) +re_smd = re.compile(SMD_REGEX, re.I) class fortran_parser(object): """ @@ -58,6 +60,10 @@ class fortran_parser(object): m = re_mod.search(line) if m: mods.append(m.group(1)) + m = re_smd.search(line) + if m: + uses.append(m.group(1)) + mods.append('{0}:{1}'.format(m.group(1),m.group(2))) return (incs, uses, mods) def start(self, node): diff --git a/Tools/ifort.py b/Tools/ifort.py index 74934f3..17d3052 100644 --- a/Tools/ifort.py +++ b/Tools/ifort.py @@ -107,7 +107,7 @@ def gather_ifort_versions(conf, versions): """ List compiler versions by looking up registry keys """ - version_pattern = re.compile('^...?.?\....?.?') + version_pattern = re.compile(r'^...?.?\....?.?') try: all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Intel\\Compilers\\Fortran') except OSError: diff --git a/Tools/javaw.py b/Tools/javaw.py index f6fd20c..9daed39 100644 --- a/Tools/javaw.py +++ b/Tools/javaw.py @@ -24,12 +24,95 @@ You would have to run:: java -jar /path/to/jython.jar waf configure [1] http://www.jython.org/ + +Usage +===== + +Load the "java" tool. + +def configure(conf): + conf.load('java') + +Java tools will be autodetected and eventually, if present, the quite +standard JAVA_HOME environment variable will be used. The also standard +CLASSPATH variable is used for library searching. + +In configuration phase checks can be done on the system environment, for +example to check if a class is known in the classpath:: + + conf.check_java_class('java.io.FileOutputStream') + +or if the system supports JNI applications building:: + + conf.check_jni_headers() + + +The java tool supports compiling java code, creating jar files and +creating javadoc documentation. This can be either done separately or +together in a single definition. For example to manage them separately:: + + bld(features = 'javac', + srcdir = 'src', + compat = '1.7', + use = 'animals', + name = 'cats-src', + ) + + bld(features = 'jar', + basedir = '.', + destfile = '../cats.jar', + name = 'cats', + use = 'cats-src' + ) + + +Or together by defining all the needed attributes:: + + bld(features = 'javac jar javadoc', + srcdir = 'src/', # folder containing the sources to compile + outdir = 'src', # folder where to output the classes (in the build directory) + compat = '1.6', # java compatibility version number + classpath = ['.', '..'], + + # jar + basedir = 'src', # folder containing the classes and other files to package (must match outdir) + destfile = 'foo.jar', # do not put the destfile in the folder of the java classes! + use = 'NNN', + jaropts = ['-C', 'default/src/', '.'], # can be used to give files + manifest = 'src/Manifest.mf', # Manifest file to include + + # javadoc + javadoc_package = ['com.meow' , 'com.meow.truc.bar', 'com.meow.truc.foo'], + javadoc_output = 'javadoc', + ) + +External jar dependencies can be mapped to a standard waf "use" dependency by +setting an environment variable with a CLASSPATH prefix in the configuration, +for example:: + + conf.env.CLASSPATH_NNN = ['aaaa.jar', 'bbbb.jar'] + +and then NNN can be freely used in rules as:: + + use = 'NNN', + +In the java tool the dependencies via use are not transitive by default, as +this necessity depends on the code. To enable recursive dependency scanning +use on a specific rule: + + recurse_use = True + +Or build-wise by setting RECURSE_JAVA: + + bld.env.RECURSE_JAVA = True + +Unit tests can be integrated in the waf unit test environment using the javatest extra. """ import os, shutil from waflib import Task, Utils, Errors, Node from waflib.Configure import conf -from waflib.TaskGen import feature, before_method, after_method +from waflib.TaskGen import feature, before_method, after_method, taskgen_method from waflib.Tools import ccroot ccroot.USELIB_VARS['javac'] = set(['CLASSPATH', 'JAVACFLAGS']) @@ -107,6 +190,32 @@ def apply_java(self): if names: tsk.env.append_value('JAVACFLAGS', ['-sourcepath', names]) + +@taskgen_method +def java_use_rec(self, name, **kw): + """ + Processes recursively the *use* attribute for each referred java compilation + """ + if name in self.tmp_use_seen: + return + + self.tmp_use_seen.append(name) + + try: + y = self.bld.get_tgen_by_name(name) + except Errors.WafError: + self.uselib.append(name) + return + else: + y.post() + # Add generated JAR name for CLASSPATH. Task ordering (set_run_after) + # is already guaranteed by ordering done between the single tasks + if hasattr(y, 'jar_task'): + self.use_lst.append(y.jar_task.outputs[0].abspath()) + + for x in self.to_list(getattr(y, 'use', [])): + self.java_use_rec(x) + @feature('javac') @before_method('propagate_uselib_vars') @after_method('apply_java') @@ -114,7 +223,8 @@ def use_javac_files(self): """ Processes the *use* attribute referring to other java compilations """ - lst = [] + self.use_lst = [] + self.tmp_use_seen = [] self.uselib = self.to_list(getattr(self, 'uselib', [])) names = self.to_list(getattr(self, 'use', [])) get = self.bld.get_tgen_by_name @@ -126,12 +236,17 @@ def use_javac_files(self): else: y.post() if hasattr(y, 'jar_task'): - lst.append(y.jar_task.outputs[0].abspath()) + self.use_lst.append(y.jar_task.outputs[0].abspath()) self.javac_task.set_run_after(y.jar_task) else: for tsk in y.tasks: self.javac_task.set_run_after(tsk) - self.env.append_value('CLASSPATH', lst) + + # If recurse use scan is enabled recursively add use attribute for each used one + if getattr(self, 'recurse_use', False) or self.bld.env.RECURSE_JAVA: + self.java_use_rec(x) + + self.env.append_value('CLASSPATH', self.use_lst) @feature('javac') @after_method('apply_java', 'propagate_uselib_vars', 'use_javac_files') @@ -245,7 +360,7 @@ class jar_create(JTask): return Task.ASK_LATER if not self.inputs: try: - self.inputs = [x for x in self.basedir.ant_glob(JAR_RE, remove=False) if id(x) != id(self.outputs[0])] + self.inputs = [x for x in self.basedir.ant_glob(JAR_RE, remove=False, quiet=True) if id(x) != id(self.outputs[0])] except Exception: raise Errors.WafError('Could not find the basedir %r for %r' % (self.basedir, self)) return super(jar_create, self).runnable_status() @@ -279,14 +394,14 @@ class javac(JTask): self.inputs = [] for x in self.srcdir: if x.exists(): - self.inputs.extend(x.ant_glob(SOURCE_RE, remove=False)) + self.inputs.extend(x.ant_glob(SOURCE_RE, remove=False, quiet=True)) return super(javac, self).runnable_status() def post_run(self): """ List class files created """ - for node in self.generator.outdir.ant_glob('**/*.class'): + for node in self.generator.outdir.ant_glob('**/*.class', quiet=True): self.generator.bld.node_sigs[node] = self.uid() self.generator.bld.task_sigs[self.uid()] = self.cache_sig @@ -338,7 +453,7 @@ class javadoc(Task.Task): self.generator.bld.cmd_and_log(lst, cwd=wd, env=env.env or None, quiet=0) def post_run(self): - nodes = self.generator.javadoc_output.ant_glob('**') + nodes = self.generator.javadoc_output.ant_glob('**', quiet=True) for node in nodes: self.generator.bld.node_sigs[node] = self.uid() self.generator.bld.task_sigs[self.uid()] = self.cache_sig diff --git a/Tools/md5_tstamp.py b/Tools/md5_tstamp.py index 6428e46..2a58792 100644 --- a/Tools/md5_tstamp.py +++ b/Tools/md5_tstamp.py @@ -2,8 +2,7 @@ # encoding: utf-8 """ -Re-calculate md5 hashes of files only when the file times or the file -size have changed. +Re-calculate md5 hashes of files only when the file time have changed. The hashes can also reflect either the file contents (STRONGEST=True) or the file time and file size. diff --git a/Tools/msvc.py b/Tools/msvc.py index 17b347d..ff58449 100644 --- a/Tools/msvc.py +++ b/Tools/msvc.py @@ -281,7 +281,7 @@ def gather_wince_supported_platforms(): def gather_msvc_detected_versions(): #Detected MSVC versions! - version_pattern = re.compile('^(\d\d?\.\d\d?)(Exp)?$') + version_pattern = re.compile(r'^(\d\d?\.\d\d?)(Exp)?$') detected_versions = [] for vcver,vcvar in (('VCExpress','Exp'), ('VisualStudio','')): prefix = 'SOFTWARE\\Wow6432node\\Microsoft\\' + vcver @@ -367,7 +367,7 @@ def gather_wsdk_versions(conf, versions): :param versions: list to modify :type versions: list """ - version_pattern = re.compile('^v..?.?\...?.?') + version_pattern = re.compile(r'^v..?.?\...?.?') try: all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Microsoft\\Microsoft SDKs\\Windows') except OSError: @@ -525,7 +525,7 @@ def gather_icl_versions(conf, versions): :param versions: list to modify :type versions: list """ - version_pattern = re.compile('^...?.?\....?.?') + version_pattern = re.compile(r'^...?.?\....?.?') try: all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Intel\\Compilers\\C++') except OSError: @@ -579,7 +579,7 @@ def gather_intel_composer_versions(conf, versions): :param versions: list to modify :type versions: list """ - version_pattern = re.compile('^...?.?\...?.?.?') + version_pattern = re.compile(r'^...?.?\...?.?.?') try: all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Intel\\Suites') except OSError: @@ -683,7 +683,7 @@ def find_lt_names_msvc(self, libname, is_static=False): if not is_static and ltdict.get('library_names', ''): dllnames=ltdict['library_names'].split() dll=dllnames[0].lower() - dll=re.sub('\.dll$', '', dll) + dll=re.sub(r'\.dll$', '', dll) return (lt_libdir, dll, False) elif ltdict.get('old_library', ''): olib=ltdict['old_library'] @@ -700,7 +700,7 @@ def find_lt_names_msvc(self, libname, is_static=False): @conf def libname_msvc(self, libname, is_static=False): lib = libname.lower() - lib = re.sub('\.lib$','',lib) + lib = re.sub(r'\.lib$','',lib) if lib in g_msvc_systemlibs: return lib @@ -747,11 +747,11 @@ def libname_msvc(self, libname, is_static=False): for libn in libnames: if os.path.exists(os.path.join(path, libn)): Logs.debug('msvc: lib found: %s', os.path.join(path,libn)) - return re.sub('\.lib$', '',libn) + return re.sub(r'\.lib$', '',libn) #if no lib can be found, just return the libname as msvc expects it self.fatal('The library %r could not be found' % libname) - return re.sub('\.lib$', '', libname) + return re.sub(r'\.lib$', '', libname) @conf def check_lib_msvc(self, libname, is_static=False, uselib_store=None): diff --git a/Tools/python.py b/Tools/python.py index 25841d0..01a2c9a 100644 --- a/Tools/python.py +++ b/Tools/python.py @@ -329,6 +329,10 @@ def check_python_headers(conf, features='pyembed pyext'): conf.find_program([''.join(pybin) + '-config', 'python%s-config' % num, 'python-config-%s' % num, 'python%sm-config' % num], var='PYTHON_CONFIG', msg="python-config", mandatory=False) if env.PYTHON_CONFIG: + # check python-config output only once + if conf.env.HAVE_PYTHON_H: + return + # python2.6-config requires 3 runs all_flags = [['--cflags', '--libs', '--ldflags']] if sys.hexversion < 0x2070000: diff --git a/Tools/qt5.py b/Tools/qt5.py index 4f9c690..9f43280 100644 --- a/Tools/qt5.py +++ b/Tools/qt5.py @@ -313,11 +313,11 @@ def apply_qt5(self): The additional parameters are: - :param lang: list of translation files (\*.ts) to process + :param lang: list of translation files (\\*.ts) to process :type lang: list of :py:class:`waflib.Node.Node` or string without the .ts extension - :param update: whether to process the C++ files to update the \*.ts files (use **waf --translate**) + :param update: whether to process the C++ files to update the \\*.ts files (use **waf --translate**) :type update: bool - :param langname: if given, transform the \*.ts files into a .qrc files to include in the binary file + :param langname: if given, transform the \\*.ts files into a .qrc files to include in the binary file :type langname: :py:class:`waflib.Node.Node` or string without the .qrc extension """ if getattr(self, 'lang', None): @@ -762,7 +762,7 @@ def set_qt5_libs_to_check(self): if self.environ.get('QT5_FORCE_STATIC'): pat = self.env.cxxstlib_PATTERN if Utils.unversioned_sys_platform() == 'darwin': - pat = "%s\.framework" + pat = r"%s\.framework" re_qt = re.compile(pat%'Qt5?(?P.*)'+'$') for x in dirlst: m = re_qt.match(x) diff --git a/Tools/waf_unit_test.py b/Tools/waf_unit_test.py index a71ed1c..74d6c05 100644 --- a/Tools/waf_unit_test.py +++ b/Tools/waf_unit_test.py @@ -205,7 +205,7 @@ class utest(Task.Task): return self.exec_command(self.ut_exec) def exec_command(self, cmd, **kw): - Logs.debug('runner: %r', cmd) + self.generator.bld.log_command(cmd, kw) if getattr(Options.options, 'dump_test_scripts', False): script_code = SCRIPT_TEMPLATE % { 'python': sys.executable, diff --git a/Tools/winres.py b/Tools/winres.py index 586c596..9be1ed6 100644 --- a/Tools/winres.py +++ b/Tools/winres.py @@ -24,8 +24,8 @@ def rc_file(self, node): self.compiled_tasks = [rctask] re_lines = re.compile( - '(?:^[ \t]*(#|%:)[ \t]*(ifdef|ifndef|if|else|elif|endif|include|import|define|undef|pragma)[ \t]*(.*?)\s*$)|'\ - '(?:^\w+[ \t]*(ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)[ \t]*(.*?)\s*$)', + r'(?:^[ \t]*(#|%:)[ \t]*(ifdef|ifndef|if|else|elif|endif|include|import|define|undef|pragma)[ \t]*(.*?)\s*$)|'\ + r'(?:^\w+[ \t]*(ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)[ \t]*(.*?)\s*$)', re.IGNORECASE | re.MULTILINE) class rc_parser(c_preproc.c_parser): diff --git a/Utils.py b/Utils.py index b4665c4..4b808a8 100644 --- a/Utils.py +++ b/Utils.py @@ -49,10 +49,16 @@ try: from hashlib import md5 except ImportError: try: - from md5 import md5 + from hashlib import sha1 as md5 except ImportError: - # never fail to enable fixes from another module + # never fail to enable potential fixes from another module pass +else: + try: + md5().digest() + except ValueError: + # Fips? #2213 + from hashlib import sha1 as md5 try: import threading @@ -202,7 +208,7 @@ class lazy_generator(object): next = __next__ -is_win32 = os.sep == '\\' or sys.platform == 'win32' # msys2 +is_win32 = os.sep == '\\' or sys.platform == 'win32' or os.name == 'nt' # msys2 """ Whether this system is a Windows series """ @@ -484,7 +490,9 @@ def split_path_msys(path): if sys.platform == 'cygwin': split_path = split_path_cygwin elif is_win32: - if os.environ.get('MSYSTEM'): + # Consider this an MSYSTEM environment if $MSYSTEM is set and python + # reports is executable from a unix like path on a windows host. + if os.environ.get('MSYSTEM') and sys.executable.startswith('/'): split_path = split_path_msys else: split_path = split_path_win32 @@ -730,7 +738,7 @@ def unversioned_sys_platform(): if s == 'cli' and os.name == 'nt': # ironpython is only on windows as far as we know return 'win32' - return re.split('\d+$', s)[0] + return re.split(r'\d+$', s)[0] def nada(*k, **kw): """ diff --git a/ansiterm.py b/ansiterm.py index 0d20c63..027f0ad 100644 --- a/ansiterm.py +++ b/ansiterm.py @@ -264,7 +264,7 @@ else: 'u': pop_cursor, } # Match either the escape sequence or text not containing escape sequence - ansi_tokens = re.compile('(?:\x1b\[([0-9?;]*)([a-zA-Z])|([^\x1b]+))') + ansi_tokens = re.compile(r'(?:\x1b\[([0-9?;]*)([a-zA-Z])|([^\x1b]+))') def write(self, text): try: wlock.acquire() diff --git a/extras/buildcopy.py b/extras/buildcopy.py index a6d9ac8..eaff7e6 100644 --- a/extras/buildcopy.py +++ b/extras/buildcopy.py @@ -22,7 +22,7 @@ Examples:: """ import os, shutil -from waflib import Errors, Task, TaskGen, Utils, Node +from waflib import Errors, Task, TaskGen, Utils, Node, Logs @TaskGen.before_method('process_source') @TaskGen.feature('buildcopy') @@ -58,10 +58,13 @@ def make_buildcopy(self): raise Errors.WafError('buildcopy: File not found in src: %s'%os.path.join(*lst)) nodes = [ to_src_nodes(n) for n in getattr(self, 'buildcopy_source', getattr(self, 'source', [])) ] + if not nodes: + Logs.warn('buildcopy: No source files provided to buildcopy in %s (set `buildcopy_source` or `source`)', + self) + return node_pairs = [(n, n.get_bld()) for n in nodes] self.create_task('buildcopy', [n[0] for n in node_pairs], [n[1] for n in node_pairs], node_pairs=node_pairs) - class buildcopy(Task.Task): """ Copy for each pair `n` in `node_pairs`: n[0] -> n[1]. diff --git a/extras/cpplint.py b/extras/cpplint.py index e3302e5..8cdd6dd 100644 --- a/extras/cpplint.py +++ b/extras/cpplint.py @@ -43,12 +43,12 @@ from waflib import Errors, Task, TaskGen, Logs, Options, Node, Utils critical_errors = 0 CPPLINT_FORMAT = '[CPPLINT] %(filename)s:\nline %(linenum)s, severity %(confidence)s, category: %(category)s\n%(message)s\n' -RE_EMACS = re.compile('(?P.*):(?P\d+): (?P.*) \[(?P.*)\] \[(?P\d+)\]') +RE_EMACS = re.compile(r'(?P.*):(?P\d+): (?P.*) \[(?P.*)\] \[(?P\d+)\]') CPPLINT_RE = { 'waf': RE_EMACS, 'emacs': RE_EMACS, - 'vs7': re.compile('(?P.*)\((?P\d+)\): (?P.*) \[(?P.*)\] \[(?P\d+)\]'), - 'eclipse': re.compile('(?P.*):(?P\d+): warning: (?P.*) \[(?P.*)\] \[(?P\d+)\]'), + 'vs7': re.compile(r'(?P.*)\((?P\d+)\): (?P.*) \[(?P.*)\] \[(?P\d+)\]'), + 'eclipse': re.compile(r'(?P.*):(?P\d+): warning: (?P.*) \[(?P.*)\] \[(?P\d+)\]'), } CPPLINT_STR = ('${CPPLINT} ' '--verbose=${CPPLINT_LEVEL} ' diff --git a/extras/cython.py b/extras/cython.py index 481d6f4..591c274 100644 --- a/extras/cython.py +++ b/extras/cython.py @@ -8,8 +8,9 @@ from waflib.TaskGen import extension cy_api_pat = re.compile(r'\s*?cdef\s*?(public|api)\w*') re_cyt = re.compile(r""" - (?:from\s+(\w+)\s+)? # optionally match "from foo" and capture foo - c?import\s(\w+|[*]) # require "import bar" and capture bar + ^\s* # must begin with some whitespace characters + (?:from\s+(\w+)(?:\.\w+)*\s+)? # optionally match "from foo(.baz)" and capture foo + c?import\s(\w+|[*]) # require "import bar" and capture bar """, re.M | re.VERBOSE) @extension('.pyx') @@ -85,12 +86,12 @@ class cython(Task.Task): node = self.inputs[0] txt = node.read() - mods = [] + mods = set() for m in re_cyt.finditer(txt): if m.group(1): # matches "from foo import bar" - mods.append(m.group(1)) + mods.add(m.group(1)) else: - mods.append(m.group(2)) + mods.add(m.group(2)) Logs.debug('cython: mods %r', mods) incs = getattr(self.generator, 'cython_includes', []) @@ -99,7 +100,7 @@ class cython(Task.Task): found = [] missing = [] - for x in mods: + for x in sorted(mods): for y in incs: k = y.find_resource(x + '.pxd') if k: diff --git a/extras/distnet.py b/extras/distnet.py index 09a31a6..ff3ed8e 100644 --- a/extras/distnet.py +++ b/extras/distnet.py @@ -44,7 +44,7 @@ TARFORMAT = 'w:bz2' TIMEOUT = 60 REQUIRES = 'requires.txt' -re_com = re.compile('\s*#.*', re.M) +re_com = re.compile(r'\s*#.*', re.M) def total_version_order(num): lst = num.split('.') diff --git a/extras/erlang.py b/extras/erlang.py index 49f6d5b..0b93d9a 100644 --- a/extras/erlang.py +++ b/extras/erlang.py @@ -51,7 +51,7 @@ class erl(Task.Task): if n.abspath() in scanned: continue - for i in re.findall('-include\("(.*)"\)\.', n.read()): + for i in re.findall(r'-include\("(.*)"\)\.', n.read()): for d in task.erlc_incnodes: r = d.find_node(i) if r: diff --git a/extras/fast_partial.py b/extras/fast_partial.py index b3af513..d5b6144 100644 --- a/extras/fast_partial.py +++ b/extras/fast_partial.py @@ -17,7 +17,7 @@ Usage:: def options(opt): opt.load('fast_partial') -Assuptions: +Assumptions: * Mostly for C/C++/Fortran targets with link tasks (object-only targets are not handled) * For full project builds: no --targets and no pruning from subfolders * The installation phase is ignored diff --git a/extras/fc_nfort.py b/extras/fc_nfort.py new file mode 100644 index 0000000..c25886b --- /dev/null +++ b/extras/fc_nfort.py @@ -0,0 +1,52 @@ +#! /usr/bin/env python +# encoding: utf-8 +# Detection of the NEC Fortran compiler for Aurora Tsubasa + +import re +from waflib.Tools import fc,fc_config,fc_scan +from waflib.Configure import conf +from waflib.Tools.compiler_fc import fc_compiler +fc_compiler['linux'].append('fc_nfort') + +@conf +def find_nfort(conf): + fc=conf.find_program(['nfort'],var='FC') + conf.get_nfort_version(fc) + conf.env.FC_NAME='NFORT' + conf.env.FC_MOD_CAPITALIZATION='lower' + +@conf +def nfort_flags(conf): + v=conf.env + v['_FCMODOUTFLAGS']=[] + v['FCFLAGS_DEBUG']=[] + v['FCFLAGS_fcshlib']=[] + v['LINKFLAGS_fcshlib']=[] + v['FCSTLIB_MARKER']='' + v['FCSHLIB_MARKER']='' + +@conf +def get_nfort_version(conf,fc): + version_re=re.compile(r"nfort\s*\(NFORT\)\s*(?P\d+)\.(?P\d+)\.",re.I).search + cmd=fc+['--version'] + out,err=fc_config.getoutput(conf,cmd,stdin=False) + if out: + match=version_re(out) + else: + match=version_re(err) + if not match: + return(False) + conf.fatal('Could not determine the NEC NFORT Fortran compiler version.') + else: + k=match.groupdict() + conf.env['FC_VERSION']=(k['major'],k['minor']) + +def configure(conf): + conf.find_nfort() + conf.find_program('nar',var='AR') + conf.add_os_flags('ARFLAGS') + if not conf.env.ARFLAGS: + conf.env.ARFLAGS=['rcs'] + conf.fc_flags() + conf.fc_add_flags() + conf.nfort_flags() diff --git a/extras/gccdeps.py b/extras/gccdeps.py index d9758ab..bfabe72 100644 --- a/extras/gccdeps.py +++ b/extras/gccdeps.py @@ -36,7 +36,7 @@ def scan(self): names = [] return (nodes, names) -re_o = re.compile("\.o$") +re_o = re.compile(r"\.o$") re_splitter = re.compile(r'(? '2': - m = re.search(r'^message\s+(\w*)\s*{*', line) - if m: - messages.append(m.groups()[0]) - - if javapkg: - nodename = javapkg - elif pkgname: - nodename = pkgname - else: - raise Errors.WafError('Cannot derive java name from protoc file') - - nodename = nodename.replace('.',os.sep) + os.sep - if javacn: - nodename += javacn + '.java' - else: - if self.env.PROTOC_MAJOR > '2' and node.abspath()[node.abspath().rfind(os.sep)+1:node.abspath().rfind('.')].title() in messages: - nodename += node.abspath()[node.abspath().rfind(os.sep)+1:node.abspath().rfind('.')].title().replace('_','') + 'OuterClass.java' - else: - nodename += node.abspath()[node.abspath().rfind(os.sep)+1:node.abspath().rfind('.')].title().replace('_','') + '.java' - - java_node = node.parent.find_or_declare(nodename) - out_nodes.append(java_node) - protoc_flags.append('--java_out=%s' % node.parent.get_bld().bldpath()) - # Make javac get also pick java code generated in build if not node.parent.get_bld() in self.javac_task.srcdir: self.javac_task.srcdir.append(node.parent.get_bld()) - if not out_nodes: - raise Errors.WafError('Feature %r not supported by protoc extra' % self.features) + protoc_flags.append('--java_out=%s' % node.parent.get_bld().bldpath()) tsk = self.create_task('protoc', node, out_nodes) tsk.env.append_value('PROTOC_FLAGS', protoc_flags) @@ -219,9 +186,22 @@ def process_protoc(self, node): # For C++ standard include files dirs are used, # but this doesn't apply to Python for example for incpath in getattr(self, 'protoc_includes', []): - incdirs.append(self.path.find_node(incpath).bldpath()) + incpath_node = self.path.find_node(incpath) + if incpath_node: + incdirs.append(incpath_node.bldpath()) + else: + # Check if relative to top-level for extra tg dependencies + incpath_node = self.bld.path.find_node(incpath) + if incpath_node: + incdirs.append(incpath_node.bldpath()) + else: + raise Errors.WafError('protoc: include path %r does not exist' % incpath) + tsk.env.PROTOC_INCPATHS = incdirs + # Include paths external to the waf project (ie. shared pb repositories) + tsk.env.PROTOC_EXTINCPATHS = getattr(self, 'protoc_extincludes', []) + # PR2115: protoc generates output of .proto files in nested # directories by canonicalizing paths. To avoid this we have to pass # as first include the full directory file of the .proto file diff --git a/extras/pyqt5.py b/extras/pyqt5.py index c21dfa7..80f43b8 100644 --- a/extras/pyqt5.py +++ b/extras/pyqt5.py @@ -111,9 +111,9 @@ def apply_pyqt5(self): """ The additional parameters are: - :param lang: list of translation files (\*.ts) to process + :param lang: list of translation files (\\*.ts) to process :type lang: list of :py:class:`waflib.Node.Node` or string without the .ts extension - :param langname: if given, transform the \*.ts files into a .qrc files to include in the binary file + :param langname: if given, transform the \\*.ts files into a .qrc files to include in the binary file :type langname: :py:class:`waflib.Node.Node` or string without the .qrc extension """ if getattr(self, 'lang', None): diff --git a/extras/qt4.py b/extras/qt4.py index 90cae7e..d19a4dd 100644 --- a/extras/qt4.py +++ b/extras/qt4.py @@ -290,11 +290,11 @@ def apply_qt4(self): The additional parameters are: - :param lang: list of translation files (\*.ts) to process + :param lang: list of translation files (\\*.ts) to process :type lang: list of :py:class:`waflib.Node.Node` or string without the .ts extension - :param update: whether to process the C++ files to update the \*.ts files (use **waf --translate**) + :param update: whether to process the C++ files to update the \\*.ts files (use **waf --translate**) :type update: bool - :param langname: if given, transform the \*.ts files into a .qrc files to include in the binary file + :param langname: if given, transform the \\*.ts files into a .qrc files to include in the binary file :type langname: :py:class:`waflib.Node.Node` or string without the .qrc extension """ if getattr(self, 'lang', None): diff --git a/extras/remote.py b/extras/remote.py index 3b038f7..f43b600 100644 --- a/extras/remote.py +++ b/extras/remote.py @@ -203,7 +203,7 @@ class remote(BuildContext): Options.commands.remove(k) def login_to_host(self, login): - return re.sub('(\w+@)', '', login) + return re.sub(r'(\w+@)', '', login) def variant_to_login(self, variant): """linux_32_debug -> search env.LINUX_32 and then env.LINUX""" diff --git a/extras/run_do_script.py b/extras/run_do_script.py index f3c5812..07e3aa2 100644 --- a/extras/run_do_script.py +++ b/extras/run_do_script.py @@ -101,7 +101,7 @@ class run_do_script(run_do_script_base): with open(**kwargs) as log: log_tail = log.readlines()[-10:] for line in log_tail: - error_found = re.match("r\(([0-9]+)\)", line) + error_found = re.match(r"r\(([0-9]+)\)", line) if error_found: return error_found.group(1), ''.join(log_tail) else: diff --git a/extras/swig.py b/extras/swig.py index fd3d6d2..740ab46 100644 --- a/extras/swig.py +++ b/extras/swig.py @@ -17,10 +17,10 @@ tasks have to be added dynamically: SWIG_EXTS = ['.swig', '.i'] -re_module = re.compile('%module(?:\s*\(.*\))?\s+(.+)', re.M) +re_module = re.compile(r'%module(?:\s*\(.*\))?\s+(.+)', re.M) re_1 = re.compile(r'^%module.*?\s+([\w]+)\s*?$', re.M) -re_2 = re.compile('[#%]include [<"](.*)[">]', re.M) +re_2 = re.compile(r'[#%](?:include|import(?:\(module=".*"\))+|python(?:begin|code)) [<"](.*)[">]', re.M) class swig(Task.Task): color = 'BLUE' -- cgit v1.2.1