14.3. Top-Relative Path Names in Subsidiary SConscript Files

If you need to use a file from another directory, it's sometimes more convenient to specify the path to a file in another directory from the top-level SConstruct directory, even when you're using that file in a subsidiary SConscript file in a subdirectory. You can tell SCons to interpret a path name as relative to the top-level SConstruct directory, not the local directory of the SConscript file, by prepending a # (hash mark) in front of the path name:

env = Environment()
env.Program('prog', ['main.c', '#lib/foo1.c', 'foo2.c'])

In this example, the lib directory is directly underneath the top-level SConstruct directory. If the above SConscript file is in a subdirectory named src/prog, the output would look like:

% scons -Q
cc -o lib/foo1.o -c lib/foo1.c
cc -o src/prog/foo2.o -c src/prog/foo2.c
cc -o src/prog/main.o -c src/prog/main.c
cc -o src/prog/prog src/prog/main.o lib/foo1.o src/prog/foo2.o

(Notice that the lib/foo1.o object file is built in the same directory as its source file. See Chapter 15, Separating Source and Build Trees: Variant Directories, below, for information about how to build the object file in a different subdirectory.)

A couple of notes on top-relative paths:

  1. SCons doesn't care whether you add a slash after the #. Some people consider '#/lib/foo1.c' more readable than '#lib/foo1.c', but they're functionally equivalent.

  2. The top-relative syntax is only evaluated by SCons, the Python language itself does not understand about it. This becomes immediately obvious if you like to use print for debugging, or write a Python function that wants to evaluate a path. You can force SCons to evaluate a top-relative path by creating a Node object from it:

path = "#/include"

print("path =", path)
print("force-interpreted path =", Entry(path))

Which shows:

% scons -Q
path = #/include
force-interpreted path = include
scons: `.' is up to date.