This file is indexed.

/usr/share/makepp/html/makepp_extending.html is in makepp 2.0.98.3-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<?xml version='1.0'?><!DOCTYPE html><html xmlns='http://www.w3.org/1999/xhtml'><head><link rel='stylesheet' href='makepp.css' type='text/css'/><title>Makepp Extending — How to extend makepp using Perl</title><link rel='next' href='makepp_functions.html'/><link rel='prev' href='makepp_compatibility.html'/><meta http-equiv='Content-Type' content='text/html; charset=utf-8'/><link rel='shortcut icon' type='image/png' href='url.png'/><link rel='top' href='http://makepp.sourceforge.net/'/><link rel='index' href='makepp_index.html'/><link rel='contents' href='index.html'/><link rel='help' href='http://sourceforge.net/projects/makepp/support'/><script src='makepp.js' type='text/javascript'></script><meta name='keywords' content='makepp, make++, Make, build tool, repository, cache, Perl, Make alternative, Make replacement, Make enhancement, Make improvement, Make substitute, dmake, gmake, GNU Make, nmake, pmake, easymake, imake, jmake, maketool, mmake, omake, ppmake, PVM gmake, shake, SMake, ant, maven, cook, jam, Cons, SCons, cc -M, gcc -MM, g++ -MM, makedepend, makedep, mkdep, CCache, Compilercache, cachecc1, Make::Cache, automake'/></head><body><div id='_head'><form action='http://www.google.com/search'><p><input type='hidden' name='as_sitesearch' value='makepp.sourceforge.net/2.1'/><input type='text' name='as_q'/><input type='submit' value='Go'/></p></form><a title='Makepp Homepage' href='http://makepp.sourceforge.net/'><img src='makepp.png' alt='Makepp'/></a><div><a href='http://makepp.sourceforge.net/'><img title='Makepp Homepage' id='_home' src='tabs.png' alt='Home'/></a><a href='makepp_faq.html'><img title='Frequently Asked Questions' id='_faq' src='tabs.png' alt='FAQ'/></a><a href='http://makepp.sourceforge.net/gallery/'><img title='Gallery' id='_gallery' src='tabs.png' alt='Gallery'/></a><a href='http://sourceforge.net/projects/makepp/files/2.1/snapshots/'><img title='Download' id='_download' src='tabs.png' alt='Download'/></a><a href='https://sourceforge.net/projects/makepp/'><img title='Makepp on SourceForge' id='_sourceforge' src='tabs.png' alt='SourceForge'/></a><a href='http://search.cpan.org/dist/makepp/'><img title='Makepp on CPAN' id='_cpan' src='tabs.png' alt='CPAN'/></a></div></div><ul><li id='_close'><script type='text/javascript'>r()</script><span title='Flip side' onclick='lr(this)'></span><span title='Collapse' onclick='roll(this)'></span><span title='Expand' onclick='roll(this,1)'>¤</span><span title='Close' onclick='nonav(this)'>×</span></li><li class='fold' onclick='fold(this)'>Overview<ul><li><a href='index.html'>Introduction</a></li><li><a href='makepp_tutorial.html'>Tutorial</a></li><li><a href='makepp_tutorial_compilation.html'>Compilation Tutorial</a></li><li><a href='makepp_release_notes.html'>Release Notes</a></li><li><a href='makepp_incompatibilities.html'>Incompatibilities</a></li><li><a href='makepp_speedup.html'>Speedup</a></li><li><a href='perl_performance.html'>Perl Performance</a></li></ul></li><li class='fold' onclick='fold(this)'>Q&amp;A<ul><li><a href='makepp_cookbook.html'>Cookbook</a></li><li><a href='makepp_faq.html'>FAQ</a></li></ul></li><li id='_act' class='unfold' onclick='fold(this)'><b>Features</b><ul><li><a href='makepp_build_algorithm.html'>Build Algorithm</a></li><li><a href='makepp_build_cache.html'>Build Cache</a></li><li><a href='makepp_build_check.html'>Build Check Methods</a></li><li><a href='makepp_builtin.html'>Builtin Rules</a></li><li><a href='makepp_builtins.html'>Builtin Commands</a></li><li><a href='makepp_compatibility.html'>Compatibility</a></li><li><b>Extending</b></li><li><a href='makepp_functions.html'>Functions</a></li><li><a href='makepp_repositories.html'>Repositories</a></li><li><a href='makepp_rules.html'>Rules</a></li><li><a href='makepp_sandboxes.html'>Sandboxes</a></li><li><a href='makepp_scanning.html'>Scanning</a></li><li><a href='makepp_signatures.html'>Signatures</a></li><li><a href='makepp_statements.html'>Statements</a></li><li><a href='makepp_variables.html'>Variables</a></li></ul></li><li class='fold' onclick='fold(this)'>Commands<ul><li><a href='makepp_command.html'>makepp,&nbsp; mpp</a></li><li><a href='makeppbuiltin.html'>makeppbuiltin,&nbsp; mppb</a></li><li><a href='makeppclean.html'>makeppclean,&nbsp; mppc</a></li><li><a href='makeppgraph.html'>makeppgraph,&nbsp; mppg</a></li><li><a href='makeppinfo.html'>makeppinfo,&nbsp; mppi</a></li><li><a href='makepplog.html'>makepplog,&nbsp; mppl</a></li><li><a href='makeppreplay.html'>makeppreplay,&nbsp; mppr</a></li></ul></li><li><a href='makepp_index.html'>Index</a></li></ul><div id='_main'><h1>Makepp Extending</h1><p><b>How to extend makepp using Perl</b></p><ul><li><a href="#general_notes_on_writing_perl_code_to_work_with_makepp">General notes on writing Perl code to work with makepp</a></li><li><a href="#adding_new_textual_functions">Adding new textual functions</a></li><li><a href="#putting_functions_into_a_perl_module">Putting functions into a Perl module</a></li><li><a href="#calling_external_perl_scripts">Calling external Perl scripts</a></li><li><a href="#writing_your_own_signature_methods">Writing your own signature methods</a></li><li><a href="#unfinished">Unfinished</a></li></ul><p>Makepp internally is flexible enough so that by writing a little bit of Perl code, you can add functions or do a number of other operations.</p><p></p><h2 id="general_notes_on_writing_perl_code_to_work_with_makepp">General notes on writing Perl code to work with makepp</h2><p>Each makefile lives in its own package. Thus definitions in one makefile do not affect definitions in another makefile. A common set of functions including all the standard textual manipulation functions is imported into the package when it is created.</p><p>Makefile variables are stored as Perl scalars in that package. (There are exceptions to this: automatic variables and the default value of variables like CC are actually implemented as functions with no arguments. Target specific vars, command line vars and environment vars are not seen this way.) Thus any Perl code you write has access to all makefile variables. Global variables are stored in the <tt>Mpp::global</tt> package. See <a href="makepp_variables.html#variables_and_perl">Makefile variables</a> for the details.</p><p>Each of the statements (<a href="makepp_statements.html#ifperl_perlcode">ifperl / ifmakeperl</a>, <a href="makepp_statements.html#perl_perlcode">perl / makeperl</a>, <a href="makepp_statements.html#sub">sub / makesub</a>), the functions (<a href="makepp_functions.html#perl_perlcode">perl / makeperl</a>, <a href="makepp_functions.html#map_words_perlcode">map / makemap</a>) and the rule action (<a href="makepp_rules.html#perl">perl / makeperl</a>) for writing Perl code directly in the makefile come in two flavours. The first is absolutely normal Perl, meaning you have to use the <tt>f_</tt> prefix as explained in the next section, if you want to call makepp functions. The second variant first passes the statement through Make-style variable expansion, meaning you have to double the <tt>$</tt>s you want Perl to see.</p><p>End handling is special because makepp's huge (depending on your build system) data structures would take several seconds to garbage collect with a normal exit. So we do a brute force exit. In the main process you can still have <tt>END</tt> blocks but if you have any global file handles they may not get flushed. But you should be using the modern lexical filehandles, which get closed properly when going out of scope.</p><p>In Perl code run directly as a rule action or via a command you define, it is the opposite. <tt>END</tt> blocks will not be run, but global filehandles get flushed for you. The <tt>DESTROY</tt> of global objects will never be run.</p><p></p><h2 id="adding_new_textual_functions">Adding new textual functions</h2><p>You can add a new function to makepp's repertoire by simply defining a Perl subroutine of the same name but with a prefix of <tt>f_</tt>. For example:</p><pre><b>sub</b> <i>f_myfunc</i> {
  my $argument = &amp;arg;      <span class='comment'># Name the argument.</span>
  my( undef, $mkfile, $mkfile_line ) = @_; <span class='comment'># Name the arguments.</span>
  ... do something here<b class="tall"> </b>
  return $return_value;<b class="tall"> </b>
}
<i>XYZ</i> := $(<i>myfunc</i> my func arguments)<b class="tall"> </b></pre><p>If your function takes no arguments, there is nothing to do. If your function takes one argument, as in the example above, use the simple accessor <tt>&amp;arg</tt> to obtain it. If you expect more arguments, you need the more complex accessor <a href="#args"><tt>args</tt></a> described below.</p><p>These accessors processes the same three parameters that should be passed to any <tt>f_</tt> function, namely the function arguments, the makefile object and a line descriptor for messages. Therefore you can use the efficient <tt>&amp;arg</tt> form in the first case.</p><p>The <tt>&amp;arg</tt> accessor takes care of the following for you: If the arguments were already expanded (e.g. to find the name of the function in <tt>$(<i>my</i>$(<i>function</i>) arg)</tt> the arg is passed as a string and just returned. If the argument still needs expansion, this is the usual case, it is instead a reference to a string. The <tt>&amp;arg</tt> accessor expands it for you, for which it needs the makefile object as its 2nd parameter.</p><p>If you expect more arguments, possibly in variable number, the job is performed by <a href="#args"><tt>args</tt></a>. This accessor takes the same 3 parameters as arg, plus additional parameters:</p><dl><dt id="args"><b>max: number of args (default 2): give ~0 (maxint) for endless</b></dt><dt><b>min: number of args (default 0 if max is ~0, else same as max)</b></dt><dt id="only_comma_don_t_eat_space_around_commas_usual_for_non_filename"><b>only_comma: don't eat space around commas, usual for non-filename</b></dt></dl><p>At most max, but at least min commas present before expansion are used to split the arguments. Some examples from makepp's builtin functions:</p><pre>my( $prefix, $text ) = args $_[0], $_[1], $_[2], 2, 2, 1; <span class='comment'># addprefix</span>
for my $cond ( args $_[0], undef, $_[2], ~0 ) ... <span class='comment'># and, or</span>
my @args= args $_[0], $_[1], $_[2], ~0, 1, 1; <span class='comment'># call</span>
my( $filters, $words ) = args $_[0], $_[1], $_[2]; <span class='comment'># filter</span></pre><p>The function should return a scalar string (not an array) which is then inserted into the text at that point.</p><p>If your function encounters an error, it should die using the usual Perl die statement. This will be trapped by makepp and an error message displaying the file name and the line number of the expression causing the error will be printed out.</p><p>There are essentially no limits on what the function can do; you can access the file, run shell commands, etc.</p><p>At present, expressions appearing in dependencies and in the rule actions are expanded once while expressions appearing in targets are expanded twice, so be careful if your function has side effects and is present in an expression for a target.</p><p>Note that the environment (in particular, the cwd) in which the function evaluates will not necessarily match the environment in which the rules from the Makefile in which the function was evaluated are executed. If this is a problem for you, then your function probably ought to look something like this:</p><pre><b>sub</b> <i>f_foo</i> {
  ...
  chdir $makefile-&gt;{CWD};
  ... etc.<b class="tall"> </b>
}</pre><p></p><h2 id="putting_functions_into_a_perl_module">Putting functions into a Perl module</h2><p>If you put functions into an include file, you will have one copy per Makeppfile which uses it. To avoid that, you can write them as a normal Perl module with an <tt>Exporter</tt> interface, and use that. This will load faster and save memory:</p><pre><b>perl </b>{ use mymodule }
<b>perl </b>{
    <em>use my</em>::module;         <span class='comment'># put : on a new line so this is not parsed as a rule</span>
}</pre><p>If you need any of the functions normally available in a Makefile (like the <tt>f_</tt> functions, <tt>arg</tt> or <a href="#args"><tt>args</tt></a>), you must put this line into your module:</p><pre>use Mpp::Subs;</pre><p>The drawback is that the module would be in a different package than a function directly appearing in a makefile. So you need to pass in everything as parameters, or construct names with Perl's <tt>caller</tt> function.</p><p></p><h2 id="calling_external_perl_scripts">Calling external Perl scripts</h2><p>If you call an external Perl script via <tt>system</tt>, or as a rule action, makepp will fork a new process (unless it's the last rule action) and fire off a brand new perl interpreter. There's nothing wrong with that, except that there's a more efficient way:</p><dl><dt id="command_arguments"><b>&amp;<i>command arguments...</i></b></dt><dd><p>This can be a rule action. It will call a function <i>command</i> with a <tt>c_</tt> prefix, and pass it the remaining (optionally quoted makepp style -- not exactly the same as Shell) arguments. If such a function cannot be found, this passes all strings to <a href="#run_script_arguments"><tt>run</tt></a>.</p><pre><b>sub</b> <i>c_mycmd</i> { my @args = @_; ... }
<em>$(<i><b>phony</b></i> callcmd)</em>:<b class="tall"> </b>
    &amp;mycmd 'arg with space' arg2 "arg3" <span class='comment'># calls c_mycmd</span>
