mirror of https://gitlab.com/ita1024/waf.git
Api docs
This commit is contained in:
parent
ef6525c0bf
commit
eaa83004c8
191
waflib/Task.py
191
waflib/Task.py
|
@ -70,14 +70,17 @@ def f(tsk):
|
||||||
'''
|
'''
|
||||||
|
|
||||||
classes = {}
|
classes = {}
|
||||||
"Class tasks created by user scripts or Waf tools (maps names to class objects). Task classes defined in Waf tools are registered here through the metaclass :py:class:`waflib.Task.store_task_type`."
|
"""
|
||||||
|
The metaclass :py:class:`waflib.Task.store_task_type` stores all class tasks
|
||||||
|
created by user scripts or Waf tools to this dict. It maps class names to class objects.
|
||||||
|
"""
|
||||||
|
|
||||||
class store_task_type(type):
|
class store_task_type(type):
|
||||||
"""
|
"""
|
||||||
Metaclass: store the task classes into :py:const:`waflib.Task.classes`, or to the dict pointed
|
Metaclass: store the task classes into the dict pointed by the
|
||||||
by the class attribute 'register'.
|
class attribute 'register' which defaults to :py:const:`waflib.Task.classes`,
|
||||||
The attribute 'run_str' will be processed to compute a method 'run' on the task class
|
|
||||||
The decorator :py:func:`waflib.Task.cache_outputs` is also applied to the class
|
The attribute 'run_str' is compiled into a method 'run' bound to the task class.
|
||||||
"""
|
"""
|
||||||
def __init__(cls, name, bases, dict):
|
def __init__(cls, name, bases, dict):
|
||||||
super(store_task_type, cls).__init__(name, bases, dict)
|
super(store_task_type, cls).__init__(name, bases, dict)
|
||||||
|
@ -112,24 +115,22 @@ class TaskBase(evil):
|
||||||
'fun' in :py:meth:`waflib.Task.TaskBase.run`. When in doubt, create
|
'fun' in :py:meth:`waflib.Task.TaskBase.run`. When in doubt, create
|
||||||
subclasses of :py:class:`waflib.Task.Task` instead.
|
subclasses of :py:class:`waflib.Task.Task` instead.
|
||||||
|
|
||||||
Subclasses should override these methods:
|
Subclasses must override these methods:
|
||||||
|
|
||||||
#. __str__: string to display to the user
|
#. __str__: string to display to the user
|
||||||
#. runnable_status: ask the task if it should be run, skipped, or if we have to ask later
|
#. runnable_status: ask the task if it should be run, skipped, or if we have to ask later
|
||||||
#. run: let threads execute the task
|
#. run: what to do to execute the task
|
||||||
#. post_run: let threads update the data regarding the task (cache)
|
#. post_run: what to do after the task has been executed
|
||||||
|
|
||||||
.. warning:: For backward compatibility reasons, the suffix "_task" is truncated in derived class names. This limitation will be removed in Waf 1.9.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
color = 'GREEN'
|
color = 'GREEN'
|
||||||
"""Color for the console display, see :py:const:`waflib.Logs.colors_lst`"""
|
"""Color for the console display, see :py:const:`waflib.Logs.colors_lst`"""
|
||||||
|
|
||||||
ext_in = []
|
ext_in = []
|
||||||
"""File extensions that objects of this task class might use"""
|
"""File extensions that objects of this task class may use"""
|
||||||
|
|
||||||
ext_out = []
|
ext_out = []
|
||||||
"""File extensions that objects of this task class might create"""
|
"""File extensions that objects of this task class may create"""
|
||||||
|
|
||||||
before = []
|
before = []
|
||||||
"""List of task class names to execute before instances of this class"""
|
"""List of task class names to execute before instances of this class"""
|
||||||
|
@ -144,7 +145,7 @@ class TaskBase(evil):
|
||||||
|
|
||||||
def __init__(self, *k, **kw):
|
def __init__(self, *k, **kw):
|
||||||
"""
|
"""
|
||||||
The base task class requires a task generator, which will be itself if missing
|
The base task class requires a task generator (set to *self* if missing)
|
||||||
"""
|
"""
|
||||||
self.hasrun = NOT_RUN
|
self.hasrun = NOT_RUN
|
||||||
try:
|
try:
|
||||||
|
@ -153,21 +154,25 @@ class TaskBase(evil):
|
||||||
self.generator = self
|
self.generator = self
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
"for debugging purposes"
|
|
||||||
return '\n\t{task %r: %s %s}' % (self.__class__.__name__, id(self), str(getattr(self, 'fun', '')))
|
return '\n\t{task %r: %s %s}' % (self.__class__.__name__, id(self), str(getattr(self, 'fun', '')))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"string to display to the user"
|
"String to display to the user"
|
||||||
if hasattr(self, 'fun'):
|
if hasattr(self, 'fun'):
|
||||||
return self.fun.__name__
|
return self.fun.__name__
|
||||||
return self.__class__.__name__
|
return self.__class__.__name__
|
||||||
|
|
||||||
def keyword(self):
|
def keyword(self):
|
||||||
|
"Display keyword used to prettify the console outputs"
|
||||||
if hasattr(self, 'fun'):
|
if hasattr(self, 'fun'):
|
||||||
return 'Function'
|
return 'Function'
|
||||||
return 'Processing'
|
return 'Processing'
|
||||||
|
|
||||||
def get_cwd(self):
|
def get_cwd(self):
|
||||||
|
"""
|
||||||
|
:return: current working directory
|
||||||
|
:rtype: :py:class:`waflib.Node.Node`
|
||||||
|
"""
|
||||||
bld = self.generator.bld
|
bld = self.generator.bld
|
||||||
ret = getattr(self, 'cwd', None) or getattr(self.generator.bld, 'cwd', bld.bldnode)
|
ret = getattr(self, 'cwd', None) or getattr(self.generator.bld, 'cwd', bld.bldnode)
|
||||||
if isinstance(ret, str):
|
if isinstance(ret, str):
|
||||||
|
@ -175,6 +180,14 @@ class TaskBase(evil):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def quote_flag(self, x):
|
def quote_flag(self, x):
|
||||||
|
"""
|
||||||
|
Surround a process argument by quotes so that a list of arguments can be written to a file
|
||||||
|
|
||||||
|
:param x: flag
|
||||||
|
:type x: string
|
||||||
|
:return: quoted flag
|
||||||
|
:rtype: string
|
||||||
|
"""
|
||||||
old = x
|
old = x
|
||||||
if '\\' in x:
|
if '\\' in x:
|
||||||
x = x.replace('\\', '\\\\')
|
x = x.replace('\\', '\\\\')
|
||||||
|
@ -185,12 +198,23 @@ class TaskBase(evil):
|
||||||
return x
|
return x
|
||||||
|
|
||||||
def split_argfile(self, cmd):
|
def split_argfile(self, cmd):
|
||||||
|
"""
|
||||||
|
Splits a list of process commands into the executable part and its list of arguments
|
||||||
|
|
||||||
|
:return: a tuple containing the executable first and then the rest of arguments
|
||||||
|
:rtype: tuple
|
||||||
|
"""
|
||||||
return ([cmd[0]], [self.quote_flag(x) for x in cmd[1:]])
|
return ([cmd[0]], [self.quote_flag(x) for x in cmd[1:]])
|
||||||
|
|
||||||
def exec_command(self, cmd, **kw):
|
def exec_command(self, cmd, **kw):
|
||||||
"""
|
"""
|
||||||
Wrapper for :py:meth:`waflib.Context.Context.exec_command` which sets a current working directory to ``build.variant_dir``
|
Wrapper for :py:meth:`waflib.Context.Context.exec_command`.
|
||||||
|
This version set the current working directory (``build.variant_dir``),
|
||||||
|
applies PATH settings (if self.env.PATH is provided), and can run long
|
||||||
|
commands through a temporary ``@argfile``.
|
||||||
|
|
||||||
|
:param cmd: process command to execute
|
||||||
|
:type cmd: list of string (best) or string (process will use a shell)
|
||||||
:return: the return code
|
:return: the return code
|
||||||
:rtype: int
|
:rtype: int
|
||||||
"""
|
"""
|
||||||
|
@ -221,7 +245,7 @@ class TaskBase(evil):
|
||||||
|
|
||||||
def runnable_status(self):
|
def runnable_status(self):
|
||||||
"""
|
"""
|
||||||
State of the task
|
Returns the Task status
|
||||||
|
|
||||||
:return: a task state in :py:const:`waflib.Task.RUN_ME`, :py:const:`waflib.Task.SKIP_ME` or :py:const:`waflib.Task.ASK_LATER`.
|
:return: a task state in :py:const:`waflib.Task.RUN_ME`, :py:const:`waflib.Task.SKIP_ME` or :py:const:`waflib.Task.ASK_LATER`.
|
||||||
:rtype: int
|
:rtype: int
|
||||||
|
@ -229,12 +253,20 @@ class TaskBase(evil):
|
||||||
return RUN_ME
|
return RUN_ME
|
||||||
|
|
||||||
def uid(self):
|
def uid(self):
|
||||||
|
"""
|
||||||
|
Computes a unique identifier for the task
|
||||||
|
|
||||||
|
:rtype: string or bytes
|
||||||
|
"""
|
||||||
return Utils.SIG_NIL
|
return Utils.SIG_NIL
|
||||||
|
|
||||||
def process(self):
|
def process(self):
|
||||||
"""
|
"""
|
||||||
Assume that the task has had a ``master`` which is an instance of :py:class:`waflib.Runner.Parallel`.
|
Assume that the task has had a ``master`` which is an instance of :py:class:`waflib.Runner.Parallel`.
|
||||||
Execute the task and then put it back in the queue :py:attr:`waflib.Runner.Parallel.out` (may be replaced by subclassing).
|
Execute the task and then put it back in the queue :py:attr:`waflib.Runner.Parallel.out` (may be replaced by subclassing).
|
||||||
|
|
||||||
|
:return: 0 or None if everything is fine
|
||||||
|
:rtype: integer
|
||||||
"""
|
"""
|
||||||
# remove the task signature immediately before it is executed
|
# remove the task signature immediately before it is executed
|
||||||
# in case of failure the task will be executed again
|
# in case of failure the task will be executed again
|
||||||
|
@ -274,7 +306,8 @@ class TaskBase(evil):
|
||||||
def run(self):
|
def run(self):
|
||||||
"""
|
"""
|
||||||
Called by threads to execute the tasks. The default is empty and meant to be overridden in subclasses.
|
Called by threads to execute the tasks. The default is empty and meant to be overridden in subclasses.
|
||||||
It is a bad idea to create nodes in this method (so, no node.ant_glob)
|
|
||||||
|
.. warning:: It is a bad idea to create nodes in this method, so avoid :py:meth:`waflib.Node.Node.ant_glob`
|
||||||
|
|
||||||
:rtype: int
|
:rtype: int
|
||||||
"""
|
"""
|
||||||
|
@ -283,11 +316,11 @@ class TaskBase(evil):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def post_run(self):
|
def post_run(self):
|
||||||
"Update the cache files (executed by threads). Override in subclasses."
|
"Update build data after successful Task execution. Override in subclasses."
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def log_display(self, bld):
|
def log_display(self, bld):
|
||||||
"Write the execution status on the context logger"
|
"Writes the execution status on the context logger"
|
||||||
if self.generator.bld.progress_bar == 3:
|
if self.generator.bld.progress_bar == 3:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -307,7 +340,7 @@ class TaskBase(evil):
|
||||||
|
|
||||||
def display(self):
|
def display(self):
|
||||||
"""
|
"""
|
||||||
Return an execution status for the console, the progress bar, or the IDE output.
|
Returns an execution status for the console, the progress bar, or the IDE output.
|
||||||
|
|
||||||
:rtype: string
|
:rtype: string
|
||||||
"""
|
"""
|
||||||
|
@ -351,19 +384,18 @@ class TaskBase(evil):
|
||||||
|
|
||||||
def hash_constraints(self):
|
def hash_constraints(self):
|
||||||
"""
|
"""
|
||||||
Identify a task type for all the constraints relevant for the scheduler: precedence, file production
|
Identifies a task type for all the constraints relevant for the scheduler: precedence, file production
|
||||||
|
|
||||||
:return: a hash value
|
:return: a hash value
|
||||||
:rtype: string
|
:rtype: string
|
||||||
"""
|
"""
|
||||||
cls = self.__class__
|
cls = self.__class__
|
||||||
tup = (str(cls.before), str(cls.after), str(cls.ext_in), str(cls.ext_out), cls.__name__, cls.hcode)
|
tup = (str(cls.before), str(cls.after), str(cls.ext_in), str(cls.ext_out), cls.__name__, cls.hcode)
|
||||||
h = hash(tup)
|
return hash(tup)
|
||||||
return h
|
|
||||||
|
|
||||||
def format_error(self):
|
def format_error(self):
|
||||||
"""
|
"""
|
||||||
Error message to display to the user when a build fails
|
Returns an error message to display the build failure reasons
|
||||||
|
|
||||||
:rtype: string
|
:rtype: string
|
||||||
"""
|
"""
|
||||||
|
@ -385,7 +417,7 @@ class TaskBase(evil):
|
||||||
|
|
||||||
def colon(self, var1, var2):
|
def colon(self, var1, var2):
|
||||||
"""
|
"""
|
||||||
Support code for scriptlet expressions such as ${FOO_ST:FOO}
|
Enable scriptlet expressions of the form ${FOO_ST:FOO}
|
||||||
If the first variable (FOO_ST) is empty, then an empty list is returned
|
If the first variable (FOO_ST) is empty, then an empty list is returned
|
||||||
|
|
||||||
The results will be slightly different if FOO_ST is a list, for example::
|
The results will be slightly different if FOO_ST is a list, for example::
|
||||||
|
@ -424,10 +456,10 @@ class Task(TaskBase):
|
||||||
nodes (if present).
|
nodes (if present).
|
||||||
"""
|
"""
|
||||||
vars = []
|
vars = []
|
||||||
"""Variables to depend on (class attribute used for :py:meth:`waflib.Task.Task.sig_vars`)"""
|
"""ConfigSet variables that should trigger a rebuild (class attribute used for :py:meth:`waflib.Task.Task.sig_vars`)"""
|
||||||
|
|
||||||
always_run = False
|
always_run = False
|
||||||
"""Specify whether task instances must always be executed or not"""
|
"""Specify whether task instances must always be executed or not (class attribute)"""
|
||||||
|
|
||||||
shell = False
|
shell = False
|
||||||
"""Execute the command with the shell (class attribute)"""
|
"""Execute the command with the shell (class attribute)"""
|
||||||
|
@ -436,7 +468,7 @@ class Task(TaskBase):
|
||||||
TaskBase.__init__(self, *k, **kw)
|
TaskBase.__init__(self, *k, **kw)
|
||||||
|
|
||||||
self.env = kw['env']
|
self.env = kw['env']
|
||||||
"""ConfigSet object (make sure to provide one)"""
|
""":py:class:`waflib.ConfigSet.ConfigSet` object (make sure to provide one)"""
|
||||||
|
|
||||||
self.inputs = []
|
self.inputs = []
|
||||||
"""List of input nodes, which represent the files used by the task instance"""
|
"""List of input nodes, which represent the files used by the task instance"""
|
||||||
|
@ -470,6 +502,9 @@ class Task(TaskBase):
|
||||||
return '%s: %s%s%s' % (self.__class__.__name__, src_str, sep, tgt_str)
|
return '%s: %s%s%s' % (self.__class__.__name__, src_str, sep, tgt_str)
|
||||||
|
|
||||||
def keyword(self):
|
def keyword(self):
|
||||||
|
"""
|
||||||
|
See :py:meth:`waflib.Task.TaskBase`
|
||||||
|
"""
|
||||||
name = self.__class__.__name__
|
name = self.__class__.__name__
|
||||||
if name.endswith(('lib', 'program')):
|
if name.endswith(('lib', 'program')):
|
||||||
return 'Linking'
|
return 'Linking'
|
||||||
|
@ -494,10 +529,10 @@ class Task(TaskBase):
|
||||||
|
|
||||||
def uid(self):
|
def uid(self):
|
||||||
"""
|
"""
|
||||||
Return an identifier used to determine if tasks are up-to-date. Since the
|
Returns an identifier used to determine if tasks are up-to-date. Since the
|
||||||
identifier will be stored between executions, it must be:
|
identifier will be stored between executions, it must be:
|
||||||
|
|
||||||
- unique: no two tasks return the same value (for a given build context)
|
- unique for a task: no two tasks return the same value (for a given build context)
|
||||||
- the same for a given task instance
|
- the same for a given task instance
|
||||||
|
|
||||||
By default, the node paths, the class name, and the function are used
|
By default, the node paths, the class name, and the function are used
|
||||||
|
@ -521,7 +556,7 @@ class Task(TaskBase):
|
||||||
|
|
||||||
def set_inputs(self, inp):
|
def set_inputs(self, inp):
|
||||||
"""
|
"""
|
||||||
Append the nodes to the *inputs*
|
Appends the nodes to the *inputs* list
|
||||||
|
|
||||||
:param inp: input nodes
|
:param inp: input nodes
|
||||||
:type inp: node or list of nodes
|
:type inp: node or list of nodes
|
||||||
|
@ -531,7 +566,7 @@ class Task(TaskBase):
|
||||||
|
|
||||||
def set_outputs(self, out):
|
def set_outputs(self, out):
|
||||||
"""
|
"""
|
||||||
Append the nodes to the *outputs*
|
Appends the nodes to the *outputs* list
|
||||||
|
|
||||||
:param out: output nodes
|
:param out: output nodes
|
||||||
:type out: node or list of nodes
|
:type out: node or list of nodes
|
||||||
|
@ -541,8 +576,7 @@ class Task(TaskBase):
|
||||||
|
|
||||||
def set_run_after(self, task):
|
def set_run_after(self, task):
|
||||||
"""
|
"""
|
||||||
Run this task only after *task*. Affect :py:meth:`waflib.Task.runnable_status`
|
Run this task only after the given *task*.
|
||||||
You probably want to use tsk.run_after.add(task) directly
|
|
||||||
|
|
||||||
:param task: task
|
:param task: task
|
||||||
:type task: :py:class:`waflib.Task.Task`
|
:type task: :py:class:`waflib.Task.Task`
|
||||||
|
@ -567,9 +601,14 @@ class Task(TaskBase):
|
||||||
sig = super(Task.Task, self).signature()
|
sig = super(Task.Task, self).signature()
|
||||||
delattr(self, 'cache_sig')
|
delattr(self, 'cache_sig')
|
||||||
return super(Task.Task, self).signature()
|
return super(Task.Task, self).signature()
|
||||||
|
|
||||||
|
:return: the signature value
|
||||||
|
:rtype: string or bytes
|
||||||
"""
|
"""
|
||||||
try: return self.cache_sig
|
try:
|
||||||
except AttributeError: pass
|
return self.cache_sig
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
self.m = Utils.md5(self.hcode)
|
self.m = Utils.md5(self.hcode)
|
||||||
|
|
||||||
|
@ -591,8 +630,7 @@ class Task(TaskBase):
|
||||||
|
|
||||||
def runnable_status(self):
|
def runnable_status(self):
|
||||||
"""
|
"""
|
||||||
Override :py:meth:`waflib.Task.TaskBase.runnable_status` to determine if the task is ready
|
See :py:meth:`waflib.Task.TaskBase.runnable_status`
|
||||||
to be run (:py:attr:`waflib.Task.Task.run_after`)
|
|
||||||
"""
|
"""
|
||||||
#return 0 # benchmarking
|
#return 0 # benchmarking
|
||||||
|
|
||||||
|
@ -636,11 +674,8 @@ class Task(TaskBase):
|
||||||
|
|
||||||
def post_run(self):
|
def post_run(self):
|
||||||
"""
|
"""
|
||||||
Called after successful execution to update the cache data :py:class:`waflib.Node.Node` sigs
|
Called after successful execution to record that the task has run by
|
||||||
and :py:attr:`waflib.Build.BuildContext.task_sigs`.
|
updating the entry in :py:attr:`waflib.Build.BuildContext.task_sigs`.
|
||||||
|
|
||||||
The node signature is obtained from the task signature, but the output nodes may also get the signature
|
|
||||||
of their contents. See the class decorator :py:func:`waflib.Task.update_outputs` if you need this behaviour.
|
|
||||||
"""
|
"""
|
||||||
bld = self.generator.bld
|
bld = self.generator.bld
|
||||||
for node in self.outputs:
|
for node in self.outputs:
|
||||||
|
@ -657,7 +692,7 @@ class Task(TaskBase):
|
||||||
|
|
||||||
def sig_explicit_deps(self):
|
def sig_explicit_deps(self):
|
||||||
"""
|
"""
|
||||||
Used by :py:meth:`waflib.Task.Task.signature`, hash :py:attr:`waflib.Task.Task.inputs`
|
Used by :py:meth:`waflib.Task.Task.signature`; it hashes :py:attr:`waflib.Task.Task.inputs`
|
||||||
and :py:attr:`waflib.Task.Task.dep_nodes` signatures.
|
and :py:attr:`waflib.Task.Task.dep_nodes` signatures.
|
||||||
"""
|
"""
|
||||||
bld = self.generator.bld
|
bld = self.generator.bld
|
||||||
|
@ -685,7 +720,7 @@ class Task(TaskBase):
|
||||||
|
|
||||||
def sig_vars(self):
|
def sig_vars(self):
|
||||||
"""
|
"""
|
||||||
Used by :py:meth:`waflib.Task.Task.signature`, hash :py:attr:`waflib.Task.Task.env` variables/values
|
Used by :py:meth:`waflib.Task.Task.signature`; it hashes :py:attr:`waflib.Task.Task.env` variables/values
|
||||||
"""
|
"""
|
||||||
sig = self.generator.bld.hash_env_vars(self.env, self.__class__.vars)
|
sig = self.generator.bld.hash_env_vars(self.env, self.__class__.vars)
|
||||||
self.m.update(sig)
|
self.m.update(sig)
|
||||||
|
@ -702,24 +737,21 @@ class Task(TaskBase):
|
||||||
from waflib.Task import Task
|
from waflib.Task import Task
|
||||||
class mytask(Task):
|
class mytask(Task):
|
||||||
def scan(self, node):
|
def scan(self, node):
|
||||||
return ((), ())
|
return ([], [])
|
||||||
|
|
||||||
The first and second lists are stored in :py:attr:`waflib.Build.BuildContext.node_deps` and
|
The first and second lists in the tuple are stored in :py:attr:`waflib.Build.BuildContext.node_deps` and
|
||||||
:py:attr:`waflib.Build.BuildContext.raw_deps` respectively.
|
:py:attr:`waflib.Build.BuildContext.raw_deps` respectively.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def sig_implicit_deps(self):
|
def sig_implicit_deps(self):
|
||||||
"""
|
"""
|
||||||
Used by :py:meth:`waflib.Task.Task.signature` hashes node signatures obtained by scanning for dependencies (:py:meth:`waflib.Task.Task.scan`).
|
Used by :py:meth:`waflib.Task.Task.signature`; it hashes node signatures
|
||||||
|
obtained by scanning for dependencies (:py:meth:`waflib.Task.Task.scan`).
|
||||||
|
|
||||||
The exception :py:class:`waflib.Errors.TaskRescan` is thrown
|
The exception :py:class:`waflib.Errors.TaskRescan` is thrown
|
||||||
when a file has changed. When this occurs, :py:meth:`waflib.Task.Task.signature` is called
|
when a file has changed. In this case, the method :py:meth:`waflib.Task.Task.signature` is called
|
||||||
once again, and this method will be executed once again, this time calling :py:meth:`waflib.Task.Task.scan`
|
once again, and return here to call :py:meth:`waflib.Task.Task.scan` and searching for dependencies.
|
||||||
for searching the dependencies.
|
|
||||||
|
|
||||||
:rtype: hash value
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
bld = self.generator.bld
|
bld = self.generator.bld
|
||||||
|
|
||||||
# get the task signatures from previous runs
|
# get the task signatures from previous runs
|
||||||
|
@ -764,6 +796,9 @@ class Task(TaskBase):
|
||||||
"""
|
"""
|
||||||
Used by :py:meth:`waflib.Task.Task.sig_implicit_deps` for computing the actual hash of the
|
Used by :py:meth:`waflib.Task.Task.sig_implicit_deps` for computing the actual hash of the
|
||||||
:py:class:`waflib.Node.Node` returned by the scanner.
|
:py:class:`waflib.Node.Node` returned by the scanner.
|
||||||
|
|
||||||
|
:return: a hash value for the implicit dependencies
|
||||||
|
:rtype: string or bytes
|
||||||
"""
|
"""
|
||||||
upd = self.m.update
|
upd = self.m.update
|
||||||
self.are_implicit_nodes_ready()
|
self.are_implicit_nodes_ready()
|
||||||
|
@ -777,9 +812,10 @@ class Task(TaskBase):
|
||||||
|
|
||||||
def are_implicit_nodes_ready(self):
|
def are_implicit_nodes_ready(self):
|
||||||
"""
|
"""
|
||||||
For each node returned by the scanner, see if there is a task behind it, and force the build order
|
For each node returned by the scanner, see if there is a task that creates it,
|
||||||
|
and infer the build order
|
||||||
|
|
||||||
Low performance impact on null builds (1.86s->1.66s) thanks to caching (28s->1.86s)
|
This has a low performance impact on null builds (1.86s->1.66s) thanks to caching (28s->1.86s)
|
||||||
"""
|
"""
|
||||||
bld = self.generator.bld
|
bld = self.generator.bld
|
||||||
try:
|
try:
|
||||||
|
@ -823,7 +859,7 @@ if sys.hexversion > 0x3000000:
|
||||||
|
|
||||||
def is_before(t1, t2):
|
def is_before(t1, t2):
|
||||||
"""
|
"""
|
||||||
Return a non-zero value if task t1 is to be executed before task t2::
|
Returns a non-zero value if task t1 is to be executed before task t2::
|
||||||
|
|
||||||
t1.ext_out = '.h'
|
t1.ext_out = '.h'
|
||||||
t2.ext_in = '.h'
|
t2.ext_in = '.h'
|
||||||
|
@ -831,9 +867,9 @@ def is_before(t1, t2):
|
||||||
t1.before = ['t2']
|
t1.before = ['t2']
|
||||||
waflib.Task.is_before(t1, t2) # True
|
waflib.Task.is_before(t1, t2) # True
|
||||||
|
|
||||||
:param t1: task
|
:param t1: Task object
|
||||||
:type t1: :py:class:`waflib.Task.TaskBase`
|
:type t1: :py:class:`waflib.Task.TaskBase`
|
||||||
:param t2: task
|
:param t2: Task object
|
||||||
:type t2: :py:class:`waflib.Task.TaskBase`
|
:type t2: :py:class:`waflib.Task.TaskBase`
|
||||||
"""
|
"""
|
||||||
to_list = Utils.to_list
|
to_list = Utils.to_list
|
||||||
|
@ -851,7 +887,7 @@ def is_before(t1, t2):
|
||||||
|
|
||||||
def set_file_constraints(tasks):
|
def set_file_constraints(tasks):
|
||||||
"""
|
"""
|
||||||
Adds tasks to the task 'run_after' attribute based on the task inputs and outputs
|
Updates the ``run_after`` attribute of all tasks based on the task inputs and outputs
|
||||||
|
|
||||||
:param tasks: tasks
|
:param tasks: tasks
|
||||||
:type tasks: list of :py:class:`waflib.Task.TaskBase`
|
:type tasks: list of :py:class:`waflib.Task.TaskBase`
|
||||||
|
@ -871,7 +907,7 @@ def set_file_constraints(tasks):
|
||||||
|
|
||||||
def set_precedence_constraints(tasks):
|
def set_precedence_constraints(tasks):
|
||||||
"""
|
"""
|
||||||
Add tasks to the task 'run_after' attribute based on the after/before/ext_out/ext_in attributes
|
Updates the ``run_after`` attribute of all tasks based on the after/before/ext_out/ext_in attributes
|
||||||
|
|
||||||
:param tasks: tasks
|
:param tasks: tasks
|
||||||
:type tasks: list of :py:class:`waflib.Task.TaskBase`
|
:type tasks: list of :py:class:`waflib.Task.TaskBase`
|
||||||
|
@ -906,7 +942,7 @@ def set_precedence_constraints(tasks):
|
||||||
|
|
||||||
def funex(c):
|
def funex(c):
|
||||||
"""
|
"""
|
||||||
Compile a function by 'exec'
|
Compiles a scriptlet expression into a Python function
|
||||||
|
|
||||||
:param c: function to compile
|
:param c: function to compile
|
||||||
:type c: string
|
:type c: string
|
||||||
|
@ -922,16 +958,18 @@ re_novar = re.compile(r'^(SRC|TGT)\W+.*?$')
|
||||||
reg_act = re.compile(r'(?P<backslash>\\)|(?P<dollar>\$\$)|(?P<subst>\$\{(?P<var>\w+)(?P<code>.*?)\})', re.M)
|
reg_act = re.compile(r'(?P<backslash>\\)|(?P<dollar>\$\$)|(?P<subst>\$\{(?P<var>\w+)(?P<code>.*?)\})', re.M)
|
||||||
def compile_fun_shell(line):
|
def compile_fun_shell(line):
|
||||||
"""
|
"""
|
||||||
Create a compiled function to execute a process with the shell
|
Creates a compiled function to execute a process through a sub-shell
|
||||||
WARNING: this method may disappear anytime, so use compile_fun instead
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
extr = []
|
extr = []
|
||||||
def repl(match):
|
def repl(match):
|
||||||
g = match.group
|
g = match.group
|
||||||
if g('dollar'): return "$"
|
if g('dollar'):
|
||||||
elif g('backslash'): return '\\\\'
|
return "$"
|
||||||
elif g('subst'): extr.append((g('var'), g('code'))); return "%s"
|
elif g('backslash'):
|
||||||
|
return '\\\\'
|
||||||
|
elif g('subst'):
|
||||||
|
extr.append((g('var'), g('code')))
|
||||||
|
return "%s"
|
||||||
return None
|
return None
|
||||||
line = reg_act.sub(repl, line) or line
|
line = reg_act.sub(repl, line) or line
|
||||||
|
|
||||||
|
@ -994,8 +1032,7 @@ def compile_fun_shell(line):
|
||||||
reg_act_noshell = re.compile(r"(?P<space>\s+)|(?P<subst>\$\{(?P<var>\w+)(?P<code>.*?)\})|(?P<text>\S+)", re.M)
|
reg_act_noshell = re.compile(r"(?P<space>\s+)|(?P<subst>\$\{(?P<var>\w+)(?P<code>.*?)\})|(?P<text>\S+)", re.M)
|
||||||
def compile_fun_noshell(line):
|
def compile_fun_noshell(line):
|
||||||
"""
|
"""
|
||||||
Create a compiled function to execute a process without the shell
|
Creates a compiled function to execute a process without a sub-shell
|
||||||
WARNING: this method may disappear anytime, so use compile_fun instead
|
|
||||||
"""
|
"""
|
||||||
buf = []
|
buf = []
|
||||||
dvars = []
|
dvars = []
|
||||||
|
@ -1076,10 +1113,10 @@ def compile_fun_noshell(line):
|
||||||
|
|
||||||
def compile_fun(line, shell=False):
|
def compile_fun(line, shell=False):
|
||||||
"""
|
"""
|
||||||
Parse a string expression such as "${CC} ${SRC} -o ${TGT}" and return a pair containing:
|
Parses a string expression such as '${CC} ${SRC} -o ${TGT}' and returns a pair containing:
|
||||||
|
|
||||||
* the function created (compiled) for use as :py:meth:`waflib.Task.TaskBase.run`
|
* The function created (compiled) for use as :py:meth:`waflib.Task.TaskBase.run`
|
||||||
* the list of variables that imply a dependency from self.env
|
* The list of variables that must cause rebuilds when *env* data is modified
|
||||||
|
|
||||||
for example::
|
for example::
|
||||||
|
|
||||||
|
@ -1089,8 +1126,8 @@ def compile_fun(line, shell=False):
|
||||||
def build(bld):
|
def build(bld):
|
||||||
bld(source='wscript', rule='echo "foo\\${SRC[0].name}\\bar"')
|
bld(source='wscript', rule='echo "foo\\${SRC[0].name}\\bar"')
|
||||||
|
|
||||||
The env variables (CXX, ..) on the task must not hold dicts (order)
|
The env variables (CXX, ..) on the task must not hold dicts so as to preserve a consistent order.
|
||||||
The reserved keywords *TGT* and *SRC* represent the task input and output nodes
|
The reserved keywords ``TGT`` and ``SRC`` represent the task input and output nodes
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if isinstance(line, str):
|
if isinstance(line, str):
|
||||||
|
@ -1161,7 +1198,7 @@ def task_factory(name, func=None, vars=None, color='GREEN', ext_in=[], ext_out=[
|
||||||
|
|
||||||
def always_run(cls):
|
def always_run(cls):
|
||||||
"""
|
"""
|
||||||
Task class decorator, to be removed in waf 2.0
|
Deprecated Task class decorator (to be removed in waf 2.0)
|
||||||
|
|
||||||
Set all task instances of this class to be executed whenever a build is started
|
Set all task instances of this class to be executed whenever a build is started
|
||||||
The task signature is calculated, but the result of the comparison between
|
The task signature is calculated, but the result of the comparison between
|
||||||
|
|
|
@ -7,9 +7,7 @@ Task generators
|
||||||
|
|
||||||
The class :py:class:`waflib.TaskGen.task_gen` encapsulates the creation of task objects (low-level code)
|
The class :py:class:`waflib.TaskGen.task_gen` encapsulates the creation of task objects (low-level code)
|
||||||
The instances can have various parameters, but the creation of task nodes (Task.py)
|
The instances can have various parameters, but the creation of task nodes (Task.py)
|
||||||
is always postponed. To achieve this, various methods are called from the method "apply"
|
is deferred. To achieve this, various methods are called from the method "apply"
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import copy, re, os
|
import copy, re, os
|
||||||
|
@ -34,31 +32,28 @@ class task_gen(object):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
mappings = Utils.ordered_iter_dict()
|
mappings = Utils.ordered_iter_dict()
|
||||||
"""Mappings are global file extension mappings, they are retrieved in the order of definition"""
|
"""Mappings are global file extension mappings that are retrieved in the order of definition"""
|
||||||
|
|
||||||
prec = Utils.defaultdict(list)
|
prec = Utils.defaultdict(list)
|
||||||
"""Dict holding the precedence rules for task generator methods"""
|
"""Dict that holds the precedence execution rules for task generator methods"""
|
||||||
|
|
||||||
def __init__(self, *k, **kw):
|
def __init__(self, *k, **kw):
|
||||||
"""
|
"""
|
||||||
The task generator objects predefine various attributes (source, target) for possible
|
Task generator objects predefine various attributes (source, target) for possible
|
||||||
processing by process_rule (make-like rules) or process_source (extensions, misc methods)
|
processing by process_rule (make-like rules) or process_source (extensions, misc methods)
|
||||||
|
|
||||||
The tasks are stored on the attribute 'tasks'. They are created by calling methods
|
Tasks are stored on the attribute 'tasks'. They are created by calling methods
|
||||||
listed in self.meths *or* referenced in the attribute features
|
listed in ``self.meths`` or referenced in the attribute ``features``
|
||||||
A topological sort is performed to ease the method re-use.
|
A topological sort is performed to execute the methods in correct order.
|
||||||
|
|
||||||
The extra key/value elements passed in kw are set as attributes
|
The extra key/value elements passed in ``kw`` are set as attributes
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# so we will have to play with directed acyclic graphs
|
|
||||||
# detect cycles, etc
|
|
||||||
self.source = ''
|
self.source = ''
|
||||||
self.target = ''
|
self.target = ''
|
||||||
|
|
||||||
self.meths = []
|
self.meths = []
|
||||||
"""
|
"""
|
||||||
List of method names to execute (it is usually a good idea to avoid touching this)
|
List of method names to execute (internal)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.features = []
|
self.features = []
|
||||||
|
@ -68,7 +63,7 @@ class task_gen(object):
|
||||||
|
|
||||||
self.tasks = []
|
self.tasks = []
|
||||||
"""
|
"""
|
||||||
List of tasks created.
|
Tasks created are added to this list
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if not 'bld' in kw:
|
if not 'bld' in kw:
|
||||||
|
@ -92,11 +87,11 @@ class task_gen(object):
|
||||||
setattr(self, key, val)
|
setattr(self, key, val)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""for debugging purposes"""
|
"""Debugging helper"""
|
||||||
return "<task_gen %r declared in %s>" % (self.name, self.path.abspath())
|
return "<task_gen %r declared in %s>" % (self.name, self.path.abspath())
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
"""for debugging purposes"""
|
"""Debugging helper"""
|
||||||
lst = []
|
lst = []
|
||||||
for x in self.__dict__:
|
for x in self.__dict__:
|
||||||
if x not in ('env', 'bld', 'compiled_tasks', 'tasks'):
|
if x not in ('env', 'bld', 'compiled_tasks', 'tasks'):
|
||||||
|
@ -104,11 +99,19 @@ class task_gen(object):
|
||||||
return "bld(%s) in %s" % (", ".join(lst), self.path.abspath())
|
return "bld(%s) in %s" % (", ".join(lst), self.path.abspath())
|
||||||
|
|
||||||
def get_cwd(self):
|
def get_cwd(self):
|
||||||
|
"""
|
||||||
|
Current working directory for the task generator, defaults to the build directory.
|
||||||
|
This is still used in a few places but it should disappear at some point as the classes
|
||||||
|
define their own working directory.
|
||||||
|
|
||||||
|
:rtype: :py:class:`waflib.Node.Node`
|
||||||
|
"""
|
||||||
return self.bld.bldnode
|
return self.bld.bldnode
|
||||||
|
|
||||||
def get_name(self):
|
def get_name(self):
|
||||||
"""
|
"""
|
||||||
If not set, the name is computed from the target name::
|
If the attribute ``name`` is not set on the instance,
|
||||||
|
the name is computed from the target name::
|
||||||
|
|
||||||
def build(bld):
|
def build(bld):
|
||||||
x = bld(name='foo')
|
x = bld(name='foo')
|
||||||
|
@ -135,18 +138,20 @@ class task_gen(object):
|
||||||
|
|
||||||
def to_list(self, val):
|
def to_list(self, val):
|
||||||
"""
|
"""
|
||||||
Ensure that a parameter is a list
|
Ensures that a parameter is a list, see :py:func:`waflib.Utils.to_list`
|
||||||
|
|
||||||
:type val: string or list of string
|
:type val: string or list of string
|
||||||
:param val: input to return as a list
|
:param val: input to return as a list
|
||||||
:rtype: list
|
:rtype: list
|
||||||
"""
|
"""
|
||||||
if isinstance(val, str): return val.split()
|
if isinstance(val, str):
|
||||||
else: return val
|
return val.split()
|
||||||
|
else:
|
||||||
|
return val
|
||||||
|
|
||||||
def post(self):
|
def post(self):
|
||||||
"""
|
"""
|
||||||
Create task objects. The following operations are performed:
|
Creates tasks for this task generators. The following operations are performed:
|
||||||
|
|
||||||
#. The body of this method is called only once and sets the attribute ``posted``
|
#. The body of this method is called only once and sets the attribute ``posted``
|
||||||
#. The attribute ``features`` is used to add more methods in ``self.meths``
|
#. The attribute ``features`` is used to add more methods in ``self.meths``
|
||||||
|
@ -226,6 +231,8 @@ class task_gen(object):
|
||||||
|
|
||||||
def get_hook(self, node):
|
def get_hook(self, node):
|
||||||
"""
|
"""
|
||||||
|
Returns the ``@extension`` method to call for a Node of a particular extension.
|
||||||
|
|
||||||
:param node: Input file to process
|
:param node: Input file to process
|
||||||
:type node: :py:class:`waflib.Tools.Node.Node`
|
:type node: :py:class:`waflib.Tools.Node.Node`
|
||||||
:return: A method able to process the input node by looking at the extension
|
:return: A method able to process the input node by looking at the extension
|
||||||
|
@ -244,8 +251,7 @@ class task_gen(object):
|
||||||
|
|
||||||
def create_task(self, name, src=None, tgt=None, **kw):
|
def create_task(self, name, src=None, tgt=None, **kw):
|
||||||
"""
|
"""
|
||||||
Wrapper for creating task instances. The classes are retrieved from the
|
Creates task instances.
|
||||||
context class if possible, then from the global dict Task.classes.
|
|
||||||
|
|
||||||
:param name: task class name
|
:param name: task class name
|
||||||
:type name: string
|
:type name: string
|
||||||
|
@ -267,7 +273,7 @@ class task_gen(object):
|
||||||
|
|
||||||
def clone(self, env):
|
def clone(self, env):
|
||||||
"""
|
"""
|
||||||
Make a copy of a task generator. Once the copy is made, it is necessary to ensure that the
|
Makes a copy of a task generator. Once the copy is made, it is necessary to ensure that the
|
||||||
it does not create the same output files as the original, or the same files may
|
it does not create the same output files as the original, or the same files may
|
||||||
be compiled several times.
|
be compiled several times.
|
||||||
|
|
||||||
|
@ -296,7 +302,7 @@ class task_gen(object):
|
||||||
def declare_chain(name='', rule=None, reentrant=None, color='BLUE',
|
def declare_chain(name='', rule=None, reentrant=None, color='BLUE',
|
||||||
ext_in=[], ext_out=[], before=[], after=[], decider=None, scan=None, install_path=None, shell=False):
|
ext_in=[], ext_out=[], before=[], after=[], decider=None, scan=None, install_path=None, shell=False):
|
||||||
"""
|
"""
|
||||||
Create a new mapping and a task class for processing files by extension.
|
Creates a new mapping and a task class for processing files by extension.
|
||||||
See Tools/flex.py for an example.
|
See Tools/flex.py for an example.
|
||||||
|
|
||||||
:param name: name for the task class
|
:param name: name for the task class
|
||||||
|
@ -361,7 +367,7 @@ def declare_chain(name='', rule=None, reentrant=None, color='BLUE',
|
||||||
|
|
||||||
def taskgen_method(func):
|
def taskgen_method(func):
|
||||||
"""
|
"""
|
||||||
Decorator: register a method as a task generator method.
|
Decorator that registers method as a task generator method.
|
||||||
The function must accept a task generator as first parameter::
|
The function must accept a task generator as first parameter::
|
||||||
|
|
||||||
from waflib.TaskGen import taskgen_method
|
from waflib.TaskGen import taskgen_method
|
||||||
|
@ -378,8 +384,8 @@ def taskgen_method(func):
|
||||||
|
|
||||||
def feature(*k):
|
def feature(*k):
|
||||||
"""
|
"""
|
||||||
Decorator: register a task generator method that will be executed when the
|
Decorator that registers a task generator method that will be executed when the
|
||||||
object attribute 'feature' contains the corresponding key(s)::
|
object attribute ``feature`` contains the corresponding key(s)::
|
||||||
|
|
||||||
from waflib.Task import feature
|
from waflib.Task import feature
|
||||||
@feature('myfeature')
|
@feature('myfeature')
|
||||||
|
@ -400,7 +406,7 @@ def feature(*k):
|
||||||
|
|
||||||
def before_method(*k):
|
def before_method(*k):
|
||||||
"""
|
"""
|
||||||
Decorator: register a task generator method which will be executed
|
Decorator that registera task generator method which will be executed
|
||||||
before the functions of given name(s)::
|
before the functions of given name(s)::
|
||||||
|
|
||||||
from waflib.TaskGen import feature, before
|
from waflib.TaskGen import feature, before
|
||||||
|
@ -429,7 +435,7 @@ before = before_method
|
||||||
|
|
||||||
def after_method(*k):
|
def after_method(*k):
|
||||||
"""
|
"""
|
||||||
Decorator: register a task generator method which will be executed
|
Decorator that registers a task generator method which will be executed
|
||||||
after the functions of given name(s)::
|
after the functions of given name(s)::
|
||||||
|
|
||||||
from waflib.TaskGen import feature, after
|
from waflib.TaskGen import feature, after
|
||||||
|
@ -458,7 +464,7 @@ after = after_method
|
||||||
|
|
||||||
def extension(*k):
|
def extension(*k):
|
||||||
"""
|
"""
|
||||||
Decorator: register a task generator method which will be invoked during
|
Decorator that registers a task generator method which will be invoked during
|
||||||
the processing of source files for the extension given::
|
the processing of source files for the extension given::
|
||||||
|
|
||||||
from waflib import Task
|
from waflib import Task
|
||||||
|
@ -484,7 +490,7 @@ def extension(*k):
|
||||||
@taskgen_method
|
@taskgen_method
|
||||||
def to_nodes(self, lst, path=None):
|
def to_nodes(self, lst, path=None):
|
||||||
"""
|
"""
|
||||||
Convert the input list into a list of nodes.
|
Converts the input list into a list of nodes.
|
||||||
It is used by :py:func:`waflib.TaskGen.process_source` and :py:func:`waflib.TaskGen.process_rule`.
|
It is used by :py:func:`waflib.TaskGen.process_source` and :py:func:`waflib.TaskGen.process_rule`.
|
||||||
It is designed for source files, for folders, see :py:func:`waflib.Tools.ccroot.to_incnodes`:
|
It is designed for source files, for folders, see :py:func:`waflib.Tools.ccroot.to_incnodes`:
|
||||||
|
|
||||||
|
@ -515,7 +521,7 @@ def to_nodes(self, lst, path=None):
|
||||||
@feature('*')
|
@feature('*')
|
||||||
def process_source(self):
|
def process_source(self):
|
||||||
"""
|
"""
|
||||||
Process each element in the attribute ``source`` by extension.
|
Processes each element in the attribute ``source`` by extension.
|
||||||
|
|
||||||
#. The *source* list is converted through :py:meth:`waflib.TaskGen.to_nodes` to a list of :py:class:`waflib.Node.Node` first.
|
#. The *source* list is converted through :py:meth:`waflib.TaskGen.to_nodes` to a list of :py:class:`waflib.Node.Node` first.
|
||||||
#. File extensions are mapped to methods having the signature: ``def meth(self, node)`` by :py:meth:`waflib.TaskGen.extension`
|
#. File extensions are mapped to methods having the signature: ``def meth(self, node)`` by :py:meth:`waflib.TaskGen.extension`
|
||||||
|
@ -531,7 +537,7 @@ def process_source(self):
|
||||||
@before_method('process_source')
|
@before_method('process_source')
|
||||||
def process_rule(self):
|
def process_rule(self):
|
||||||
"""
|
"""
|
||||||
Process the attribute ``rule``. When present, :py:meth:`waflib.TaskGen.process_source` is disabled::
|
Processes the attribute ``rule``. When present, :py:meth:`waflib.TaskGen.process_source` is disabled::
|
||||||
|
|
||||||
def build(bld):
|
def build(bld):
|
||||||
bld(rule='cp ${SRC} ${TGT}', source='wscript', target='bar.txt')
|
bld(rule='cp ${SRC} ${TGT}', source='wscript', target='bar.txt')
|
||||||
|
@ -627,7 +633,7 @@ def process_rule(self):
|
||||||
@feature('seq')
|
@feature('seq')
|
||||||
def sequence_order(self):
|
def sequence_order(self):
|
||||||
"""
|
"""
|
||||||
Add a strict sequential constraint between the tasks generated by task generators.
|
Adds a strict sequential constraint between the tasks generated by task generators.
|
||||||
It works because task generators are posted in order.
|
It works because task generators are posted in order.
|
||||||
It will not post objects which belong to other folders.
|
It will not post objects which belong to other folders.
|
||||||
|
|
||||||
|
@ -665,7 +671,7 @@ re_m4 = re.compile('@(\w+)@', re.M)
|
||||||
|
|
||||||
class subst_pc(Task.Task):
|
class subst_pc(Task.Task):
|
||||||
"""
|
"""
|
||||||
Create *.pc* files from *.pc.in*. The task is executed whenever an input variable used
|
Creates *.pc* files from *.pc.in*. The task is executed whenever an input variable used
|
||||||
in the substitution changes.
|
in the substitution changes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -762,7 +768,7 @@ class subst_pc(Task.Task):
|
||||||
@extension('.pc.in')
|
@extension('.pc.in')
|
||||||
def add_pcfile(self, node):
|
def add_pcfile(self, node):
|
||||||
"""
|
"""
|
||||||
Process *.pc.in* files to *.pc*. Install the results to ``${PREFIX}/lib/pkgconfig/``
|
Processes *.pc.in* files to *.pc*. Installs the results to ``${PREFIX}/lib/pkgconfig/`` by default
|
||||||
|
|
||||||
def build(bld):
|
def build(bld):
|
||||||
bld(source='foo.pc.in', install_path='${LIBDIR}/pkgconfig/')
|
bld(source='foo.pc.in', install_path='${LIBDIR}/pkgconfig/')
|
||||||
|
@ -778,7 +784,7 @@ class subst(subst_pc):
|
||||||
@before_method('process_source', 'process_rule')
|
@before_method('process_source', 'process_rule')
|
||||||
def process_subst(self):
|
def process_subst(self):
|
||||||
"""
|
"""
|
||||||
Define a transformation that substitutes the contents of *source* files to *target* files::
|
Defines a transformation that substitutes the contents of *source* files to *target* files::
|
||||||
|
|
||||||
def build(bld):
|
def build(bld):
|
||||||
bld(
|
bld(
|
||||||
|
|
140
waflib/Utils.py
140
waflib/Utils.py
|
@ -82,7 +82,7 @@ rot_idx = 0
|
||||||
"Index of the current throbber character (progress bar)"
|
"Index of the current throbber character (progress bar)"
|
||||||
|
|
||||||
class ordered_iter_dict(dict):
|
class ordered_iter_dict(dict):
|
||||||
"""An ordered dictionary that provides iteration from the most recently inserted keys first"""
|
"""Ordered dictionary that provides iteration from the most recently inserted keys first"""
|
||||||
def __init__(self, *k, **kw):
|
def __init__(self, *k, **kw):
|
||||||
self.lst = deque()
|
self.lst = deque()
|
||||||
dict.__init__(self, *k, **kw)
|
dict.__init__(self, *k, **kw)
|
||||||
|
@ -106,6 +106,9 @@ class ordered_iter_dict(dict):
|
||||||
return reversed(self.lst)
|
return reversed(self.lst)
|
||||||
|
|
||||||
class lru_node(object):
|
class lru_node(object):
|
||||||
|
"""
|
||||||
|
Used by :py:class:`waflib.Utils.lru_cache`
|
||||||
|
"""
|
||||||
__slots__ = ('next', 'prev', 'key', 'val')
|
__slots__ = ('next', 'prev', 'key', 'val')
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.next = self
|
self.next = self
|
||||||
|
@ -118,7 +121,13 @@ class lru_cache(object):
|
||||||
__slots__ = ('maxlen', 'table', 'head')
|
__slots__ = ('maxlen', 'table', 'head')
|
||||||
def __init__(self, maxlen=100):
|
def __init__(self, maxlen=100):
|
||||||
self.maxlen = maxlen
|
self.maxlen = maxlen
|
||||||
|
"""
|
||||||
|
Maximum amount of elements in the cache
|
||||||
|
"""
|
||||||
self.table = {}
|
self.table = {}
|
||||||
|
"""
|
||||||
|
Mapping key-value
|
||||||
|
"""
|
||||||
self.head = lru_node()
|
self.head = lru_node()
|
||||||
for x in range(maxlen - 1):
|
for x in range(maxlen - 1):
|
||||||
node = lru_node()
|
node = lru_node()
|
||||||
|
@ -159,12 +168,13 @@ class lru_cache(object):
|
||||||
self.table[key] = node
|
self.table[key] = node
|
||||||
|
|
||||||
is_win32 = os.sep == '\\' or sys.platform == 'win32' # msys2
|
is_win32 = os.sep == '\\' or sys.platform == 'win32' # msys2
|
||||||
|
"""
|
||||||
|
Whether this system is a Windows series
|
||||||
|
"""
|
||||||
|
|
||||||
def readf(fname, m='r', encoding='ISO8859-1'):
|
def readf(fname, m='r', encoding='ISO8859-1'):
|
||||||
"""
|
"""
|
||||||
Read an entire file into a string, use this function instead of os.open() whenever possible.
|
Reads an entire file into a string. See also :py:meth:`waflib.Node.Node.readf`::
|
||||||
|
|
||||||
In practice the wrapper node.read(..) should be preferred to this function::
|
|
||||||
|
|
||||||
def build(ctx):
|
def build(ctx):
|
||||||
from waflib import Utils
|
from waflib import Utils
|
||||||
|
@ -202,9 +212,8 @@ def readf(fname, m='r', encoding='ISO8859-1'):
|
||||||
|
|
||||||
def writef(fname, data, m='w', encoding='ISO8859-1'):
|
def writef(fname, data, m='w', encoding='ISO8859-1'):
|
||||||
"""
|
"""
|
||||||
Write an entire file from a string, use this function instead of os.open() whenever possible.
|
Writes an entire file from a string.
|
||||||
|
See also :py:meth:`waflib.Node.Node.writef`::
|
||||||
In practice the wrapper node.write(..) should be preferred to this function::
|
|
||||||
|
|
||||||
def build(ctx):
|
def build(ctx):
|
||||||
from waflib import Utils
|
from waflib import Utils
|
||||||
|
@ -237,6 +246,7 @@ def h_file(fname):
|
||||||
:type fname: string
|
:type fname: string
|
||||||
:param fname: path to the file to hash
|
:param fname: path to the file to hash
|
||||||
:return: hash of the file contents
|
:return: hash of the file contents
|
||||||
|
:rtype: string or bytes
|
||||||
"""
|
"""
|
||||||
f = open(fname, 'rb')
|
f = open(fname, 'rb')
|
||||||
m = md5()
|
m = md5()
|
||||||
|
@ -344,8 +354,8 @@ Return the hexadecimal representation of a string
|
||||||
|
|
||||||
def listdir_win32(s):
|
def listdir_win32(s):
|
||||||
"""
|
"""
|
||||||
List the contents of a folder in a portable manner.
|
Lists the contents of a folder in a portable manner.
|
||||||
On Win32, return the list of drive letters: ['C:', 'X:', 'Z:']
|
On Win32, returns the list of drive letters: ['C:', 'X:', 'Z:'] when an empty string is given.
|
||||||
|
|
||||||
:type s: string
|
:type s: string
|
||||||
:param s: a string, which can be empty on Windows
|
:param s: a string, which can be empty on Windows
|
||||||
|
@ -378,7 +388,7 @@ if is_win32:
|
||||||
|
|
||||||
def num2ver(ver):
|
def num2ver(ver):
|
||||||
"""
|
"""
|
||||||
Convert a string, tuple or version number into an integer. The number is supposed to have at most 4 digits::
|
Converts a string, tuple or version number into an integer. The number is supposed to have at most 4 digits::
|
||||||
|
|
||||||
from waflib.Utils import num2ver
|
from waflib.Utils import num2ver
|
||||||
num2ver('1.3.2') == num2ver((1,3,2)) == num2ver((1,3,2,0))
|
num2ver('1.3.2') == num2ver((1,3,2)) == num2ver((1,3,2,0))
|
||||||
|
@ -398,31 +408,29 @@ def num2ver(ver):
|
||||||
|
|
||||||
def ex_stack():
|
def ex_stack():
|
||||||
"""
|
"""
|
||||||
Extract the stack to display exceptions
|
Extracts the stack to display exceptions. Deprecated: use traceback.format_exc()
|
||||||
Deprecated: use traceback.format_exc()
|
|
||||||
|
|
||||||
:return: a string represening the last exception
|
:return: a string represening the last exception
|
||||||
"""
|
"""
|
||||||
# TODO remove in waf 2.0
|
# TODO remove in waf 2.0
|
||||||
return traceback.format_exc()
|
return traceback.format_exc()
|
||||||
|
|
||||||
def to_list(sth):
|
def to_list(val):
|
||||||
"""
|
"""
|
||||||
Convert a string argument to a list by splitting on spaces, and pass
|
Converts a string argument to a list by splitting it by spaces.
|
||||||
through a list argument unchanged::
|
Returns the object if not a string::
|
||||||
|
|
||||||
from waflib.Utils import to_list
|
from waflib.Utils import to_list
|
||||||
lst = to_list("a b c d")
|
lst = to_list('a b c d')
|
||||||
|
|
||||||
:param sth: List or a string of items separated by spaces
|
:param val: list of string or space-separated string
|
||||||
:rtype: list
|
:rtype: list
|
||||||
:return: Argument converted to list
|
:return: Argument converted to list
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if isinstance(sth, str):
|
if isinstance(val, str):
|
||||||
return sth.split()
|
return val.split()
|
||||||
else:
|
else:
|
||||||
return sth
|
return val
|
||||||
|
|
||||||
def split_path_unix(path):
|
def split_path_unix(path):
|
||||||
return path.split('/')
|
return path.split('/')
|
||||||
|
@ -465,19 +473,20 @@ else:
|
||||||
split_path = split_path_unix
|
split_path = split_path_unix
|
||||||
|
|
||||||
split_path.__doc__ = """
|
split_path.__doc__ = """
|
||||||
Split a path by / or \\. This function is not like os.path.split
|
Splits a path by / or \\; do not confuse this function with with ``os.path.split``
|
||||||
|
|
||||||
:type path: string
|
:type path: string
|
||||||
:param path: path to split
|
:param path: path to split
|
||||||
:return: list of strings
|
:return: list of string
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def check_dir(path):
|
def check_dir(path):
|
||||||
"""
|
"""
|
||||||
Ensure that a directory exists (similar to ``mkdir -p``).
|
Ensures that a directory exists (similar to ``mkdir -p``).
|
||||||
|
|
||||||
:type path: string
|
:type path: string
|
||||||
:param path: Path to directory
|
:param path: Path to directory
|
||||||
|
:raises: :py:class:`waflib.Errors.WafError` if the folder cannot be added.
|
||||||
"""
|
"""
|
||||||
if not os.path.isdir(path):
|
if not os.path.isdir(path):
|
||||||
try:
|
try:
|
||||||
|
@ -488,11 +497,14 @@ def check_dir(path):
|
||||||
|
|
||||||
def check_exe(name, env=None):
|
def check_exe(name, env=None):
|
||||||
"""
|
"""
|
||||||
Ensure that a program exists
|
Ensures that a program exists
|
||||||
|
|
||||||
:type name: string
|
:type name: string
|
||||||
:param name: name or path to program
|
:param name: path to the program
|
||||||
|
:param env: configuration object
|
||||||
|
:type env: :py:class:`waflib.ConfigSet.ConfigSet`
|
||||||
:return: path of the program or None
|
:return: path of the program or None
|
||||||
|
:raises: :py:class:`waflib.Errors.WafError` if the folder cannot be added.
|
||||||
"""
|
"""
|
||||||
if not name:
|
if not name:
|
||||||
raise ValueError('Cannot execute an empty string!')
|
raise ValueError('Cannot execute an empty string!')
|
||||||
|
@ -504,7 +516,7 @@ def check_exe(name, env=None):
|
||||||
return os.path.abspath(name)
|
return os.path.abspath(name)
|
||||||
else:
|
else:
|
||||||
env = env or os.environ
|
env = env or os.environ
|
||||||
for path in env["PATH"].split(os.pathsep):
|
for path in env['PATH'].split(os.pathsep):
|
||||||
path = path.strip('"')
|
path = path.strip('"')
|
||||||
exe_file = os.path.join(path, name)
|
exe_file = os.path.join(path, name)
|
||||||
if is_exe(exe_file):
|
if is_exe(exe_file):
|
||||||
|
@ -513,7 +525,7 @@ def check_exe(name, env=None):
|
||||||
|
|
||||||
def def_attrs(cls, **kw):
|
def def_attrs(cls, **kw):
|
||||||
"""
|
"""
|
||||||
Set default attributes on a class instance
|
Sets default attributes on a class instance
|
||||||
|
|
||||||
:type cls: class
|
:type cls: class
|
||||||
:param cls: the class to update the given attributes in.
|
:param cls: the class to update the given attributes in.
|
||||||
|
@ -526,7 +538,7 @@ def def_attrs(cls, **kw):
|
||||||
|
|
||||||
def quote_define_name(s):
|
def quote_define_name(s):
|
||||||
"""
|
"""
|
||||||
Convert a string to an identifier suitable for C defines.
|
Converts a string into an identifier suitable for C defines.
|
||||||
|
|
||||||
:type s: string
|
:type s: string
|
||||||
:param s: String to convert
|
:param s: String to convert
|
||||||
|
@ -540,8 +552,8 @@ def quote_define_name(s):
|
||||||
|
|
||||||
def h_list(lst):
|
def h_list(lst):
|
||||||
"""
|
"""
|
||||||
Hash lists. For tuples, using hash(tup) is much more efficient,
|
Hash lists. We would prefer to use hash(tup) for tuples because it is much more efficient,
|
||||||
except on python >= 3.3 where hash randomization assumes everybody is running a web application.
|
but Python now enforces hash randomization by assuming everybody is running a web application.
|
||||||
|
|
||||||
:param lst: list to hash
|
:param lst: list to hash
|
||||||
:type lst: list of strings
|
:type lst: list of strings
|
||||||
|
@ -556,6 +568,7 @@ def h_fun(fun):
|
||||||
:param fun: function to hash
|
:param fun: function to hash
|
||||||
:type fun: function
|
:type fun: function
|
||||||
:return: hash of the function
|
:return: hash of the function
|
||||||
|
:rtype: string or bytes
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return fun.code
|
return fun.code
|
||||||
|
@ -563,7 +576,7 @@ def h_fun(fun):
|
||||||
try:
|
try:
|
||||||
h = inspect.getsource(fun)
|
h = inspect.getsource(fun)
|
||||||
except EnvironmentError:
|
except EnvironmentError:
|
||||||
h = "nocode"
|
h = 'nocode'
|
||||||
try:
|
try:
|
||||||
fun.code = h
|
fun.code = h
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
@ -572,8 +585,11 @@ def h_fun(fun):
|
||||||
|
|
||||||
def h_cmd(ins):
|
def h_cmd(ins):
|
||||||
"""
|
"""
|
||||||
Task command hashes are calculated by calling this function. The inputs can be
|
Hashes objects recursively
|
||||||
strings, functions, tuples/lists containing strings/functions
|
|
||||||
|
:param ins: input object
|
||||||
|
:type ins: string or list or tuple or function
|
||||||
|
:rtype: string or bytes
|
||||||
"""
|
"""
|
||||||
# this function is not meant to be particularly fast
|
# this function is not meant to be particularly fast
|
||||||
if isinstance(ins, str):
|
if isinstance(ins, str):
|
||||||
|
@ -592,7 +608,7 @@ def h_cmd(ins):
|
||||||
reg_subst = re.compile(r"(\\\\)|(\$\$)|\$\{([^}]+)\}")
|
reg_subst = re.compile(r"(\\\\)|(\$\$)|\$\{([^}]+)\}")
|
||||||
def subst_vars(expr, params):
|
def subst_vars(expr, params):
|
||||||
"""
|
"""
|
||||||
Replace ${VAR} with the value of VAR taken from a dict or a config set::
|
Replaces ${VAR} with the value of VAR taken from a dict or a config set::
|
||||||
|
|
||||||
from waflib import Utils
|
from waflib import Utils
|
||||||
s = Utils.subst_vars('${PREFIX}/bin', env)
|
s = Utils.subst_vars('${PREFIX}/bin', env)
|
||||||
|
@ -617,7 +633,8 @@ def subst_vars(expr, params):
|
||||||
|
|
||||||
def destos_to_binfmt(key):
|
def destos_to_binfmt(key):
|
||||||
"""
|
"""
|
||||||
Return the binary format based on the unversioned platform name.
|
Returns the binary format based on the unversioned platform name,
|
||||||
|
and defaults to ``elf`` if nothing is found.
|
||||||
|
|
||||||
:param key: platform name
|
:param key: platform name
|
||||||
:type key: string
|
:type key: string
|
||||||
|
@ -631,7 +648,7 @@ def destos_to_binfmt(key):
|
||||||
|
|
||||||
def unversioned_sys_platform():
|
def unversioned_sys_platform():
|
||||||
"""
|
"""
|
||||||
Return the unversioned platform name.
|
Returns the unversioned platform name.
|
||||||
Some Python platform names contain versions, that depend on
|
Some Python platform names contain versions, that depend on
|
||||||
the build environment, e.g. linux2, freebsd6, etc.
|
the build environment, e.g. linux2, freebsd6, etc.
|
||||||
This returns the name without the version number. Exceptions are
|
This returns the name without the version number. Exceptions are
|
||||||
|
@ -670,7 +687,7 @@ def unversioned_sys_platform():
|
||||||
|
|
||||||
def nada(*k, **kw):
|
def nada(*k, **kw):
|
||||||
"""
|
"""
|
||||||
A function that does nothing
|
Does nothing
|
||||||
|
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
|
@ -706,7 +723,7 @@ class Timer(object):
|
||||||
|
|
||||||
def read_la_file(path):
|
def read_la_file(path):
|
||||||
"""
|
"""
|
||||||
Read property files, used by msvc.py
|
Reads property files, used by msvc.py
|
||||||
|
|
||||||
:param path: file to read
|
:param path: file to read
|
||||||
:type path: string
|
:type path: string
|
||||||
|
@ -729,6 +746,8 @@ def run_once(fun):
|
||||||
def foo(k):
|
def foo(k):
|
||||||
return 345*2343
|
return 345*2343
|
||||||
|
|
||||||
|
.. note:: in practice this can cause memory leaks, prefer a :py:class:`waflib.Utils.lru_cache`
|
||||||
|
|
||||||
:param fun: function to execute
|
:param fun: function to execute
|
||||||
:type fun: function
|
:type fun: function
|
||||||
:return: the return value of the function executed
|
:return: the return value of the function executed
|
||||||
|
@ -746,6 +765,12 @@ def run_once(fun):
|
||||||
return wrap
|
return wrap
|
||||||
|
|
||||||
def get_registry_app_path(key, filename):
|
def get_registry_app_path(key, filename):
|
||||||
|
"""
|
||||||
|
Returns the value of a registry key for an executable
|
||||||
|
|
||||||
|
:type key: string
|
||||||
|
:type filename: list of string
|
||||||
|
"""
|
||||||
if not winreg:
|
if not winreg:
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
|
@ -757,6 +782,12 @@ def get_registry_app_path(key, filename):
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def lib64():
|
def lib64():
|
||||||
|
"""
|
||||||
|
Guess the default ``/usr/lib`` extension for 64-bit applications
|
||||||
|
|
||||||
|
:return: '64' or ''
|
||||||
|
:rtype: string
|
||||||
|
"""
|
||||||
# default settings for /usr/lib
|
# default settings for /usr/lib
|
||||||
if os.sep == '/':
|
if os.sep == '/':
|
||||||
if platform.architecture()[0] == '64bit':
|
if platform.architecture()[0] == '64bit':
|
||||||
|
@ -768,9 +799,17 @@ def sane_path(p):
|
||||||
# private function for the time being!
|
# private function for the time being!
|
||||||
return os.path.abspath(os.path.expanduser(p))
|
return os.path.abspath(os.path.expanduser(p))
|
||||||
|
|
||||||
|
|
||||||
process_pool = []
|
process_pool = []
|
||||||
|
"""
|
||||||
|
List of processes started to execute sub-process commands
|
||||||
|
"""
|
||||||
|
|
||||||
def get_process():
|
def get_process():
|
||||||
|
"""
|
||||||
|
Returns a process object that can execute commands as sub-processes
|
||||||
|
|
||||||
|
:rtype: subprocess.Popen
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
return process_pool.pop()
|
return process_pool.pop()
|
||||||
except IndexError:
|
except IndexError:
|
||||||
|
@ -779,6 +818,9 @@ def get_process():
|
||||||
return subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, bufsize=0)
|
return subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, bufsize=0)
|
||||||
|
|
||||||
def run_prefork_process(cmd, kwargs, cargs):
|
def run_prefork_process(cmd, kwargs, cargs):
|
||||||
|
"""
|
||||||
|
Delegates process execution to a pre-forked process instance.
|
||||||
|
"""
|
||||||
obj = base64.b64encode(cPickle.dumps([cmd, kwargs, cargs]))
|
obj = base64.b64encode(cPickle.dumps([cmd, kwargs, cargs]))
|
||||||
|
|
||||||
proc = get_process()
|
proc = get_process()
|
||||||
|
@ -804,6 +846,9 @@ def run_prefork_process(cmd, kwargs, cargs):
|
||||||
return ret, out, err
|
return ret, out, err
|
||||||
|
|
||||||
def run_regular_process(cmd, kwargs, cargs={}):
|
def run_regular_process(cmd, kwargs, cargs={}):
|
||||||
|
"""
|
||||||
|
Executes a subprocess command by using subprocess.Popen
|
||||||
|
"""
|
||||||
proc = subprocess.Popen(cmd, **kwargs)
|
proc = subprocess.Popen(cmd, **kwargs)
|
||||||
if kwargs.get('stdout') or kwargs.get('stderr'):
|
if kwargs.get('stdout') or kwargs.get('stderr'):
|
||||||
out, err = proc.communicate(**cargs)
|
out, err = proc.communicate(**cargs)
|
||||||
|
@ -814,12 +859,27 @@ def run_regular_process(cmd, kwargs, cargs={}):
|
||||||
return status, out, err
|
return status, out, err
|
||||||
|
|
||||||
def run_process(cmd, kwargs, cargs={}):
|
def run_process(cmd, kwargs, cargs={}):
|
||||||
|
"""
|
||||||
|
Executes a subprocess by using a pre-forked process when possible
|
||||||
|
or falling back to subprocess.Popen. See :py:func:`waflib.Utils.run_prefork_process`
|
||||||
|
and :py:func:`waflib.Utils.run_regular_process`
|
||||||
|
"""
|
||||||
if kwargs.get('stdout') and kwargs.get('stderr'):
|
if kwargs.get('stdout') and kwargs.get('stderr'):
|
||||||
return run_prefork_process(cmd, kwargs, cargs)
|
return run_prefork_process(cmd, kwargs, cargs)
|
||||||
else:
|
else:
|
||||||
return run_regular_process(cmd, kwargs, cargs)
|
return run_regular_process(cmd, kwargs, cargs)
|
||||||
|
|
||||||
def alloc_process_pool(n, force=False):
|
def alloc_process_pool(n, force=False):
|
||||||
|
"""
|
||||||
|
Allocates an amount of processes to the default pool so its size is at least *n*.
|
||||||
|
It is useful to call this function early so that the pre-forked
|
||||||
|
processes use as little memory as possible.
|
||||||
|
|
||||||
|
:param n: pool size
|
||||||
|
:type n: integer
|
||||||
|
:param force: if True then *n* more processes are added to the existing pool
|
||||||
|
:type force: bool
|
||||||
|
"""
|
||||||
# mandatory on python2, unnecessary on python >= 3.2
|
# mandatory on python2, unnecessary on python >= 3.2
|
||||||
global run_process, get_process, alloc_process_pool
|
global run_process, get_process, alloc_process_pool
|
||||||
if not force:
|
if not force:
|
||||||
|
|
Loading…
Reference in New Issue