Buzzy
Buzzy

Reputation: 3677

Configuring SCons to use separate tools for code generation and assembly

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)

  1. How can I make SCons run the builder on all files and include those object files for linking?
  2. Is there a better way to accomplish what I am trying to do? I am just beginning to work with SCons.

Upvotes: 5

Views: 3614

Answers (1)

Andrew Walker
Andrew Walker

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

Related Questions