Saturday, September 4, 2010


This is my log of start using SCons, you don't need to read this if you are familiar with SCons already. Most of my knowledge comes from SCons User Guide, and many of examples shown here were taken from the guide.

I looked for a build tool (like make) for my project. Like everybody else in the world, I'm sick of traditional make and needed a more elegant one.OMake's concurrent build (-P switch) attracted me a lot but it seemed to need some time to use Omake with emacs. Scons is a build tool (like make) fully utilizes Python, and there is no need to code in OCaml (omake) (*).

Once you have installed scons (if you use macport to install, you also need py25-hashlib to be installed), the first step of using Scons is to write a SConstruct file (Makefile equivalent), which is actually a Python script (so you can write a Makefile equivalent in Python).
If you just have two files hello.cpp which uses hello.h, a simple SConstruct file is


to build, you just type

Scons automatically looks at the source code hello.cpp and it is dependent on hello.h, so whenever hello.h changes, scons knows it needs to rebuild hello.

SCons User Guide is very well written and easy to read document but it is targeted for non-Python programmers and a little bit verbose, so I'll just write down the most important parts (for me) of the guide here. It doesn't cover throughout hte guide, I only read the first several chapters, up to 7.2.1 and I felt I can already use Scons to some extent.

-Program(['foo.cpp', 'bar.cpp']) if there are two sources.

-You can write Program('program', Glob('*.c')).

-SharedLibrary('foo', ['f1.c', 'f2.c']) and StaticLibrary('foo', ['f1.c', 'f2.c']) for shared and static library.

-Program('prog.c', LIBS=['foo', 'bar'], LIBPATH='.')

-Program('hello.c', CPPPATH = ['include', '/home/project/inc']) for -Iinclude -I/home/project/inc

-Program('prog.c', LIBS = 'm', LIBPATH = ['/usr/lib', '/usr/local/lib']) for -L/usr/lib -L/usr/local/lib -lm

-You can write SConstruct script like,
     hello_list = Object('hello.c', CCFLAGS='-DHELLO')
    goodbye_list = Object('goodbye.c', CCFLAGS='-DGOODBYE')
    Program(hello_list + goodbye_list)
Object means "Object file" (i.e. *.o file). Not Python object, nor any other object.

-Explict dependency.
      hello = Program('hello.c')
     Depends(hello, 'other_file')
The following scripts are also accepted.
Depends('hello', 'ho.cpp')

-Construction Environment
env = Environment(CC = 'gcc', CCFLAGS = '-O2')
To make it default settings (so that you can write Program('foo.c') instead of env.Program('foo.c')),
DefaultEnvironment(CC = 'gcc')

- SConscript(['subdirectory/SConscript']) for hierarchical build,

- Program(['foo.cpp', 'bar.cpp']) makes build target foo (looks scons gets the name from the first item in the list, not where the main function exists). Default(Program(['foo.cpp', 'bar.cpp'])) to set it as the default target.

(*) OMake official site says "There is no need to code in Perl (cons), or Python (scons)." ;)

No comments: