summaryrefslogtreecommitdiff
path: root/doc/user/scanners.in
diff options
context:
space:
mode:
Diffstat (limited to 'doc/user/scanners.in')
-rw-r--r--doc/user/scanners.in392
1 files changed, 0 insertions, 392 deletions
diff --git a/doc/user/scanners.in b/doc/user/scanners.in
deleted file mode 100644
index 9237fb3..0000000
--- a/doc/user/scanners.in
+++ /dev/null
@@ -1,392 +0,0 @@
-<!--
-
- Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 The SCons Foundation
-
- Permission is hereby granted, free of charge, to any person obtaining
- a copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sublicense, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
-
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
-
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
- KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
--->
-
-<!--
-
-=head1 Using and writing dependency scanners
-
-QuickScan allows simple target-independent scanners to be set up for
-source files. Only one QuickScan scanner may be associated with any given
-source file and environment, although the same scanner may (and should)
-be used for multiple files of a given type.
-
-A QuickScan scanner is only ever invoked once for a given source file,
-and it is only invoked if the file is used by some target in the tree
-(i.e., there is a dependency on the source file).
-
-QuickScan is invoked as follows:
-
- QuickScan CONSENV CODEREF, FILENAME [, PATH]
-
-The subroutine referenced by CODEREF is expected to return a list of
-filenames included directly by FILE. These filenames will, in turn, be
-scanned. The optional PATH argument supplies a lookup path for finding
-FILENAME and/or files returned by the user-supplied subroutine. The PATH
-may be a reference to an array of lookup-directory names, or a string of
-names separated by the system's separator character (':' on UNIX systems,
-';' on Windows NT).
-
-The subroutine is called once for each line in the file, with $_ set to the
-current line. If the subroutine needs to look at additional lines, or, for
-that matter, the entire file, then it may read them itself, from the
-filehandle SCAN. It may also terminate the loop, if it knows that no further
-include information is available, by closing the filehandle.
-
-Whether or not a lookup path is provided, QuickScan first tries to lookup
-the file relative to the current directory (for the top-level file
-supplied directly to QuickScan), or from the directory containing the
-file which referenced the file. This is not very general, but seems good
-enough, especially if you have the luxury of writing your own utilities
-and can control the use of the search path in a standard way.
-
-Here's a real example, taken from a F<Construct> file here:
-
- sub cons::SMFgen {
- my($env, @tables) = @_;
- foreach $t (@tables) {
- $env->QuickScan(sub { /\b\S*?\.smf\b/g }, "$t.smf",
- $env->{SMF_INCLUDE_PATH});
- $env->Command(["$t.smdb.cc","$t.smdb.h","$t.snmp.cc",
- "$t.ami.cc", "$t.http.cc"], "$t.smf",
- q(smfgen %( %SMF_INCLUDE_OPT %) %<));
- }
- }
-
-The subroutine above finds all names of the form <name>.smf in the
-file. It will return the names even if they're found within comments,
-but that's OK (the mechanism is forgiving of extra files; they're just
-ignored on the assumption that the missing file will be noticed when
-the program, in this example, smfgen, is actually invoked).
-
-[NOTE that the form C<$env-E<gt>QuickScan ...> and C<$env-E<gt>Command
-...> should not be necessary, but, for some reason, is required
-for this particular invocation. This appears to be a bug in Perl or
-a misunderstanding on my part; this invocation style does not always
-appear to be necessary.]
-
-Here is another way to build the same scanner. This one uses an
-explicit code reference, and also (unnecessarily, in this case) reads
-the whole file itself:
-
- sub myscan {
- my(@includes);
- do {
- push(@includes, /\b\S*?\.smf\b/g);
- } while <SCAN>;
- @includes
- }
-
-Note that the order of the loop is reversed, with the loop test at the
-end. This is because the first line is already read for you. This scanner
-can be attached to a source file by:
-
- QuickScan $env \&myscan, "$_.smf";
-
-This final example, which scans a different type of input file, takes
-over the file scanning rather than being called for each input line:
-
- $env->QuickScan(
- sub { my(@includes) = ();
- do {
- push(@includes, $3)
- if /^(#include|import)\s+(\")(.+)(\")/ && $3
- } while <SCAN>;
- @includes
- },
- "$idlFileName",
- "$env->{CPPPATH};$BUILD/ActiveContext/ACSCLientInterfaces"
- );
-
--->
-
- <para>
-
- &SCons; has built-in scanners that know how to look in
- C, Fortran and IDL source files for information about
- other files that targets built from those files depend on--for example,
- in the case of files that use the C preprocessor,
- the <filename>.h</filename> files that are specified
- using <literal>#include</literal> lines in the source.
- You can use the same mechanisms that &SCons; uses to create
- its built-in scanners to write scanners of your own for file types
- that &SCons; does not know how to scan "out of the box."
-
- </para>
-
- <section>
- <title>A Simple Scanner Example</title>
-
- <para>
-
- Suppose, for example, that we want to create a simple scanner
- for <filename>.foo</filename> files.
- A <filename>.foo</filename> file contains some text that
- will be processed,
- and can include other files on lines that begin
- with <literal>include</literal>
- followed by a file name:
-
- </para>
-
- <programlisting>
- include filename.foo
- </programlisting>
-
- <para>
-
- Scanning a file will be handled by a Python function
- that you must supply.
- Here is a function that will use the Python
- <filename>re</filename> module
- to scan for the <literal>include</literal> lines in our example:
-
- </para>
-
- <programlisting>
- import re
-
- include_re = re.compile(r'^include\s+(\S+)$', re.M)
-
- def kfile_scan(node, env, path, arg):
- contents = node.get_text_contents()
- return env.File(include_re.findall(contents))
- </programlisting>
-
- <para>
-
- It is important to note that you
- have to return a list of File nodes from the scanner function, simple
- strings for the file names won't do. As in the examples we are showing here,
- you can use the &File;
- function of your current Environment in order to create nodes on the fly from
- a sequence of file names with relative paths.
-
- </para>
-
- <para>
-
- The scanner function must
- accept the four specified arguments
- and return a list of implicit dependencies.
- Presumably, these would be dependencies found
- from examining the contents of the file,
- although the function can perform any
- manipulation at all to generate the list of
- dependencies.
-
- </para>
-
- <variablelist>
-
- <varlistentry>
- <term>node</term>
-
- <listitem>
- <para>
-
- An &SCons; node object representing the file being scanned.
- The path name to the file can be
- used by converting the node to a string
- using the <literal>str()</literal> function,
- or an internal &SCons; <literal>get_text_contents()</literal>
- object method can be used to fetch the contents.
-
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>env</term>
-
- <listitem>
- <para>
-
- The construction environment in effect for this scan.
- The scanner function may choose to use construction
- variables from this environment to affect its behavior.
-
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>path</term>
-
- <listitem>
- <para>
-
- A list of directories that form the search path for included files
- for this scanner.
- This is how &SCons; handles the &cv-link-CPPPATH; and &cv-link-LIBPATH;
- variables.
-
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>arg</term>
-
- <listitem>
- <para>
-
- An optional argument that you can choose to
- have passed to this scanner function by
- various scanner instances.
-
- </para>
- </listitem>
- </varlistentry>
-
- </variablelist>
-
- <para>
-
- A Scanner object is created using the &Scanner; function,
- which typically takes an <literal>skeys</literal> argument
- to associate the type of file suffix with this scanner.
- The Scanner object must then be associated with the
- &cv-link-SCANNERS; construction variable of a construction environment,
- typically by using the &Append; method:
-
- </para>
-
- <programlisting>
- kscan = Scanner(function = kfile_scan,
- skeys = ['.k'])
- env.Append(SCANNERS = kscan)
- </programlisting>
-
- <para>
-
- When we put it all together, it looks like:
-
- </para>
-
- <scons_example name="scan">
- <file name="SConstruct" printme="1">
- import re
-
- include_re = re.compile(r'^include\s+(\S+)$', re.M)
-
- def kfile_scan(node, env, path):
- contents = node.get_text_contents()
- includes = include_re.findall(contents)
- return env.File(includes)
-
- kscan = Scanner(function = kfile_scan,
- skeys = ['.k'])
-
- env = Environment(ENV = {'PATH' : '__ROOT__/usr/local/bin'})
- env.Append(SCANNERS = kscan)
-
- env.Command('foo', 'foo.k', 'kprocess &lt; $SOURCES &gt; $TARGET')
- </file>
- <file name="foo.k">
- include other_file
- </file>
- <file name="other_file">
- other_file
- </file>
- <directory name="__ROOT__/usr"></directory>
- <directory name="__ROOT__/usr/local"></directory>
- <directory name="__ROOT__/usr/local/bin"></directory>
- <file name="__ROOT_/usr/local/bin/kprocess" chmod="755">
- cat
- </file>
- </scons_example>
-
- <!--
-
- <para>
-
- Now if we run &scons;
- and then re-run it after changing the contents of
- <filename>other_file</filename>,
- the <filename>foo</filename>
- target file will be automatically rebuilt:
-
- </para>
-
- <scons_output example="scan">
- <scons_output_command>scons -Q</scons_output_command>
- <scons_output_command output=" [CHANGE THE CONTENTS OF other_file]">edit other_file</scons_output_command>
- <scons_output_command>scons -Q</scons_output_command>
- <scons_output_command>scons -Q</scons_output_command>
- </scons_output>
-
- -->
-
- </section>
-
- <section>
- <title>Adding a search path to a scanner: &FindPathDirs;</title>
-
- <para>
-
- Many scanners need to search for included files or dependencies
- using a path variable; this is how &cv-link-CPPPATH; and
- &cv-link-LIBPATH; work. The path to search is passed to your
- scanner as the <literal>path</literal> argument. Path variables
- may be lists of nodes, semicolon-separated strings, or even
- contain SCons variables which need to be expanded. Fortunately,
- &SCons; provides the &FindPathDirs; function which itself returns
- a function to expand a given path (given as a SCons construction
- variable name) to a list of paths at the time the scanner is
- called. Deferring evaluation until that point allows, for
- instance, the path to contain $TARGET references which differ for
- each file scanned.
-
- </para>
-
- <para>
-
- Using &FindPathDirs; is quite easy. Continuing the above example,
- using KPATH as the construction variable with the search path
- (analogous to &cv-link-CPPPATH;), we just modify the &Scanner;
- constructor call to include a path keyword arg:
-
- </para>
-
- <scons_example name="findpathdirs">
- <file name="SConstruct" printme="1">
- kscan = Scanner(function = kfile_scan,
- skeys = ['.k'],
- path=FindPathDirs('KPATH'))
- </file>
- </scons_example>
-
- <para>
-
- FindPathDirs returns a callable object that, when called, will
- essentially expand the elements in env['KPATH'] and tell the
- scanner to search in those dirs. It will also properly add
- related repository and variant dirs to the search list. As a side
- note, the returned method stores the path in an efficient way so
- lookups are fast even when variable substitutions may be needed.
- This is important since many files get scanned in a typical build.
-
- </para>
- </section>