<em>%.out</em>: %.in<b class="tall"> </b>
    &amp;myscript -o <em>$(<i><b>output</b></i>)</em> $(<i><b>input</b></i>) <span class='comment'># calls external myscript</span></pre><p>You can write your commands within the framework of the builtins, allowing you to use the same standard options as they have, and the I/O handling they give.</p><p>The block operator <tt>Mpp::Cmds::frame</tt> is followed by a single letter option list of the builtins (maximally <tt>qw(f i I o O r s)</tt>). Even if you specify your own option overriding one of these, you still give the single letter of the standard option.</p><p>Each own option is specified as <tt>[qw(n name), \$ref, arg, sub]</tt>. The first two elements are short and long name, followed by the variable reference and optionally by a boolean for whether to take an argument. Without an arg, the variable is incremented each time the option is given, else the option value is stored in it.</p><pre><b>sub</b> <i>c_my_ocmd</i> {             <span class='comment'># Typical output case</span>
  local @ARGV = @_;
  Mpp::Cmds::frame {
    ... print something here with @ARGV, with options already automatically removed<b class="tall"> </b>
  } 'f', qw(o O);<b class="tall"> </b>
}
<b>sub</b> <i>c_my_icmd</i> {             <span class='comment'># Typical input case with 2 options</span><b class="tall"> </b>
  local @ARGV = @_;
  my( $short, $long );
  Mpp::Cmds::frame {
    ... do something here with &lt;&gt;<b class="tall"> </b>
  } qw(i I r s),            <span class='comment'># s specifies only --separator, not -s</span><b class="tall"> </b>
    [qw(s short), \$short], <span class='comment'># No option arg -&gt; $short == 1</span>
    [qw(l long), \$long, 1, sub { warn "got arg $long"}];
}</pre><p>Here comes a simple command which upcases only the first character of each input record (equivalent to <tt><b>&amp;sed</b> '$$_ = &quot;\u\L$$_&quot;'</tt>):</p><pre><b>sub</b> <i>c_uc</i> {
  local @ARGV = @_;
  Mpp::Cmds::frame {
    print "\u\L$_" while &lt;&gt;;
  } 'f', qw(i I o O r s);
}</pre><p>Within the block handled by frame, you can have nested blocks for performing critical operations, like opening other files.</p><pre>Mpp::Cmds::perform { ... } 'message';</pre><p>This will output message with <a href="makeppclean.html#verbose"><tt><b>--</b>verbose</tt></a> (which every command accepts) iff the command is successfully run. But if the block evaluates as false, it dies with negated message.</p></dd><dt id="run_script_arguments"><b>run <i>script arguments...</i></b></dt><dd><p>This is a normal Perl function you can use in any Perl context within your makefile. It is similar to the multi-argument form of system, but it runs the Perl script within the current process. For makepp statements, the <a href="makepp_functions.html#perl_perlcode">perl</a> function or your own functions that is the process running makepp. But for a rule that is the subprocess performing it. The script gets parsed as many times as it gets called, but you can put the real work into a lib, as pod2html does. This lib can then get used in the top level, so that it's already present:</p><pre><b>perl </b>{ use mylib }          <span class='comment'># gets forked to all rules which needn't reparse it</span>
<em>%.out</em>: %.in<b class="tall"> </b>
    <b>makeperl </b>{ run qw'myscript -o <em>$(<i><b>output</b></i>)</em> $(<i><b>input</b></i>)' }</pre><p>If the script calls <tt>exit</tt>, closes standard file descriptors or relies on the system to clean up after it (open files, memory...), this can be a problem with <tt>run</tt>. If you call <tt>run</tt> within statements or the <a href="makepp_functions.html#perl_perlcode">perl</a> function, makepp can get disturbed or the cleanup only happens at the end of makepp.</p><p>If you have one the aforementioned problems, run the script externally, i.e. as from the command line instead. Within a rule cleanup is less of a problem, especially not as the last action of a rule, since the rule subprocess will exit afterwards anyway, except on Windows.</p></dd></dl><p></p><h2 id="writing_your_own_signature_methods">Writing your own signature methods</h2><p>Sometimes you want makepp to compute a signature method using a different technique. For example, suppose you have a binary that depends on a shared library. Ordinarily, if you change the shared library, you don't have to relink executables that depend on it because the linking is done at run time. (However, it is possible that relinking the executable might be necessary, which is why I did not make this the default.) What you want makepp to do is to have the same signature for the shared library even if it changes.</p><p>This can be accomplished in several ways. The easiest way is to create your own new signature method (let's call it &quot;shared_object&quot;). You would use this signature method only on rules that link binaries, like this:</p><pre><em>myprogram</em> : *.o lib1/lib1.so lib2/lib2.so
    : <b>signature</b> <em>shared_object</em>
    $(<i>CC</i>) $(<i><b>inputs</b></i>) -o <em>$(<i><b>output</b></i>)</em></pre><p>Now we have to create the signature method.</p><p>All signature methods must be their own class, and the class must contain a few special items (see Mpp/Signature.pm in the distribution for details). The class's name must be prefixed with <tt>Mpp::Signature::</tt>, so in this case our class should be called <tt>Mpp::Signature::shared_object</tt>. We have to create a file called <i class="file">shared_object.pm</i> and put it into a <i class="file">Mpp::Signature</i> directory somewhere in the Perl include path; the easiest place might be in the <i class="file">Mpp/Signature</i> directory in the makepp installation (e.g., <i class="file">/usr/local/share/makepp/Mpp/Signature</i> or wherever you installed it).</p><p>For precise details about what has to go in this class, you should look carefully through the file <i class="file">Mpp/Signature.pm</i> and probably also <i class="file">Mpp/Signature/exact_match.pm</i> in the makepp distribution. But in our case, all we want to do is to make a very small change to an existing signature mechanism; if the file is a shared library, we want to have a constant signature, whereas if the file is anything else, we want to rely on makepp's normal signature mechanism. The best way to do this is to inherit from <tt>Mpp::Signature::c_compilation_md5</tt>, which is the signature method that is usually chosen when makepp recognizes a link command.</p><p>So the file <i class="file">Mpp/Signature/shared_object.pm</i> might contain the following:</p><pre>use strict;
