If you're used to build systems like Make
you've already figured out that the SConstruct
file
is the SCons equivalent of a Makefile
.
That is, the SConstruct
file is the input file
that SCons reads to control the build.
There is, however, an important difference between
an SConstruct
file and a Makefile
:
the SConstruct
file is actually a Python script.
If you're not already familiar with Python, don't worry.
This User's Guide will introduce you step-by-step
to the relatively small amount of Python you'll
need to know to be able to use SCons effectively.
And Python is very easy to learn.
One aspect of using Python as the
scripting language is that you can put comments
in your SConstruct
file using Python's commenting convention;
that is, everything between a '#' and the end of the line
will be ignored:
# Arrange to build the "hello" program. Program('hello.c') # "hello.c" is the source file.
You'll see throughout the remainder of this Guide that being able to use the power of a real scripting language can greatly simplify the solutions to complex requirements of real-world builds.
One important way in which the SConstruct
file is not exactly like a normal Python script,
and is more like a Makefile
,
is that the order in which
the SCons functions are called in
the SConstruct
file
does not
affect the order in which SCons
actually builds the programs and object files
you want it to build
[1].
In other words, when you call the Program
builder
(or any other builder method),
you're not telling SCons to build
the program at that moment.
Instead, you're telling SCons what you want accomplished,
and it's up to SCons to figure out how to do that, and to
take those steps if/when it's necessary.
We'll learn more about how
SCons decides when building or rebuilding a target
is necessary in Chapter 6, Dependencies, below.
SCons reflects this distinction between
calling a builder method like Program
and actually building the program
by printing the status messages that indicate
when it's "just reading" the SConstruct
file,
and when it's actually building the target files.
This is to make it clear when SCons is
executing the Python statements that make up the SConstruct
file,
and when SCons is actually executing the
commands or other actions to
build the necessary files.
Let's clarify this with an example.
Python has a print
function that
prints a string of characters to the screen.
If we put print
calls around
our calls to the Program
builder method:
print("Calling Program('hello.c')") Program('hello.c') print("Calling Program('goodbye.c')") Program('goodbye.c') print("Finished calling Program()")
Then when we execute SCons,
we see the output from calling the print
function in between the messages about
reading the SConscript
files,
indicating that is when the
Python statements are being executed:
% scons
scons: Reading SConscript files ...
Calling Program('hello.c')
Calling Program('goodbye.c')
Finished calling Program()
scons: done reading SConscript files.
scons: Building targets ...
cc -o goodbye.o -c goodbye.c
cc -o goodbye goodbye.o
cc -o hello.o -c hello.c
cc -o hello hello.o
scons: done building targets.
Notice that SCons built the goodbye
program first,
even though the "reading SConscript
" output
shows that we called Program('hello.c')
first in the SConstruct
file.
Notice also that SCons was able to infer a lot of information
from the two Program
calls. Because
hello.c
and goodbye.c
were recognized as C-language source files, it knew to build
the intermediate target files hello.o
and goodbye.o
and the final files hello
and goodbye
It was not necessary to program scons beyond just calling Program
.
[1] In programming parlance,
the SConstruct
file is
declarative,
meaning you tell SCons what you want done
and let it figure out the order in which to do it,
rather than strictly imperative,
where you specify explicitly the order in
which to do things.