summaryrefslogtreecommitdiffstats
path: root/doc/user/scanners.sgml
diff options
context:
space:
mode:
Diffstat (limited to 'doc/user/scanners.sgml')
-rw-r--r--doc/user/scanners.sgml196
1 files changed, 187 insertions, 9 deletions
diff --git a/doc/user/scanners.sgml b/doc/user/scanners.sgml
index 76b2a1a..23cd044 100644
--- a/doc/user/scanners.sgml
+++ b/doc/user/scanners.sgml
@@ -121,19 +121,197 @@ over the file scanning rather than being called for each input line:
-->
- <para>
+ <para>
- XXX
+ &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>
- </para>
+ <section>
+ <title>A Simple Scanner Example</title>
- <section>
- <title>XXX</title>
+ <para>
- <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:
- XXX
+ </para>
- </para>
+ <programlisting>
+ include filename.foo
+ </programlisting>
- </section>
+ <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_contents()
+ return include_re.findall(contents)
+ </programlisting>
+
+ <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_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 &CPPPATH; and &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
+ &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>
+
+ <programlisting>
+ import re
+
+ include_re = re.compile(r'^include\\s+(\\S+)$', re.M)
+
+ def kfile_scan(node, env, path):
+ contents = node.get_contents()
+ includes = include_re.findall(contents)
+ return includes
+
+ kscan = Scanner(function = kfile_scan,
+ skeys = ['.k'])
+
+ env = Environment(ENV = {'PATH' : '/usr/local/bin'})
+ env.Append(SCANNERS = kscan)
+
+ env.Command('foo', 'foo.k', 'kprocess < $SOURCES > $TARGET')
+ </programlisting>
+
+ <!--
+
+ <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">
+ <command>scons -Q</command>
+ <command output=" [CHANGE THE CONTENTS OF other_file]">edit other_file</command>
+ <command>scons -Q</command>
+ <command>scons -Q</command>
+ </scons_output>
+
+ -->
+
+ </section>