Multi-File Build
Once we have multiple source files there are a number of choices on how to build.
Assume our setup is this:
$ tree
.
├── SConstruct
├── main.c
├── message.c
└── message.h
Where message.h
is:
#ifndef message_H
#define message_H
void print_message(const char * str);
#endif // message_H
and main.c
is now:
#include "message.h"
int main(void)
{
print_message("Hello from scons");
return 0;
}
If we rebuild now, we'd get the following error message:
$ scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
gcc -o main.o -c main.c
gcc -o main main.o
Undefined symbols for architecture x86_64:
"_print_message", referenced from:
_main in main.o
As the build system is not including message.c
Option-1 : Quick and Dirty
The easy fix is to use the Glob
pattern matching facility, e.g.
Program(source = Glob('*.c'))
This will include all files matching the pattern, i.e. all .c
files in current directory in this case.
The pattern matching uses standard Unix style matchers, e.g.
* matches everything
? matches any single character
[seq] matches any character in seq
[!seq] matches any char not in seq”
Option-2 : Explicit List
As Scons is Python based, we can utilise Python lists, e.g.
Program(source = ['main.c', 'message.c'])
or alternatively:
sources=['main.c', 'message.c']
Program(source = sources)
Setting the name of the Executable
By default, scons
will use the first filename in the list as the executable, e.g. if we change the SConstruct
to this:
sources = ['message.c','main.c']
Program(source = sources)
the an executable called message
would be generated.
We can override this behaviour by explicitly setting a target
name, e.g.
sources = ['message.c','main.c']
Program(target = 'hello', source = sources)
or more explicitly:
exe = 'hello'
sources = ['message.c','main.c']
Program(target = exe, source = sources)
Which Option is best?
PLACEHOLDER FOR PROs AND CONs