mirror of
https://gitlab.com/ita1024/waf.git
synced 2024-11-22 09:57:15 +01:00
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 = {}
|
||||
"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):
|
||||
"""
|
||||
Metaclass: store the task classes into :py:const:`waflib.Task.classes`, or to the dict pointed
|
||||
by the class attribute 'register'.
|
||||
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
|
||||
Metaclass: store the task classes into the dict pointed by the
|
||||
class attribute 'register' which defaults to :py:const:`waflib.Task.classes`,
|
||||
|
||||
The attribute 'run_str' is compiled into a method 'run' bound to the task class.
|
||||
"""
|
||||
def __init__(cls, 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
|
||||
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
|
||||
#. runnable_status: ask the task if it should be run, skipped, or if we have to ask later
|
||||
#. run: let threads execute the task
|
||||
#. post_run: let threads update the data regarding the task (cache)
|
||||
|
||||
.. warning:: For backward compatibility reasons, the suffix "_task" is truncated in derived class names. This limitation will be removed in Waf 1.9.
|
||||
#. run: what to do to execute the task
|
||||
#. post_run: what to do after the task has been executed
|
||||
"""
|
||||
|
||||
color = 'GREEN'
|
||||
"""Color for the console display, see :py:const:`waflib.Logs.colors_lst`"""
|
||||
|
||||
ext_in = []
|
||||
"""File extensions that objects of this task class might use"""
|
||||
"""File extensions that objects of this task class may use"""
|
||||
|
||||
ext_out = []
|
||||
"""File extensions that objects of this task class might create"""
|
||||
"""File extensions that objects of this task class may create"""
|
||||
|
||||
before = []
|
||||
"""List of task class names to execute before instances of this class"""
|
||||
@ -144,7 +145,7 @@ class TaskBase(evil):
|
||||
|
||||
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
|
||||
try:
|
||||
@ -153,21 +154,25 @@ class TaskBase(evil):
|
||||
self.generator = self
|
||||
|
||||
def __repr__(self):
|
||||
"for debugging purposes"
|
||||
return '\n\t{task %r: %s %s}' % (self.__class__.__name__, id(self), str(getattr(self, 'fun', '')))
|
||||
|
||||
def __str__(self):
|
||||
"string to display to the user"
|
||||
"String to display to the user"
|
||||
if hasattr(self, 'fun'):
|
||||
return self.fun.__name__
|
||||
return self.__class__.__name__
|
||||
|
||||
def keyword(self):
|
||||
"Display keyword used to prettify the console outputs"
|
||||
if hasattr(self, 'fun'):
|
||||
return 'Function'
|
||||
return 'Processing'
|
||||
|
||||
def get_cwd(self):
|
||||
"""
|
||||
:return: current working directory
|
||||
:rtype: :py:class:`waflib.Node.Node`
|
||||
"""
|
||||
bld = self.generator.bld
|
||||
ret = getattr(self, 'cwd', None) or getattr(self.generator.bld, 'cwd', bld.bldnode)
|
||||
if isinstance(ret, str):
|
||||
@ -175,6 +180,14 @@ class TaskBase(evil):
|
||||
return ret
|
||||
|
||||
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
|
||||
if '\\' in x:
|
||||
x = x.replace('\\', '\\\\')
|
||||
@ -185,12 +198,23 @@ class TaskBase(evil):
|
||||
return x
|
||||
|
||||
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:]])
|
||||
|
||||
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
|
||||
:rtype: int
|
||||
"""
|
||||
@ -221,7 +245,7 @@ class TaskBase(evil):
|
||||
|
||||
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`.
|
||||
:rtype: int
|
||||
@ -229,12 +253,20 @@ class TaskBase(evil):
|
||||
return RUN_ME
|
||||
|
||||
def uid(self):
|
||||
"""
|
||||
Computes a unique identifier for the task
|
||||
|
||||
:rtype: string or bytes
|
||||
"""
|
||||
return Utils.SIG_NIL
|
||||
|
||||
def process(self):
|
||||
"""
|
||||
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).
|
||||
|
||||
:return: 0 or None if everything is fine
|
||||
:rtype: integer
|
||||
"""
|
||||
# remove the task signature immediately before it is executed
|
||||
# in case of failure the task will be executed again
|
||||
@ -274,7 +306,8 @@ class TaskBase(evil):
|
||||
def run(self):
|
||||
"""
|
||||
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
|
||||
"""
|
||||
@ -283,11 +316,11 @@ class TaskBase(evil):
|
||||
return 0
|
||||
|
||||
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
|
||||
|
||||
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:
|
||||
return
|
||||
|
||||
@ -307,7 +340,7 @@ class TaskBase(evil):
|
||||
|
||||
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
|
||||
"""
|
||||
@ -351,19 +384,18 @@ class TaskBase(evil):
|
||||
|
||||
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
|
||||
:rtype: string
|
||||
"""
|
||||
cls = self.__class__
|
||||
tup = (str(cls.before), str(cls.after), str(cls.ext_in), str(cls.ext_out), cls.__name__, cls.hcode)
|
||||
h = hash(tup)
|
||||
return h
|
||||
return hash(tup)
|
||||
|
||||
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
|
||||
"""
|
||||
@ -385,7 +417,7 @@ class TaskBase(evil):
|
||||
|
||||
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
|
||||
|
||||
The results will be slightly different if FOO_ST is a list, for example::
|
||||
@ -424,10 +456,10 @@ class Task(TaskBase):
|
||||
nodes (if present).
|
||||
"""
|
||||
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
|
||||
"""Specify whether task instances must always be executed or not"""
|
||||
"""Specify whether task instances must always be executed or not (class attribute)"""
|
||||
|
||||
shell = False
|
||||
"""Execute the command with the shell (class attribute)"""
|
||||
@ -436,7 +468,7 @@ class Task(TaskBase):
|
||||
TaskBase.__init__(self, *k, **kw)
|
||||
|
||||
self.env = kw['env']
|
||||
"""ConfigSet object (make sure to provide one)"""
|
||||
""":py:class:`waflib.ConfigSet.ConfigSet` object (make sure to provide one)"""
|
||||
|
||||
self.inputs = []
|
||||
"""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)
|
||||
|
||||
def keyword(self):
|
||||
"""
|
||||
See :py:meth:`waflib.Task.TaskBase`
|
||||
"""
|
||||
name = self.__class__.__name__
|
||||
if name.endswith(('lib', 'program')):
|
||||
return 'Linking'
|
||||
@ -494,10 +529,10 @@ class Task(TaskBase):
|
||||
|
||||
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:
|
||||
|
||||
- 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
|
||||
|
||||
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):
|
||||
"""
|
||||
Append the nodes to the *inputs*
|
||||
Appends the nodes to the *inputs* list
|
||||
|
||||
:param inp: input nodes
|
||||
:type inp: node or list of nodes
|
||||
@ -531,7 +566,7 @@ class Task(TaskBase):
|
||||
|
||||
def set_outputs(self, out):
|
||||
"""
|
||||
Append the nodes to the *outputs*
|
||||
Appends the nodes to the *outputs* list
|
||||
|
||||
:param out: output nodes
|
||||
:type out: node or list of nodes
|
||||
@ -541,8 +576,7 @@ class Task(TaskBase):
|
||||
|
||||
def set_run_after(self, task):
|
||||
"""
|
||||
Run this task only after *task*. Affect :py:meth:`waflib.Task.runnable_status`
|
||||
You probably want to use tsk.run_after.add(task) directly
|
||||
Run this task only after the given *task*.
|
||||
|
||||
:param task: task
|
||||
:type task: :py:class:`waflib.Task.Task`
|
||||
@ -567,9 +601,14 @@ class Task(TaskBase):
|
||||
sig = super(Task.Task, self).signature()
|
||||
delattr(self, 'cache_sig')
|
||||
return super(Task.Task, self).signature()
|
||||
|
||||
:return: the signature value
|
||||
:rtype: string or bytes
|
||||
"""
|
||||
try: return self.cache_sig
|
||||
except AttributeError: pass
|
||||
try:
|
||||
return self.cache_sig
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
self.m = Utils.md5(self.hcode)
|
||||
|
||||
@ -591,8 +630,7 @@ class Task(TaskBase):
|
||||
|
||||
def runnable_status(self):
|
||||
"""
|
||||
Override :py:meth:`waflib.Task.TaskBase.runnable_status` to determine if the task is ready
|
||||
to be run (:py:attr:`waflib.Task.Task.run_after`)
|
||||
See :py:meth:`waflib.Task.TaskBase.runnable_status`
|
||||
"""
|
||||
#return 0 # benchmarking
|
||||
|
||||
@ -636,11 +674,8 @@ class Task(TaskBase):
|
||||
|
||||
def post_run(self):
|
||||
"""
|
||||
Called after successful execution to update the cache data :py:class:`waflib.Node.Node` sigs
|
||||
and :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.
|
||||
Called after successful execution to record that the task has run by
|
||||
updating the entry in :py:attr:`waflib.Build.BuildContext.task_sigs`.
|
||||
"""
|
||||
bld = self.generator.bld
|
||||
for node in self.outputs:
|
||||
@ -657,7 +692,7 @@ class Task(TaskBase):
|
||||
|
||||
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.
|
||||
"""
|
||||
bld = self.generator.bld
|
||||
@ -685,7 +720,7 @@ class Task(TaskBase):
|
||||
|
||||
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)
|
||||
self.m.update(sig)
|
||||
@ -702,24 +737,21 @@ class Task(TaskBase):
|
||||
from waflib.Task import Task
|
||||
class mytask(Task):
|
||||
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.
|
||||
"""
|
||||
|
||||
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
|
||||
when a file has changed. When this occurs, :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`
|
||||
for searching the dependencies.
|
||||
|
||||
:rtype: hash value
|
||||
when a file has changed. In this case, the method :py:meth:`waflib.Task.Task.signature` is called
|
||||
once again, and return here to call :py:meth:`waflib.Task.Task.scan` and searching for dependencies.
|
||||
"""
|
||||
|
||||
bld = self.generator.bld
|
||||
|
||||
# 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
|
||||
: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
|
||||
self.are_implicit_nodes_ready()
|
||||
@ -777,9 +812,10 @@ class Task(TaskBase):
|
||||
|
||||
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
|
||||
try:
|
||||
@ -823,7 +859,7 @@ if sys.hexversion > 0x3000000:
|
||||
|
||||
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'
|
||||
t2.ext_in = '.h'
|
||||
@ -831,9 +867,9 @@ def is_before(t1, t2):
|
||||
t1.before = ['t2']
|
||||
waflib.Task.is_before(t1, t2) # True
|
||||
|
||||
:param t1: task
|
||||
:param t1: Task object
|
||||
:type t1: :py:class:`waflib.Task.TaskBase`
|
||||
:param t2: task
|
||||
:param t2: Task object
|
||||
:type t2: :py:class:`waflib.Task.TaskBase`
|
||||
"""
|
||||
to_list = Utils.to_list
|
||||
@ -851,7 +887,7 @@ def is_before(t1, t2):
|
||||
|
||||
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
|
||||
:type tasks: list of :py:class:`waflib.Task.TaskBase`
|
||||
@ -871,7 +907,7 @@ def set_file_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
|
||||
:type tasks: list of :py:class:`waflib.Task.TaskBase`
|
||||
@ -906,7 +942,7 @@ def set_precedence_constraints(tasks):
|
||||
|
||||
def funex(c):
|
||||
"""
|
||||
Compile a function by 'exec'
|
||||
Compiles a scriptlet expression into a Python function
|
||||
|
||||
:param c: function to compile
|
||||
: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)
|
||||
def compile_fun_shell(line):
|
||||
"""
|
||||
Create a compiled function to execute a process with the shell
|
||||
WARNING: this method may disappear anytime, so use compile_fun instead
|
||||
Creates a compiled function to execute a process through a sub-shell
|
||||
"""
|
||||
|
||||
extr = []
|
||||
def repl(match):
|
||||
g = match.group
|
||||
if g('dollar'): return "$"
|
||||
elif g('backslash'): return '\\\\'
|
||||
elif g('subst'): extr.append((g('var'), g('code'))); return "%s"
|
||||
if g('dollar'):
|
||||
return "$"
|
||||
elif g('backslash'):
|
||||
return '\\\\'
|
||||
elif g('subst'):
|
||||
extr.append((g('var'), g('code')))
|
||||
return "%s"
|
||||
return None
|
||||
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)
|
||||
def compile_fun_noshell(line):
|
||||
"""
|
||||
Create a compiled function to execute a process without the shell
|
||||
WARNING: this method may disappear anytime, so use compile_fun instead
|
||||
Creates a compiled function to execute a process without a sub-shell
|
||||
"""
|
||||
buf = []
|
||||
dvars = []
|
||||
@ -1076,10 +1113,10 @@ def compile_fun_noshell(line):
|
||||
|
||||
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 list of variables that imply a dependency from self.env
|
||||
* The function created (compiled) for use as :py:meth:`waflib.Task.TaskBase.run`
|
||||
* The list of variables that must cause rebuilds when *env* data is modified
|
||||
|
||||
for example::
|
||||
|
||||
@ -1089,8 +1126,8 @@ def compile_fun(line, shell=False):
|
||||
def build(bld):
|
||||
bld(source='wscript', rule='echo "foo\\${SRC[0].name}\\bar"')
|
||||
|
||||
The env variables (CXX, ..) on the task must not hold dicts (order)
|
||||
The reserved keywords *TGT* and *SRC* represent the task input and output nodes
|
||||
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
|
||||
|
||||
"""
|
||||
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):
|
||||
"""
|
||||
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
|
||||
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 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
|
||||
@ -34,31 +32,28 @@ class task_gen(object):
|
||||
"""
|
||||
|
||||
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)
|
||||
"""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):
|
||||
"""
|
||||
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)
|
||||
|
||||
The tasks are stored on the attribute 'tasks'. They are created by calling methods
|
||||
listed in self.meths *or* referenced in the attribute features
|
||||
A topological sort is performed to ease the method re-use.
|
||||
Tasks are stored on the attribute 'tasks'. They are created by calling methods
|
||||
listed in ``self.meths`` or referenced in the attribute ``features``
|
||||
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.target = ''
|
||||
|
||||
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 = []
|
||||
@ -68,7 +63,7 @@ class task_gen(object):
|
||||
|
||||
self.tasks = []
|
||||
"""
|
||||
List of tasks created.
|
||||
Tasks created are added to this list
|
||||
"""
|
||||
|
||||
if not 'bld' in kw:
|
||||
@ -92,11 +87,11 @@ class task_gen(object):
|
||||
setattr(self, key, val)
|
||||
|
||||
def __str__(self):
|
||||
"""for debugging purposes"""
|
||||
"""Debugging helper"""
|
||||
return "<task_gen %r declared in %s>" % (self.name, self.path.abspath())
|
||||
|
||||
def __repr__(self):
|
||||
"""for debugging purposes"""
|
||||
"""Debugging helper"""
|
||||
lst = []
|
||||
for x in self.__dict__:
|
||||
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())
|
||||
|
||||
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
|
||||
|
||||
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):
|
||||
x = bld(name='foo')
|
||||
@ -135,18 +138,20 @@ class task_gen(object):
|
||||
|
||||
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
|
||||
:param val: input to return as a list
|
||||
:rtype: list
|
||||
"""
|
||||
if isinstance(val, str): return val.split()
|
||||
else: return val
|
||||
if isinstance(val, str):
|
||||
return val.split()
|
||||
else:
|
||||
return val
|
||||
|
||||
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 attribute ``features`` is used to add more methods in ``self.meths``
|
||||
@ -226,6 +231,8 @@ class task_gen(object):
|
||||
|
||||
def get_hook(self, node):
|
||||
"""
|
||||
Returns the ``@extension`` method to call for a Node of a particular extension.
|
||||
|
||||
:param node: Input file to process
|
||||
:type node: :py:class:`waflib.Tools.Node.Node`
|
||||
: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):
|
||||
"""
|
||||
Wrapper for creating task instances. The classes are retrieved from the
|
||||
context class if possible, then from the global dict Task.classes.
|
||||
Creates task instances.
|
||||
|
||||
:param name: task class name
|
||||
:type name: string
|
||||
@ -267,7 +273,7 @@ class task_gen(object):
|
||||
|
||||
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
|
||||
be compiled several times.
|
||||
|
||||
@ -296,7 +302,7 @@ class task_gen(object):
|
||||
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):
|
||||
"""
|
||||
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.
|
||||
|
||||
: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):
|
||||
"""
|
||||
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::
|
||||
|
||||
from waflib.TaskGen import taskgen_method
|
||||
@ -378,8 +384,8 @@ def taskgen_method(func):
|
||||
|
||||
def feature(*k):
|
||||
"""
|
||||
Decorator: register a task generator method that will be executed when the
|
||||
object attribute 'feature' contains the corresponding key(s)::
|
||||
Decorator that registers a task generator method that will be executed when the
|
||||
object attribute ``feature`` contains the corresponding key(s)::
|
||||
|
||||
from waflib.Task import feature
|
||||
@feature('myfeature')
|
||||
@ -400,7 +406,7 @@ def feature(*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)::
|
||||
|
||||
from waflib.TaskGen import feature, before
|
||||
@ -429,7 +435,7 @@ before = before_method
|
||||
|
||||
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)::
|
||||
|
||||
from waflib.TaskGen import feature, after
|
||||
@ -458,7 +464,7 @@ after = after_method
|
||||
|
||||
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::
|
||||
|
||||
from waflib import Task
|
||||
@ -484,7 +490,7 @@ def extension(*k):
|
||||
@taskgen_method
|
||||
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 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('*')
|
||||
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.
|
||||
#. 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')
|
||||
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):
|
||||
bld(rule='cp ${SRC} ${TGT}', source='wscript', target='bar.txt')
|
||||
@ -627,7 +633,7 @@ def process_rule(self):
|
||||
@feature('seq')
|
||||
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 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):
|
||||
"""
|
||||
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.
|
||||
"""
|
||||
|
||||
@ -762,7 +768,7 @@ class subst_pc(Task.Task):
|
||||
@extension('.pc.in')
|
||||
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):
|
||||
bld(source='foo.pc.in', install_path='${LIBDIR}/pkgconfig/')
|
||||
@ -778,7 +784,7 @@ class subst(subst_pc):
|
||||
@before_method('process_source', 'process_rule')
|
||||
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):
|
||||
bld(
|
||||
|
140
waflib/Utils.py
140
waflib/Utils.py
@ -82,7 +82,7 @@ rot_idx = 0
|
||||
"Index of the current throbber character (progress bar)"
|
||||
|
||||
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):
|
||||
self.lst = deque()
|
||||
dict.__init__(self, *k, **kw)
|
||||
@ -106,6 +106,9 @@ class ordered_iter_dict(dict):
|
||||
return reversed(self.lst)
|
||||
|
||||
class lru_node(object):
|
||||
"""
|
||||
Used by :py:class:`waflib.Utils.lru_cache`
|
||||
"""
|
||||
__slots__ = ('next', 'prev', 'key', 'val')
|
||||
def __init__(self):
|
||||
self.next = self
|
||||
@ -118,7 +121,13 @@ class lru_cache(object):
|
||||
__slots__ = ('maxlen', 'table', 'head')
|
||||
def __init__(self, maxlen=100):
|
||||
self.maxlen = maxlen
|
||||
"""
|
||||
Maximum amount of elements in the cache
|
||||
"""
|
||||
self.table = {}
|
||||
"""
|
||||
Mapping key-value
|
||||
"""
|
||||
self.head = lru_node()
|
||||
for x in range(maxlen - 1):
|
||||
node = lru_node()
|
||||
@ -159,12 +168,13 @@ class lru_cache(object):
|
||||
self.table[key] = node
|
||||
|
||||
is_win32 = os.sep == '\\' or sys.platform == 'win32' # msys2
|
||||
"""
|
||||
Whether this system is a Windows series
|
||||
"""
|
||||
|
||||
def readf(fname, m='r', encoding='ISO8859-1'):
|
||||
"""
|
||||
Read an entire file into a string, use this function instead of os.open() whenever possible.
|
||||
|
||||
In practice the wrapper node.read(..) should be preferred to this function::
|
||||
Reads an entire file into a string. See also :py:meth:`waflib.Node.Node.readf`::
|
||||
|
||||
def build(ctx):
|
||||
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'):
|
||||
"""
|
||||
Write an entire file from a string, use this function instead of os.open() whenever possible.
|
||||
|
||||
In practice the wrapper node.write(..) should be preferred to this function::
|
||||
Writes an entire file from a string.
|
||||
See also :py:meth:`waflib.Node.Node.writef`::
|
||||
|
||||
def build(ctx):
|
||||
from waflib import Utils
|
||||
@ -237,6 +246,7 @@ def h_file(fname):
|
||||
:type fname: string
|
||||
:param fname: path to the file to hash
|
||||
:return: hash of the file contents
|
||||
:rtype: string or bytes
|
||||
"""
|
||||
f = open(fname, 'rb')
|
||||
m = md5()
|
||||
@ -344,8 +354,8 @@ Return the hexadecimal representation of a string
|
||||
|
||||
def listdir_win32(s):
|
||||
"""
|
||||
List the contents of a folder in a portable manner.
|
||||
On Win32, return the list of drive letters: ['C:', 'X:', 'Z:']
|
||||
Lists the contents of a folder in a portable manner.
|
||||
On Win32, returns the list of drive letters: ['C:', 'X:', 'Z:'] when an empty string is given.
|
||||
|
||||
:type s: string
|
||||
:param s: a string, which can be empty on Windows
|
||||
@ -378,7 +388,7 @@ if is_win32:
|
||||
|
||||
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
|
||||
num2ver('1.3.2') == num2ver((1,3,2)) == num2ver((1,3,2,0))
|
||||
@ -398,31 +408,29 @@ def num2ver(ver):
|
||||
|
||||
def ex_stack():
|
||||
"""
|
||||
Extract the stack to display exceptions
|
||||
Deprecated: use traceback.format_exc()
|
||||
Extracts the stack to display exceptions. Deprecated: use traceback.format_exc()
|
||||
|
||||
:return: a string represening the last exception
|
||||
"""
|
||||
# TODO remove in waf 2.0
|
||||
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
|
||||
through a list argument unchanged::
|
||||
Converts a string argument to a list by splitting it by spaces.
|
||||
Returns the object if not a string::
|
||||
|
||||
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
|
||||
:return: Argument converted to list
|
||||
|
||||
"""
|
||||
if isinstance(sth, str):
|
||||
return sth.split()
|
||||
if isinstance(val, str):
|
||||
return val.split()
|
||||
else:
|
||||
return sth
|
||||
return val
|
||||
|
||||
def split_path_unix(path):
|
||||
return path.split('/')
|
||||
@ -465,19 +473,20 @@ else:
|
||||
split_path = split_path_unix
|
||||
|
||||
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
|
||||
:param path: path to split
|
||||
:return: list of strings
|
||||
:return: list of string
|
||||
"""
|
||||
|
||||
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
|
||||
:param path: Path to directory
|
||||
:raises: :py:class:`waflib.Errors.WafError` if the folder cannot be added.
|
||||
"""
|
||||
if not os.path.isdir(path):
|
||||
try:
|
||||
@ -488,11 +497,14 @@ def check_dir(path):
|
||||
|
||||
def check_exe(name, env=None):
|
||||
"""
|
||||
Ensure that a program exists
|
||||
Ensures that a program exists
|
||||
|
||||
: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
|
||||
:raises: :py:class:`waflib.Errors.WafError` if the folder cannot be added.
|
||||
"""
|
||||
if not name:
|
||||
raise ValueError('Cannot execute an empty string!')
|
||||
@ -504,7 +516,7 @@ def check_exe(name, env=None):
|
||||
return os.path.abspath(name)
|
||||
else:
|
||||
env = env or os.environ
|
||||
for path in env["PATH"].split(os.pathsep):
|
||||
for path in env['PATH'].split(os.pathsep):
|
||||
path = path.strip('"')
|
||||
exe_file = os.path.join(path, name)
|
||||
if is_exe(exe_file):
|
||||
@ -513,7 +525,7 @@ def check_exe(name, env=None):
|
||||
|
||||
def def_attrs(cls, **kw):
|
||||
"""
|
||||
Set default attributes on a class instance
|
||||
Sets default attributes on a class instance
|
||||
|
||||
:type cls: class
|
||||
:param cls: the class to update the given attributes in.
|
||||
@ -526,7 +538,7 @@ def def_attrs(cls, **kw):
|
||||
|
||||
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
|
||||
:param s: String to convert
|
||||
@ -540,8 +552,8 @@ def quote_define_name(s):
|
||||
|
||||
def h_list(lst):
|
||||
"""
|
||||
Hash lists. For tuples, using hash(tup) is much more efficient,
|
||||
except on python >= 3.3 where hash randomization assumes everybody is running a web application.
|
||||
Hash lists. We would prefer to use hash(tup) for tuples because it is much more efficient,
|
||||
but Python now enforces hash randomization by assuming everybody is running a web application.
|
||||
|
||||
:param lst: list to hash
|
||||
:type lst: list of strings
|
||||
@ -556,6 +568,7 @@ def h_fun(fun):
|
||||
:param fun: function to hash
|
||||
:type fun: function
|
||||
:return: hash of the function
|
||||
:rtype: string or bytes
|
||||
"""
|
||||
try:
|
||||
return fun.code
|
||||
@ -563,7 +576,7 @@ def h_fun(fun):
|
||||
try:
|
||||
h = inspect.getsource(fun)
|
||||
except EnvironmentError:
|
||||
h = "nocode"
|
||||
h = 'nocode'
|
||||
try:
|
||||
fun.code = h
|
||||
except AttributeError:
|
||||
@ -572,8 +585,11 @@ def h_fun(fun):
|
||||
|
||||
def h_cmd(ins):
|
||||
"""
|
||||
Task command hashes are calculated by calling this function. The inputs can be
|
||||
strings, functions, tuples/lists containing strings/functions
|
||||
Hashes objects recursively
|
||||
|
||||
: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
|
||||
if isinstance(ins, str):
|
||||
@ -592,7 +608,7 @@ def h_cmd(ins):
|
||||
reg_subst = re.compile(r"(\\\\)|(\$\$)|\$\{([^}]+)\}")
|
||||
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
|
||||
s = Utils.subst_vars('${PREFIX}/bin', env)
|
||||
@ -617,7 +633,8 @@ def subst_vars(expr, params):
|
||||
|
||||
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
|
||||
:type key: string
|
||||
@ -631,7 +648,7 @@ def destos_to_binfmt(key):
|
||||
|
||||
def unversioned_sys_platform():
|
||||
"""
|
||||
Return the unversioned platform name.
|
||||
Returns the unversioned platform name.
|
||||
Some Python platform names contain versions, that depend on
|
||||
the build environment, e.g. linux2, freebsd6, etc.
|
||||
This returns the name without the version number. Exceptions are
|
||||
@ -670,7 +687,7 @@ def unversioned_sys_platform():
|
||||
|
||||
def nada(*k, **kw):
|
||||
"""
|
||||
A function that does nothing
|
||||
Does nothing
|
||||
|
||||
:return: None
|
||||
"""
|
||||
@ -706,7 +723,7 @@ class Timer(object):
|
||||
|
||||
def read_la_file(path):
|
||||
"""
|
||||
Read property files, used by msvc.py
|
||||
Reads property files, used by msvc.py
|
||||
|
||||
:param path: file to read
|
||||
:type path: string
|
||||
@ -729,6 +746,8 @@ def run_once(fun):
|
||||
def foo(k):
|
||||
return 345*2343
|
||||
|
||||
.. note:: in practice this can cause memory leaks, prefer a :py:class:`waflib.Utils.lru_cache`
|
||||
|
||||
:param fun: function to execute
|
||||
:type fun: function
|
||||
:return: the return value of the function executed
|
||||
@ -746,6 +765,12 @@ def run_once(fun):
|
||||
return wrap
|
||||
|
||||
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:
|
||||
return None
|
||||
try:
|
||||
@ -757,6 +782,12 @@ def get_registry_app_path(key, filename):
|
||||
return result
|
||||
|
||||
def lib64():
|
||||
"""
|
||||
Guess the default ``/usr/lib`` extension for 64-bit applications
|
||||
|
||||
:return: '64' or ''
|
||||
:rtype: string
|
||||
"""
|
||||
# default settings for /usr/lib
|
||||
if os.sep == '/':
|
||||
if platform.architecture()[0] == '64bit':
|
||||
@ -768,9 +799,17 @@ def sane_path(p):
|
||||
# private function for the time being!
|
||||
return os.path.abspath(os.path.expanduser(p))
|
||||
|
||||
|
||||
process_pool = []
|
||||
"""
|
||||
List of processes started to execute sub-process commands
|
||||
"""
|
||||
|
||||
def get_process():
|
||||
"""
|
||||
Returns a process object that can execute commands as sub-processes
|
||||
|
||||
:rtype: subprocess.Popen
|
||||
"""
|
||||
try:
|
||||
return process_pool.pop()
|
||||
except IndexError:
|
||||
@ -779,6 +818,9 @@ def get_process():
|
||||
return subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, bufsize=0)
|
||||
|
||||
def run_prefork_process(cmd, kwargs, cargs):
|
||||
"""
|
||||
Delegates process execution to a pre-forked process instance.
|
||||
"""
|
||||
obj = base64.b64encode(cPickle.dumps([cmd, kwargs, cargs]))
|
||||
|
||||
proc = get_process()
|
||||
@ -804,6 +846,9 @@ def run_prefork_process(cmd, kwargs, cargs):
|
||||
return ret, out, err
|
||||
|
||||
def run_regular_process(cmd, kwargs, cargs={}):
|
||||
"""
|
||||
Executes a subprocess command by using subprocess.Popen
|
||||
"""
|
||||
proc = subprocess.Popen(cmd, **kwargs)
|
||||
if kwargs.get('stdout') or kwargs.get('stderr'):
|
||||
out, err = proc.communicate(**cargs)
|
||||
@ -814,12 +859,27 @@ def run_regular_process(cmd, kwargs, cargs={}):
|
||||
return status, out, err
|
||||
|
||||
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'):
|
||||
return run_prefork_process(cmd, kwargs, cargs)
|
||||
else:
|
||||
return run_regular_process(cmd, kwargs, cargs)
|
||||
|
||||
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
|
||||
global run_process, get_process, alloc_process_pool
|
||||
if not force:
|
||||
|
Loading…
Reference in New Issue
Block a user