2
0
mirror of https://gitlab.com/ita1024/waf.git synced 2024-11-22 09:57:15 +01:00
This commit is contained in:
Thomas Nagy 2016-06-25 14:49:27 +02:00
parent a2ca4b6dab
commit ef6525c0bf
No known key found for this signature in database
GPG Key ID: 67A565EDFDF90E64
13 changed files with 129 additions and 66 deletions

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
# encoding: utf-8
# Thomas Nagy, 2005-2010 (ita)
# Thomas Nagy, 2005-2016 (ita)
"""

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
# encoding: utf-8
# Thomas Nagy, 2005-2010 (ita)
# Thomas Nagy, 2005-2016 (ita)
"""
Configuration system

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
# encoding: utf-8
# Thomas Nagy, 2010 (ita)
# Thomas Nagy, 2010-2016 (ita)
"""
Exceptions used in the Waf code

View File

@ -76,7 +76,7 @@ class Node(object):
__slots__ = ('name', 'parent', 'children', 'cache_abspath', 'cache_isdir')
def __init__(self, name, parent):
"""
.. note:: Use :py:func:`Node.make_node` or :py:func:`Node.find_node`.
.. note:: Use :py:func:`Node.make_node` or :py:func:`Node.find_node` instead of calling this constructor
"""
self.name = name
self.parent = parent

View File

@ -15,10 +15,9 @@ from waflib import Logs, Utils, Context, Errors
options = {}
"""
A global dictionary representing the command-line options::
A global dictionary representing user-provided command-line options::
$ waf --foo=bar
"""
commands = []
@ -44,8 +43,8 @@ class opt_parser(optparse.OptionParser):
Command-line options parser.
"""
def __init__(self, ctx):
optparse.OptionParser.__init__(self, conflict_handler="resolve", version='waf %s (%s)' % (Context.WAFVERSION, Context.WAFREVISION))
optparse.OptionParser.__init__(self, conflict_handler="resolve",
version='waf %s (%s)' % (Context.WAFVERSION, Context.WAFREVISION))
self.formatter.width = Logs.get_term_cols()
self.ctx = ctx
@ -54,7 +53,9 @@ class opt_parser(optparse.OptionParser):
def get_usage(self):
"""
Return the message to print on ``waf --help``
Builds the message to print on ``waf --help``
:rtype: string
"""
cmds_str = {}
for cls in Context.classes:
@ -90,10 +91,9 @@ Main commands (example: ./waf build -j4)
class OptionsContext(Context.Context):
"""
Collect custom options from wscript files and parses the command line.
Set the global :py:const:`waflib.Options.commands` and :py:const:`waflib.Options.options` values.
Collects custom options from wscript files and parses the command line.
Sets the global :py:const:`waflib.Options.commands` and :py:const:`waflib.Options.options` values.
"""
cmd = 'options'
fun = 'options'
@ -156,8 +156,8 @@ class OptionsContext(Context.Context):
def jobs(self):
"""
Find the amount of cpu cores to set the default amount of tasks executed in parallel. At
runtime the options can be obtained from :py:const:`waflib.Options.options` ::
Finds the optimal amount of cpu cores to use for parallel jobs.
At runtime the options can be obtained from :py:const:`waflib.Options.options` ::
from waflib.Options import options
njobs = options.jobs
@ -193,21 +193,25 @@ class OptionsContext(Context.Context):
def add_option(self, *k, **kw):
"""
Wrapper for optparse.add_option::
Wraps ``optparse.add_option``::
def options(ctx):
ctx.add_option('-u', '--use', dest='use', default=False, action='store_true',
help='a boolean option')
ctx.add_option('-u', '--use', dest='use', default=False,
action='store_true', help='a boolean option')
:rtype: optparse option object
"""
return self.parser.add_option(*k, **kw)
def add_option_group(self, *k, **kw):
"""
Wrapper for optparse.add_option_group::
Wraps ``optparse.add_option_group``::
def options(ctx):
gr = ctx.add_option_group('some options')
gr.add_option('-u', '--use', dest='use', default=False, action='store_true')
:rtype: optparse option group object
"""
try:
gr = self.option_groups[k[0]]
@ -218,13 +222,14 @@ class OptionsContext(Context.Context):
def get_option_group(self, opt_str):
"""
Wrapper for optparse.get_option_group::
Wraps ``optparse.get_option_group``::
def options(ctx):
gr = ctx.get_option_group('configure options')
gr.add_option('-o', '--out', action='store', default='',
help='build dir for the project', dest='out')
:rtype: optparse option group object
"""
try:
return self.option_groups[opt_str]
@ -236,7 +241,7 @@ class OptionsContext(Context.Context):
def parse_args(self, _args=None):
"""
Parse arguments from a list (not bound to the command-line).
Parses arguments from a list which is not necesarily the command-line.
:param _args: arguments
:type _args: list of strings

