/scons-starter

project construction made easy (with SCons) starter tutorial

Primary LanguageC++

project construction made easy

In the following lines you find tips help you start with building C++ programs using SCons project construction tool under Linux.

SCons package can be installed with sudo apt install scons command

content

basics

SCons is super easy to start with you need to know only three thinks. The first one, scons command to start a building process (from project root directory), scons -c command for project clean-up and that SCons build file is called SConstruct. The most simplest SConstruct file can looks like this

Program('main.cpp')

Yes, that is all! I've told it is super easy. SCons will take main.cpp source file and create main executable from it. We are now ready to build something, go to basic/ directory and execute scons by

cd basic
scons

commands to see SCons in action. The main output should looks like this

./main 
done!

don't forget to test scons -c command to clean-up the sample directory

compiler settings

Let's say we want to force building against C++17 standard and also turn on all compiler warnings. To do that, we can adjust compiler options with Environment variable this way

cpp17 = Environment(CCFLAGS=['-std=c++17', '-Wall'])
cpp17.Program('main.cpp')

go to environment/ directory and run scons to build main executable to see SCons with modified environment in action

There is not only CCFLAGS construction variable there but many others like

  • CCFLAGS general options passed to the c and c++ compilers
  • CPPPATH the list of directories that the c preprocessor will search for include directories.
  • LIBS list of libraries that will be linked
  • LIBPATH the list of directories that will be searched for libraries (use # to indicate absolute path LIBPATH='#/libs')
  • CPPDEFINES c/c++ preprocessor definitions

full list of construction variables can be found there

tip: we don't need to remember all that construction variable names, there is a shortcut there we can use parse_flags argument this way Environment(parse_flags='-std=c++17 -Wall -g -O0')

advanced tip: building with clang instead of gcc can be done by setting CXX construction variable to CXX='clang++'

more source files

In some cases there are more source files there like in 3dmath sample (we have main.cpp and vectors.cpp source files there) we can use Python's list instead of single string in a Program() builder like this

Program(['main.cpp', 'vector.cpp'])

We can makes our lives even easier with Glob(PATTERN) helper function and build all cpp files in a directory with

Program('3dmath', Glob('*.cpp'))

'3dmath' is explicitly used there as a name for program executable, feel free to change it

tip: to speed up whole building process on multicore machines we can call SCons with -jN option like this scons -j4, where N represents number of parallel jobs

third party dependencies

Let's render a triangle with OpenGL ES2 and GLFW libraries, like in triangle sample. We need to create SConstruct with OpenGL ES2 and GLFW library dependencies to get our sample working.

In Linux there is almighty pkg-config there to help us with the task.

before we can continue we need to install GLFW, OpenGL ES2 libraries and pkg-config itself with sudo apt install libglfw3-dev libgles2 pkg-config command

Build environment can parse pkg-config output with ParseConfig() function this way

cpp17.ParseConfig('pkg-config --cflags --libs glfw3 glesv2')

tip: we can use pkg-config --list-all | grep -i LIBRARY command to search for GLFW and OpenGL ES2 libraries, under Ubuntu 20.04 LTS they are there as glfw3 and glesv2

Now the last think needed to be done is to tell GLFW library we want render with OpenGL ES2 (not OpenGL). It can be done with GLFW_INCLUDE_ES2 define so we need to change CPPDEFINES construction variable for our environment. Final SConstruct file will looks like this

cpp17 = Environment(
	CCFLAGS=['-std=c++17', '-Wall', '-O0', '-g'],
	CPPDEFINES=['GLFW_INCLUDE_ES2'])

cpp17.ParseConfig('pkg-config --cflags --libs glfw3 glesv2')

cpp17.Program('triangle.cpp')

We are done, go to triangle/ directory and run scons from konsole to see it is working.

see OGRE starter or cube rain repositories for more SCons samples

static library

It is a good practise to group domain specific code into a library like in a physics sample. I've moved sample physics engine from great Game Physics Cookbook into a phys/ directory and want to use it from my project as a static library. In SCons it is super easy to do that with StaticLibrary() builder and Glob() function, like this

cpp17 = Environment(
	CXX='clang++', CCFLAGS=['-std=c++17', '-Wall'])

cpp17.ParseConfig('pkg-config --cflags --libs glfw3 gl')

phys = cpp17.StaticLibrary('phys', Glob('phys/*.cpp'))

cpp17.Program('physics', ['main.cpp', phys])

We need to use clang there, because physics library use non-standard C++ language feature not supported by GCC. Install clang with sudo apt install clang command.

tip: there are also builders for shared libraries SharedLibrary() and object files Object()

install command

Sometimes it can be handy to provide install command so project can be automatically installed to proper destination without too much effort from user side. In SCons install process can be done with Install() builder and Alias() function this way

target_dir = '/opt/foo'
cpp.Install(target_dir, main)
cpp.Alias('install', target_dir)

see full SConstruct file version

Now we can type scons install to install main executable to /opt/foo directory.

tip: in case you don't have write access to /opt directory, use --install-sandbox option to prefix target directory like scons --install-sandbox=/home/adam install to install main executable to /home/adam/opt/foo instead of /opt/foo directory

Maybe, you are asking yourself whether uninstall is also possible? Yes, it is! We've got uninstall for free, we can type scons -c install which will uninstall main executable from /opt/foo directory.

Adam Hlavatovic