diff --git a/waflib/ConfigSet.py b/waflib/ConfigSet.py index 79775d9b..d0ef307f 100644 --- a/waflib/ConfigSet.py +++ b/waflib/ConfigSet.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # encoding: utf-8 -# Thomas Nagy, 2005-2010 (ita) +# Thomas Nagy, 2005-2016 (ita) """ diff --git a/waflib/Configure.py b/waflib/Configure.py index aefdaf16..4d35733a 100644 --- a/waflib/Configure.py +++ b/waflib/Configure.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # encoding: utf-8 -# Thomas Nagy, 2005-2010 (ita) +# Thomas Nagy, 2005-2016 (ita) """ Configuration system diff --git a/waflib/Errors.py b/waflib/Errors.py index e5ffe44a..b057d19b 100644 --- a/waflib/Errors.py +++ b/waflib/Errors.py @@ -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 diff --git a/waflib/Node.py b/waflib/Node.py index 3d031f8a..eba07551 100644 --- a/waflib/Node.py +++ b/waflib/Node.py @@ -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 diff --git a/waflib/Options.py b/waflib/Options.py index 54971ac2..c7f1f6d0 100644 --- a/waflib/Options.py +++ b/waflib/Options.py @@ -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 diff --git a/waflib/Runner.py b/waflib/Runner.py index 24dfad1a..82083e1d 100644 --- a/waflib/Runner.py +++ b/waflib/Runner.py @@ -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: diff --git a/waflib/Scripting.py b/waflib/Scripting.py index d5806880..a71fdcc0 100644 --- a/waflib/Scripting.py +++ b/waflib/Scripting.py @@ -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) diff --git a/waflib/Task.py b/waflib/Task.py index 5547094d..270680ea 100644 --- a/waflib/Task.py +++ b/waflib/Task.py @@ -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. diff --git a/waflib/TaskGen.py b/waflib/TaskGen.py index c38dda98..7dda4010 100644 --- a/waflib/TaskGen.py +++ b/waflib/TaskGen.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # encoding: utf-8 -# Thomas Nagy, 2005-2010 (ita) +# Thomas Nagy, 2005-2016 (ita) """ Task generators diff --git a/waflib/Tools/ifort.py b/waflib/Tools/ifort.py index 35a87c7d..83436041 100644 --- a/waflib/Tools/ifort.py +++ b/waflib/Tools/ifort.py @@ -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 diff --git a/waflib/Utils.py b/waflib/Utils.py index a0b02ea8..6676a411 100644 --- a/waflib/Utils.py +++ b/waflib/Utils.py @@ -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 diff --git a/waflib/__init__.py b/waflib/__init__.py index c8a3c349..be4a22a6 100644 --- a/waflib/__init__.py +++ b/waflib/__init__.py @@ -1,3 +1,3 @@ #!/usr/bin/env python # encoding: utf-8 -# Thomas Nagy, 2005-2010 (ita) +# Thomas Nagy, 2005-2016 (ita) diff --git a/waflib/fixpy2.py b/waflib/fixpy2.py index befc1be4..eb778de4 100644 --- a/waflib/fixpy2.py +++ b/waflib/fixpy2.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # encoding: utf-8 -# Thomas Nagy, 2010-2015 (ita) +# Thomas Nagy, 2010-2016 (ita) import os