mirror of
https://github.com/Relintai/scons_gd.git
synced 2025-03-12 18:38:59 +01:00
650 lines
17 KiB
XML
650 lines
17 KiB
XML
|
<?xml version='1.0'?>
|
||
|
<!DOCTYPE sconsdoc [
|
||
|
<!ENTITY % scons SYSTEM "../scons.mod">
|
||
|
%scons;
|
||
|
|
||
|
<!ENTITY % builders-mod SYSTEM "../generated/builders.mod">
|
||
|
%builders-mod;
|
||
|
<!ENTITY % functions-mod SYSTEM "../generated/functions.mod">
|
||
|
%functions-mod;
|
||
|
<!ENTITY % tools-mod SYSTEM "../generated/tools.mod">
|
||
|
%tools-mod;
|
||
|
<!ENTITY % variables-mod SYSTEM "../generated/variables.mod">
|
||
|
%variables-mod;
|
||
|
]>
|
||
|
|
||
|
<chapter id="chap-less-simple"
|
||
|
xmlns="http://www.scons.org/dbxsd/v1.0"
|
||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||
|
xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0 http://www.scons.org/dbxsd/v1.0/scons.xsd">
|
||
|
<title>Less Simple Things to Do With Builds</title>
|
||
|
|
||
|
<!--
|
||
|
|
||
|
__COPYRIGHT__
|
||
|
|
||
|
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.
|
||
|
|
||
|
-->
|
||
|
|
||
|
<para>
|
||
|
|
||
|
In this chapter,
|
||
|
you will see several examples of
|
||
|
very simple build configurations using &SCons;,
|
||
|
which will demonstrate how easy
|
||
|
it is to use &SCons; to
|
||
|
build programs from several different programming languages
|
||
|
on different types of systems.
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<section>
|
||
|
<title>Specifying the Name of the Target (Output) File</title>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
You've seen that when you call the &b-link-Program; builder method,
|
||
|
it builds the resulting program with the same
|
||
|
base name as the source file.
|
||
|
That is, the following call to build an
|
||
|
executable program from the &hello_c; source file
|
||
|
will build an executable program named &hello; on POSIX systems,
|
||
|
and an executable program named &hello_exe; on Windows systems:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<programlisting>
|
||
|
Program('hello.c')
|
||
|
</programlisting>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
If you want to build a program with
|
||
|
a different name than the base of the source file name,
|
||
|
you simply put the target file name
|
||
|
to the left of the source file name:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<scons_example name="lesssimple_target">
|
||
|
<file name="SConstruct" printme="1">
|
||
|
Program('new_hello', 'hello.c')
|
||
|
</file>
|
||
|
<file name="hello.c">
|
||
|
int main() { printf("Hello, world!\n"); }
|
||
|
</file>
|
||
|
</scons_example>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
(&SCons; requires the target file name first,
|
||
|
followed by the source file name,
|
||
|
so that the order mimics that of an
|
||
|
assignment statement in most programming languages,
|
||
|
including Python:
|
||
|
<literal>"target = source files"</literal>. For an
|
||
|
alternative way to supply this information, see
|
||
|
<xref linkend="keyword-args"></xref>).
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
Now &SCons; will build an executable program
|
||
|
named &new_hello; when run on a POSIX system:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<scons_output example="lesssimple_target" os="posix" suffix="1">
|
||
|
<scons_output_command>scons -Q</scons_output_command>
|
||
|
</scons_output>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
And &SCons; will build an executable program
|
||
|
named &new_hello_exe; when run on a Windows system:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<scons_output example="lesssimple_target" os="win32" suffix="2">
|
||
|
<scons_output_command>scons -Q</scons_output_command>
|
||
|
</scons_output>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
<section>
|
||
|
<title>Compiling Multiple Source Files</title>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
You've just seen how to configure &SCons;
|
||
|
to compile a program from a single source file.
|
||
|
It's more common, of course,
|
||
|
that you'll need to build a program from
|
||
|
many input source files, not just one.
|
||
|
To do this, you need to put the
|
||
|
source files in a Python list
|
||
|
(enclosed in square brackets),
|
||
|
like so:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<scons_example name="lesssimple_ex2">
|
||
|
<file name="SConstruct" printme="1">
|
||
|
Program(['prog.c', 'file1.c', 'file2.c'])
|
||
|
</file>
|
||
|
<file name="prog.c">
|
||
|
int main() { printf("prog.c\n"); }
|
||
|
</file>
|
||
|
<file name="file1.c">
|
||
|
void file1() { printf("file1.c\n"); }
|
||
|
</file>
|
||
|
<file name="file2.c">
|
||
|
void file2() { printf("file2.c\n"); }
|
||
|
</file>
|
||
|
</scons_example>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
A build of the above example would look like:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<scons_output example="lesssimple_ex2" suffix="1">
|
||
|
<scons_output_command>scons -Q</scons_output_command>
|
||
|
</scons_output>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
Notice that &SCons;
|
||
|
deduces the output program name
|
||
|
from the first source file specified
|
||
|
in the list--that is,
|
||
|
because the first source file was &prog_c;,
|
||
|
&SCons; will name the resulting program &prog;
|
||
|
(or &prog_exe; on a Windows system).
|
||
|
If you want to specify a different program name,
|
||
|
then (as we've seen in the previous section)
|
||
|
you slide the list of source files
|
||
|
over to the right
|
||
|
to make room for the output program file name.
|
||
|
(&SCons; puts the output file name to the left
|
||
|
of the source file names
|
||
|
so that the order mimics that of an
|
||
|
assignment statement: <literal>program = source files</literal>.)
|
||
|
This makes our example:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<scons_example name="lesssimple_ex3">
|
||
|
<file name="SConstruct" printme="1">
|
||
|
Program('program', ['prog.c', 'file1.c', 'file2.c'])
|
||
|
</file>
|
||
|
<file name="prog.c">
|
||
|
int main() { printf("prog.c\n"); }
|
||
|
</file>
|
||
|
<file name="file1.c">
|
||
|
void file1() { printf("file1.c\n"); }
|
||
|
</file>
|
||
|
<file name="file2.c">
|
||
|
void file2() { printf("file2.c\n"); }
|
||
|
</file>
|
||
|
</scons_example>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
On Linux, a build of this example would look like:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<scons_output example="lesssimple_ex3" os="posix" suffix="1">
|
||
|
<scons_output_command>scons -Q</scons_output_command>
|
||
|
</scons_output>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
Or on Windows:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<scons_output example="lesssimple_ex3" os="win32" suffix="2">
|
||
|
<scons_output_command>scons -Q</scons_output_command>
|
||
|
</scons_output>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
<section>
|
||
|
<title>Making a list of files with &Glob;</title>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
You can also use the &f-link-Glob; function to find all files matching a
|
||
|
certain template, using the standard shell pattern matching
|
||
|
characters <literal>*</literal> (to match everything),
|
||
|
<literal>?</literal> (to match a single character)
|
||
|
and <literal>[abc]</literal> to match any of
|
||
|
<literal>a</literal>, <literal>b</literal> or <literal>c</literal>.
|
||
|
<literal>[!abc]</literal> is also supported,
|
||
|
to match any character <emphasis>except</emphasis>
|
||
|
<literal>a</literal>, <literal>b</literal> or <literal>c</literal>.
|
||
|
This makes many multi-source-file builds quite easy:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<sconstruct>
|
||
|
Program('program', Glob('*.c'))
|
||
|
</sconstruct>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
&f-Glob; has powerful capabilities - it matches even if the
|
||
|
file does not exist, but &SCons; can determine that it would
|
||
|
exist after a build.
|
||
|
You will meet it again reading about
|
||
|
variant directories
|
||
|
(see <xref linkend="chap-separate"/>)
|
||
|
and repositories
|
||
|
(see <xref linkend="chap-repositories"/>).
|
||
|
|
||
|
</para>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
<section>
|
||
|
<title>Specifying Single Files Vs. Lists of Files</title>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
We've now shown you two ways to specify
|
||
|
the source for a program,
|
||
|
one with a list of files:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<sconstruct>
|
||
|
Program('hello', ['file1.c', 'file2.c'])
|
||
|
</sconstruct>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
And one with a single file:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<sconstruct>
|
||
|
Program('hello', 'hello.c')
|
||
|
</sconstruct>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
You could actually put a single file name in a list, too,
|
||
|
which you might prefer just for the sake of consistency:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<sconstruct>
|
||
|
Program('hello', ['hello.c'])
|
||
|
</sconstruct>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
&SCons; functions will accept a single file name in either form.
|
||
|
In fact, internally, &SCons; treats all input as lists of files,
|
||
|
but allows you to omit the square brackets
|
||
|
to cut down a little on the typing
|
||
|
when there's only a single file name.
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<important>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
Although &SCons; functions
|
||
|
are forgiving about whether or not you
|
||
|
use a string vs. a list for a single file name,
|
||
|
Python itself is more strict about
|
||
|
treating lists and strings differently.
|
||
|
So where &SCons; allows either
|
||
|
a string or list:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<sconstruct>
|
||
|
# The following two calls both work correctly:
|
||
|
Program('program1', 'program1.c')
|
||
|
Program('program2', ['program2.c'])
|
||
|
</sconstruct>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
Trying to do "Python things" that mix strings and
|
||
|
lists will cause errors or lead to incorrect results:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<sconstruct>
|
||
|
common_sources = ['file1.c', 'file2.c']
|
||
|
|
||
|
# THE FOLLOWING IS INCORRECT AND GENERATES A PYTHON ERROR
|
||
|
# BECAUSE IT TRIES TO ADD A STRING TO A LIST:
|
||
|
Program('program1', common_sources + 'program1.c')
|
||
|
|
||
|
# The following works correctly, because it's adding two
|
||
|
# lists together to make another list.
|
||
|
Program('program2', common_sources + ['program2.c'])
|
||
|
</sconstruct>
|
||
|
|
||
|
</important>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
<section>
|
||
|
<title>Making Lists of Files Easier to Read</title>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
One drawback to the use of a Python list
|
||
|
for source files is that
|
||
|
each file name must be enclosed in quotes
|
||
|
(either single quotes or double quotes).
|
||
|
This can get cumbersome and difficult to read
|
||
|
when the list of file names is long.
|
||
|
Fortunately, &SCons; and Python provide a number of ways
|
||
|
to make sure that
|
||
|
the &SConstruct; file stays easy to read.
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
To make long lists of file names
|
||
|
easier to deal with, &SCons; provides a
|
||
|
&Split; function
|
||
|
that takes a quoted list of file names,
|
||
|
with the names separated by spaces or other white-space characters,
|
||
|
and turns it into a list of separate file names.
|
||
|
Using the &Split; function turns the
|
||
|
previous example into:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<programlisting>
|
||
|
Program('program', Split('main.c file1.c file2.c'))
|
||
|
</programlisting>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
(If you're already familiar with Python,
|
||
|
you'll have realized that this is similar to the
|
||
|
<function>split()</function> method
|
||
|
in the Python standard <function>string</function> module.
|
||
|
Unlike the <function>split()</function> member function of strings,
|
||
|
however, the &Split; function
|
||
|
does not require a string as input
|
||
|
and will wrap up a single non-string object in a list,
|
||
|
or return its argument untouched if it's already a list.
|
||
|
This comes in handy as a way to make sure
|
||
|
arbitrary values can be passed to &SCons; functions
|
||
|
without having to check the type of the variable by hand.)
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
Putting the call to the &Split; function
|
||
|
inside the &b-Program; call
|
||
|
can also be a little unwieldy.
|
||
|
A more readable alternative is to
|
||
|
assign the output from the &Split; call
|
||
|
to a variable name,
|
||
|
and then use the variable when calling the
|
||
|
&b-Program; function:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<programlisting>
|
||
|
src_files = Split('main.c file1.c file2.c')
|
||
|
Program('program', src_files)
|
||
|
</programlisting>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
Lastly, the &Split; function
|
||
|
doesn't care how much white space separates
|
||
|
the file names in the quoted string.
|
||
|
This allows you to create lists of file
|
||
|
names that span multiple lines,
|
||
|
which often makes for easier editing:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<programlisting>
|
||
|
src_files = Split("""main.c
|
||
|
file1.c
|
||
|
file2.c""")
|
||
|
Program('program', src_files)
|
||
|
</programlisting>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
(Note in this example that we used
|
||
|
the Python "triple-quote" syntax,
|
||
|
which allows a string to contain
|
||
|
multiple lines.
|
||
|
The three quotes can be either
|
||
|
single or double quotes.)
|
||
|
|
||
|
</para>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
<section id="keyword-args">
|
||
|
<title>Keyword Arguments</title>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
&SCons; also allows you to identify
|
||
|
the output file and input source files
|
||
|
using Python keyword arguments
|
||
|
<parameter>target</parameter> and
|
||
|
<parameter>source</parameter>.
|
||
|
The Python syntax for this is:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<programlisting>
|
||
|
src_files = Split('main.c file1.c file2.c')
|
||
|
Program(target='program', source=src_files)
|
||
|
</programlisting>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
Because the keywords explicitly identify
|
||
|
what each argument is, the order does
|
||
|
not matter and you can reverse it if you prefer:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<programlisting>
|
||
|
src_files = Split('main.c file1.c file2.c')
|
||
|
Program(source=src_files, target='program')
|
||
|
</programlisting>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
Whether or not you choose to use keyword arguments
|
||
|
to identify the target and source files,
|
||
|
and the order in which you specify them
|
||
|
when using keywords,
|
||
|
are purely personal choices;
|
||
|
&SCons; functions the same regardless.
|
||
|
|
||
|
</para>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
<section>
|
||
|
<title>Compiling Multiple Programs</title>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
In order to compile multiple programs
|
||
|
within the same &SConstruct; file,
|
||
|
simply call the &Program; method
|
||
|
multiple times,
|
||
|
once for each program you need to build:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<scons_example name="lesssimple_ex4">
|
||
|
<file name="SConstruct" printme="1">
|
||
|
Program('foo.c')
|
||
|
Program('bar', ['bar1.c', 'bar2.c'])
|
||
|
</file>
|
||
|
<file name="foo.c">
|
||
|
int main() { printf("foo.c\n"); }
|
||
|
</file>
|
||
|
<file name="bar1.c">
|
||
|
int main() { printf("bar1.c\n"); }
|
||
|
</file>
|
||
|
<file name="bar2.c">
|
||
|
void bar2() { printf("bar2.c\n"); }
|
||
|
</file>
|
||
|
</scons_example>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
&SCons; would then build the programs as follows:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<scons_output example="lesssimple_ex4" suffix="1">
|
||
|
<scons_output_command>scons -Q</scons_output_command>
|
||
|
</scons_output>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
Notice that &SCons; does not necessarily build the
|
||
|
programs in the same order in which you specify
|
||
|
them in the &SConstruct; file.
|
||
|
&SCons; does, however, recognize that
|
||
|
the individual object files must be built
|
||
|
before the resulting program can be built.
|
||
|
We'll discuss this in greater detail in
|
||
|
the "Dependencies" section, below.
|
||
|
|
||
|
</para>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
<section>
|
||
|
<title>Sharing Source Files Between Multiple Programs</title>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
It's common to re-use code by sharing source files
|
||
|
between multiple programs.
|
||
|
One way to do this is to create a library
|
||
|
from the common source files,
|
||
|
which can then be linked into resulting programs.
|
||
|
(Creating libraries is discussed in
|
||
|
<xref linkend="chap-libraries"></xref>, below.)
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
A more straightforward, but perhaps less convenient,
|
||
|
way to share source files between multiple programs
|
||
|
is simply to include the common files
|
||
|
in the lists of source files for each program:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<scons_example name="lesssimple_ex5">
|
||
|
<file name="SConstruct" printme="1">
|
||
|
Program(Split('foo.c common1.c common2.c'))
|
||
|
Program('bar', Split('bar1.c bar2.c common1.c common2.c'))
|
||
|
</file>
|
||
|
<file name="foo.c">
|
||
|
int main() { printf("foo.c\n"); }
|
||
|
</file>
|
||
|
<file name="bar1.c">
|
||
|
int main() { printf("bar1.c\n"); }
|
||
|
</file>
|
||
|
<file name="bar2.c">
|
||
|
int bar2() { printf("bar2.c\n"); }
|
||
|
</file>
|
||
|
<file name="common1.c">
|
||
|
void common1() { printf("common1.c\n"); }
|
||
|
</file>
|
||
|
<file name="common2.c">
|
||
|
void common22() { printf("common2.c\n"); }
|
||
|
</file>
|
||
|
</scons_example>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
&SCons; recognizes that the object files for
|
||
|
the &common1_c; and &common2_c; source files
|
||
|
each need to be built only once,
|
||
|
even though the resulting object files are
|
||
|
each linked in to both of the resulting executable programs:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<scons_output example="lesssimple_ex5" suffix="1">
|
||
|
<scons_output_command>scons -Q</scons_output_command>
|
||
|
</scons_output>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
If two or more programs
|
||
|
share a lot of common source files,
|
||
|
repeating the common files in the list for each program
|
||
|
can be a maintenance problem when you need to change the
|
||
|
list of common files.
|
||
|
You can simplify this by creating a separate Python list
|
||
|
to hold the common file names,
|
||
|
and concatenating it with other lists
|
||
|
using the Python + operator:
|
||
|
|
||
|
</para>
|
||
|
|
||
|
<programlisting>
|
||
|
common = ['common1.c', 'common2.c']
|
||
|
foo_files = ['foo.c'] + common
|
||
|
bar_files = ['bar1.c', 'bar2.c'] + common
|
||
|
Program('foo', foo_files)
|
||
|
Program('bar', bar_files)
|
||
|
</programlisting>
|
||
|
|
||
|
<para>
|
||
|
|
||
|
This is functionally equivalent to the previous example.
|
||
|
|
||
|
</para>
|
||
|
|
||
|
</section>
|
||
|
|
||
|
</chapter>
|