package Mpp::Signature::shared_object;
use Mpp::Signature::c_compilation_md5;
<em>our @ISA = qw(Mpp</em>::Signature::c_compilation_md5); <span class='comment'># Indicate inheritance.</span>
our $shared_object = bless \@ISA; <span class='comment'># A piece of magic that helps makepp find</span>
                            <span class='comment'># the subroutines for this method.  All</span>
                            <span class='comment'># signature methods must have one of these.</span>
                            <span class='comment'># The value is not used, just any object.</span>
<span class='comment'># Now here's the method that gets called when we need the signature of</span>
<span class='comment'># any target or dependency for which this signature method is active:</span>
<b>sub</b> <i>signature</i> {
  my ($self,                 <span class='comment'># This will be the same as $shared_object.</span>
      $finfo) = @_;          <span class='comment'># A special structure that contains everything</span>
                             <span class='comment'># makepp knows about this file.  See</span>
                             <span class='comment'># Mpp/File.pm for details.</span>
  if ($finfo-&gt;{NAME} =~ /\.s[oa]$/) { <span class='comment'># Does the file name end in .so or .sa?</span><b class="tall"> </b>
    return $finfo-&gt;file_exists ? 'exists' : '';
                             <span class='comment'># Always return the same signature if the file</span>
                             <span class='comment'># exists.  In this case, the signature is the</span>
                             <span class='comment'># string "exists".</span>
  }
  Mpp::Signature::c_compilation_md5::<b>signature</b>;<b class="tall"> </b>
                             <span class='comment'># If the file didn't end in .so or .sa,</span>
                             <span class='comment'># delegate to makepp's usual signature method.</span>
}</pre><p>This file is provided as an example in the makepp distribution, with some additional comments.</p><p>Incidentally, why don't we make this the default? Well, there are times when changing a shared library will require a relinking of your program. If you ever change either the symbols that a shared library defines, or the symbols that it depends on other libraries for, a relink may sometimes be necessary.</p><p>Suppose, for example, that the shared library invokes some subroutines that your program provides. E.g., suppose you change the shared library so it now calls an external subroutine <tt>xyz()</tt>. Unless you use the <a href="makepp_builtins.html#e"><tt><b>-</b>E</tt></a> or <tt><b>--</b>export-dynamic</tt> option to the linker (for GNU binutils; other linkers have different option names), the symbol <tt>xyz()</tt> may not be accessible to the run-time linker even if it exists in your program.</p><p>Even worse, suppose you defined <tt>xyz()</tt> in another library (call it <i class="file">libxyz</i>), like this:</p><pre><em>my_program</em>: main.o lib1/lib1.so xyz/libxyz.a</pre><p>Since <tt>libxyz</tt> is a <i class="file">.a</i> file and not a <i class="file">.so</i> file, then <tt>xyz()</tt> may not be pulled in correctly from <i class="file">libxyz.a</i> unless you relink your binary.</p><p>Mpp::Signature methods also control not only the string that is used to determine if a file has changed, but the algorithm that is used to compare the strings. For example, the signature method <a href="makepp_build_check.html#target_newer"><tt>target_newer</tt></a> in the makepp distribution merely requires that the targets be newer than the dependencies, whereas the signature method <a href="makepp_build_check.html#exact_match"><tt>exact_match</tt></a> (and everything that depends on it, such as <a href="makepp_signatures.html#md5"><tt>md5</tt></a> and <a href="makepp_signatures.html#c_compilation_md5"><tt>c_compilation_md5</tt></a>) requires that the file have the same signature as on the last build.</p><p>Here are some other kinds of signature methods that might be useful, to help you realize the possibilities. If general purpose enough, some of these may eventually be incorporated into makepp:</p><ul><li><p>A signature method for shared libraries that returns a checksum of all the exported symbols, and also all the symbols that it needs from other libraries. This solves the problem with the example above, and guarantees a correct link under all circumstances. An experimental attempt has been made to do this in the makepp distribution (see <i class="file">Mpp/Signature/shared_object.pm</i>), but it will only work with GNU binutils and ELF libraries at the moment.</p></li><li><p>A signature method that ignores a date stamp written into a file. E.g., if you generate a <i class="file">.c</i> file automatically using some program that insists on putting a string in like this:</p><pre>static char * date_stamp = "Generated automatically on 01 Apr 2004 by nobody";</pre><p>you could write a signature method that specifically ignores changes in date stamps. Thus if the date stamp is the only thing that has changed, makepp will not rebuild.</p></li><li><p>A signature method that computes the signatures the normal way, but ignores the architecture dependence when deciding whether to rebuild. This could be useful for truly architecture-independent files; currently if you build on one architecture, makepp will insist on rebuilding even architecture-independent files when you switch to a different architecture.</p></li><li><p>A signature method that knows how to ignore comments in latex files, as the <a href="makepp_signatures.html#c_compilation_md5"><tt>c_compilation_md5</tt></a> method knows how to ignore comments in C files.</p></li><li><p>A signature method for automatic documentation extraction that checksums only to the comments that a documentation extractor needs and ignores other changes to the source file.</p></li></ul><p></p><h2 id="unfinished">Unfinished</h2><p>This document is not finished yet. It should cover how to write your own scanners for include files and things like that.</p><hr/><address>Last modified: 2012-05-15</address></div><div id='_clear'/></body></html>