Reputation: 3677
I am trying to prepare a build system using SCons. I want to use clang
for the code generation phase and a custom compiler toolchain for everything else.
By default, the SCons configuration does not have an explicit step in which the assembly (.s)
files are generated.
In order to get around this, I created my own Builder
which emits assembly files.
code_generator = Builder(action = '$CC -$LOTS_OF_FLAGS -S $SOURCE -o $TARGET', suffix = '.s')
env.Append(BUILDERS = {'CodeGenerator':code_generator})
I then use this Builder
on my source files and pass the resulting NodeList
to the Program
.
for file in Glob('*.c'):
sources += env.CodeGenerator(file)
env.Program('say_hello', sources)
This works well when I do not modify any variables. I get an executable using gcc
.
However, when I try to replace the appropriate variables so that SCons uses the custom toolchain (using env.Replace(CC='clang')...
), only one assembly file is generated. My custom Builder
is not called on any other file and SCons tries to link with only one object file (which obviously fails)
Upvotes: 5
Views: 3614
Reputation: 42480
There are a large number of keyword arguments for the Builder
class that are documented on the SCons man page, that aren't mentioned in the user manual. This is one of the weak points in the documentation for SCons, and has been for some time.
In this case, I believe you are looking for the single_source
keyword argument which:
Specifies that this builder expects exactly one source file per call. Giving more than one source file without target files results in implicitely calling the builder multiple times (once for each source given).
Looking at the source for Builder
single_source needs to evaluate to True (or an equivalent). So your code can be rewritten with one very minor modification.
env = Environment()
code_generator = Builder(action = '$CC $CCFLAGS -S $SOURCE -o $TARGET',
single_source = 1,
suffix = '.s')
env.Replace(CC= 'clang')
env.Append(BUILDERS = {'CodeGenerator' : code_generator})
sources = env.CodeGenerator(file)
env.Program('say_hello', sources)
Which for a directory with the files: foo.c and bar.c produces the output:
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
clang -S bar.c -o bar.s
as -o bar.o bar.s
clang -S foo.c -o foo.s
as -o foo.o foo.s
clang -o say_hello bar.o foo.o
scons: done building targets.
Upvotes: 3