View File

@ -1,10 +1,9 @@
#!/usr/bin/env python
# encoding: utf-8
# Thomas Nagy, 2005-2010 (ita)
# Thomas Nagy, 2005-2016 (ita)
"""
Runner.py: Task scheduling and execution
"""
import random
@ -16,18 +15,28 @@ from waflib import Utils, Task, Errors, Logs
GAP = 20
"""
Wait for free tasks if there are at least ``GAP * njobs`` in queue
Wait for at least ``GAP * njobs`` before trying to enqueue more tasks to run
"""
class Consumer(Utils.threading.Thread):
"""
Daemon thread object that executes a task. It shares a semaphore with
the coordinator :py:class:`waflib.Runner.Spawner`. There is one
instance per task to consume.
"""
__slots__ = ('task', 'spawner')
def __init__(self, spawner, task):
Utils.threading.Thread.__init__(self)
self.task = task
"""Task to execute"""
self.spawner = spawner
"""Coordinator object"""
self.setDaemon(1)
self.start()
def run(self):
"""
Processes a single task
"""
try:
if not self.spawner.master.stop:
self.task.process()
@ -38,13 +47,23 @@ class Consumer(Utils.threading.Thread):
self.spawner = None
class Spawner(Utils.threading.Thread):
"""
Daemon thread that consumes tasks from :py:class:`waflib.Runner.Parallel` producer and
spawns a consuming thread :py:class:`waflib.Runner.Consumer` for each
:py:class:`waflib.Task.TaskBase` instance.
"""
def __init__(self, master):
Utils.threading.Thread.__init__(self)
self.master = master
""":py:class:`waflib.Runner.Parallel` producer instance"""
self.sem = Utils.threading.Semaphore(master.numjobs)
"""Bounded semaphore that prevents spawning more than *n* concurrent consumers"""
self.setDaemon(1)
self.start()
def run(self):
"""
Spawns new consumers to execute tasks by delegating to :py:meth:`waflib.Runner.Spawner.loop`
"""
try:
self.loop()
except Exception:
@ -52,6 +71,10 @@ class Spawner(Utils.threading.Thread):
# we also want to stop the thread properly
pass
def loop(self):
"""
Consumes task objects from the producer; ends when the producer has no more
task to provide.
"""
master = self.master
while 1:
task = master.ready.get()
@ -71,7 +94,7 @@ class Parallel(object):
self.numjobs = j
"""
Number of consumers in the pool
Amount of parallel consumers to use
"""
self.bld = bld
@ -83,10 +106,10 @@ class Parallel(object):
"""List of :py:class:`waflib.Task.TaskBase` that may be ready to be executed"""
self.frozen = Utils.deque()
"""List of :py:class:`waflib.Task.TaskBase` that cannot be executed immediately"""
"""List of :py:class:`waflib.Task.TaskBase` that are not ready yet"""
self.ready = Queue(0)
"""List of :py:class:`waflib.Task.TaskBase` ready to be executed by task consumers"""
"""List of :py:class:`waflib.Task.TaskBase` ready to be executed by consumers"""
self.out = Queue(0)
"""List of :py:class:`waflib.Task.TaskBase` returned by the task consumers"""
@ -107,13 +130,18 @@ class Parallel(object):
"""Task iterator which must give groups of parallelizable tasks when calling ``next()``"""
self.dirty = False
"""Flag to indicate that tasks have been executed, and that the build cache must be saved (call :py:meth:`waflib.Build.BuildContext.store`)"""
"""
Flag that indicates that the build cache must be saved when a task was executed
(calls :py:meth:`waflib.Build.BuildContext.store`)"""
self.spawner = Spawner(self)
"""
Coordinating daemon thread that spawns thread consumers
"""
def get_next_task(self):
"""
Obtain the next task to execute.
Obtains the next Task instance to run
:rtype: :py:class:`waflib.Task.TaskBase`
"""
@ -123,9 +151,10 @@ class Parallel(object):
def postpone(self, tsk):
"""
A task cannot be executed at this point, put it in the list :py:attr:`waflib.Runner.Parallel.frozen`.
Adds the task to the list :py:attr:`waflib.Runner.Parallel.frozen`.
The order is scrambled so as to consume as many tasks in parallel as possible.
:param tsk: task
:param tsk: task instance
:type tsk: :py:class:`waflib.Task.TaskBase`
"""
if random.randint(0, 1):
@ -135,7 +164,7 @@ class Parallel(object):
def refill_task_list(self):
"""
Put the next group of tasks to execute in :py:attr:`waflib.Runner.Parallel.outstanding`.
Adds the next group of tasks to execute in :py:attr:`waflib.Runner.Parallel.outstanding`.
"""
while self.count > self.numjobs * GAP:
self.get_out()
@ -171,9 +200,10 @@ class Parallel(object):
def add_more_tasks(self, tsk):
"""
Tasks may be added dynamically during the build by binding them to the task :py:attr:`waflib.Task.TaskBase.more_tasks`
If a task provides :py:attr:`waflib.Task.TaskBase.more_tasks`, then the tasks contained
in that list are added to the current build and will be processed before the next build group.
:param tsk: task
:param tsk: task instance
:type tsk: :py:attr:`waflib.Task.TaskBase`
"""
if getattr(tsk, 'more_tasks', None):
@ -182,8 +212,8 @@ class Parallel(object):
def get_out(self):
"""
Obtain one task returned from the task consumers, and update the task count. Add more tasks if necessary through
:py:attr:`waflib.Runner.Parallel.add_more_tasks`.
Waits for a Task that task consumers add to :py:attr:`waflib.Runner.Parallel.out` after execution.
Adds more Tasks if necessary through :py:attr:`waflib.Runner.Parallel.add_more_tasks`.
:rtype: :py:attr:`waflib.Task.TaskBase`
"""
@ -196,14 +226,17 @@ class Parallel(object):
def add_task(self, tsk):
"""
Pass a task to a consumer.
Enqueue a Task to :py:attr:`waflib.Runner.Parallel.ready` so that consumers can run them.
:param tsk: task
:param tsk: task instance
:type tsk: :py:attr:`waflib.Task.TaskBase`
"""
self.ready.put(tsk)
def skip(self, tsk):
"""
Mark a task as skipped/up-to-date
"""
tsk.hasrun = Task.SKIPPED
def error_handler(self, tsk):
@ -213,11 +246,11 @@ class Parallel(object):
$ waf build -k
:param tsk: task
:param tsk: task instance
:type tsk: :py:attr:`waflib.Task.TaskBase`
"""
if hasattr(tsk, 'scan') and hasattr(tsk, 'uid'):
# TODO waf 1.9 - this breaks encapsulation
# TODO waf 2.0 - this breaks encapsulation
try:
del self.bld.imp_sigs[tsk.uid()]
except KeyError:
@ -227,6 +260,12 @@ class Parallel(object):
self.error.append(tsk)
def task_status(self, tsk):
"""
Obtains the task status to decide whether to run it immediately or not.
:return: the exit status, for example :py:attr:`waflib.Task.ASK_LATER`
:rtype: integer
"""
try:
return tsk.runnable_status()
except Exception:
@ -250,10 +289,12 @@ class Parallel(object):
def start(self):
"""
Give tasks to :py:class:`waflib.Runner.TaskConsumer` instances until the build finishes or the ``stop`` flag is set.
If only one job is used, then execute the tasks one by one, without consumers.
Obtains Task instances from the BuildContext instance and adds the ones that need to be executed to
:py:class:`waflib.Runner.Parallel.ready` so that the :py:class:`waflib.Runner.Spawner` consumer thread
has them executed. Obtains the executed Tasks back from :py:class:`waflib.Runner.Parallel.out`
and marks the build as failed by setting the ``stop`` flag.
If only one job is used, then executes the tasks one by one, without consumers.
"""
self.total = self.bld.total()
while not self.stop:

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
# encoding: utf-8
# Thomas Nagy, 2005-2010 (ita)
# Thomas Nagy, 2005-2016 (ita)
"Module called for configuring, compiling and installing targets"
@ -208,7 +208,7 @@ def set_main_module(file_path):
def parse_options():
"""
Parse the command-line options and initialize the logging system.
Parses the command-line options and initialize the logging system.
Called by :py:func:`waflib.Scripting.waf_entry_point` during the initialization.
"""
Context.create_context('options').execute()
@ -237,7 +237,7 @@ def parse_options():
def run_command(cmd_name):
"""
Execute a single command. Called by :py:func:`waflib.Scripting.run_commands`.
Executes a single Waf command. Called by :py:func:`waflib.Scripting.run_commands`.
:param cmd_name: command to execute, like ``build``
:type cmd_name: string
@ -255,7 +255,7 @@ def run_command(cmd_name):
def run_commands():
"""
Execute the commands that were given on the command-line, and the other options
Execute the Waf commands that were given on the command-line, and the other options
Called by :py:func:`waflib.Scripting.waf_entry_point` during the initialization, and executed
after :py:func:`waflib.Scripting.parse_options`.
"""
@ -348,7 +348,7 @@ class Dist(Context.Context):
def archive(self):
"""
Create the archive.
Creates the source archive.
"""
import tarfile
@ -395,14 +395,20 @@ class Dist(Context.Context):
def get_tar_path(self, node):
"""
return the path to use for a node in the tar archive, the purpose of this
Return the path to use for a node in the tar archive, the purpose of this
is to let subclases resolve symbolic links or to change file names
:return: absolute path
:rtype: string
"""
return node.abspath()
def add_tar_file(self, x, tar):
"""
Add a file to the tar archive. Symlinks are not verified.
Adds a file to the tar archive. Symlinks are not verified.
:param x: file path
:param tar: tar file object
"""
p = self.get_tar_path(x)
tinfo = tar.gettarinfo(name=p, arcname=self.get_tar_prefix() + '/' + x.path_from(self.base_path))
@ -421,6 +427,11 @@ class Dist(Context.Context):
tar.addfile(tinfo)
def get_tar_prefix(self):
"""
Returns the base path for files added into the archive tar file
:rtype: string
"""
try:
return self.tar_prefix
except AttributeError:
@ -428,7 +439,8 @@ class Dist(Context.Context):
def get_arch_name(self):
"""
Return the name of the archive to create. Change the default value by setting *arch_name*::
Returns the archive file name.
Set the attribute *arch_name* to change the default value::
def dist(ctx):
ctx.arch_name = 'ctx.tar.bz2'
@ -443,7 +455,7 @@ class Dist(Context.Context):
def get_base_name(self):
"""
Return the default name of the main directory in the archive, which is set to *appname-version*.
Returns the default name of the main directory in the archive, which is set to *appname-version*.
Set the attribute *base_name* to change the default value::
def dist(ctx):
@ -461,8 +473,8 @@ class Dist(Context.Context):
def get_excl(self):
"""
Return the patterns to exclude for finding the files in the top-level directory. Set the attribute *excl*
to change the default value::
Returns the patterns to exclude for finding the files in the top-level directory.
Set the attribute *excl* to change the default value::
def dist(ctx):
ctx.excl = 'build **/*.o **/*.class'
@ -481,13 +493,13 @@ class Dist(Context.Context):
def get_files(self):
"""
The files to package are searched automatically by :py:func:`waflib.Node.Node.ant_glob`. Set
*files* to prevent this behaviour::
Files to package are searched automatically by :py:func:`waflib.Node.Node.ant_glob`.
Set *files* to prevent this behaviour::
def dist(ctx):
ctx.files = ctx.path.find_node('wscript')
The files are searched from the directory 'base_path', to change it, set::
Files are also searched from the directory 'base_path', to change it, set::
def dist(ctx):
ctx.base_path = path
@ -500,18 +512,16 @@ class Dist(Context.Context):
files = self.base_path.ant_glob('**/*', excl=self.get_excl())
return files
def dist(ctx):
'''makes a tarball for redistributing the sources'''
pass
class DistCheck(Dist):
"""
Create an archive of the project, and try to build the project in a temporary directory::
Creates an archive of the project, then attempts to build the project in a temporary directory::
$ waf distcheck
"""
fun = 'distcheck'
cmd = 'distcheck'
@ -525,7 +535,7 @@ class DistCheck(Dist):
def check(self):
"""
Create the archive, uncompress it and try to build the project
Creates the archive, uncompresses it and tries to build the project
"""
import tempfile, tarfile
@ -560,9 +570,12 @@ def distcheck(ctx):
def autoconfigure(execute_method):
"""
Decorator used to set the commands that can be configured automatically
Decorator that enables context commands to run *configure* as needed.
"""
def execute(self):
"""
Wraps :py:func:`waflib.Context.Context.execute` on the context class
"""
if not Configure.autoconfig:
return execute_method(self)

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
# encoding: utf-8
# Thomas Nagy, 2005-2010 (ita)
# Thomas Nagy, 2005-2016 (ita)
"""
Tasks represent atomic operations such as processes.

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
# encoding: utf-8
# Thomas Nagy, 2005-2010 (ita)
# Thomas Nagy, 2005-2016 (ita)
"""
Task generators

View File

@ -398,6 +398,10 @@ def apply_flags_ifort(self):
@feature('fcprogram', 'fcshlib', 'fcprogram_test')
@after_method('apply_link')
def apply_manifest_ifort(self):
"""
Enables manifest embedding in Fortran DLLs when using ifort on Windows
See: http://msdn2.microsoft.com/en-us/library/ms235542(VS.80).aspx
"""
if self.env.IFORT_WIN32 and getattr(self, 'link_task', None):
# it seems ifort.exe cannot be called for linking
self.link_task.env.FC = self.env.LINK_FC

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
# encoding: utf-8
# Thomas Nagy, 2005-2010 (ita)
# Thomas Nagy, 2005-2016 (ita)
"""
Utilities and platform-specific fixes

View File

@ -1,3 +1,3 @@
#!/usr/bin/env python
# encoding: utf-8
# Thomas Nagy, 2005-2010 (ita)
# Thomas Nagy, 2005-2016 (ita)

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
# encoding: utf-8
# Thomas Nagy, 2010-2015 (ita)
# Thomas Nagy, 2010-2016 (ita)
import os