Reputation: 1237
I am attempting to build a modular system using scons to compile multiple shared libraries, some of which depend on the others. While I can get this to compile with a few different work-arounds, each has some disadvantages, as described in the Attempted Solutions section.
.
├── SConstruct
└── src
├── libA
│ ├── a.cc
│ ├── a.hh
│ └── SConscript
├── libB
│ ├── b.cc
│ ├── b.hh
│ └── SConscript
└── SConscript
Here, b.cc
includes a.hh
, which is the dependency between the two libraries.
The contents of each of the files are shown below.
# In SConstruct
VariantDir('build', 'src', duplicate=False)
SConscript('build/SConscript')
# In src/SConscript
env = Environment()
SConscript(['libA/SConscript', 'libB/SConscript'],
exports='env')
# In src/libA/SConscript
Import('env')
env.Append(CPPPATH=['.'])
env.SharedLibrary('a.cc')
# In src/libB/SConscript
Import('env')
env.Append(CPPPATH=['.'])
env.SharedLibrary('b.cc')
Here, I run into an issue. When I run scons, I have the following result.
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o build/libA/a.os -c -fPIC -Ibuild/libA -Isrc/libA -Ibuild/libA -Isrc/libA src/libA/a.cc
g++ -o build/libA/liba.so -shared build/libA/a.os
g++ -o build/libB/b.os -c -fPIC -Ibuild/libB -Isrc/libB -Ibuild/libB -Isrc/libB src/libB/b.cc
src/libB/b.cc:3:16: fatal error: a.hh: No such file or directory
#include "a.hh"
^
compilation terminated.
scons: *** [build/libB/b.os] Error 1
scons: building terminated because of errors.
I know from this older question that the duplication of -Ibuild/libA
and -Isrc/libA
makes sense, and is intended. However, -Isrc/libA
is passed twice when compiling a.cc
, and not at all when compiling b.cc
.
This seems to be caused by passing a string into CPPPATH
, rather than a Dir()
node. The string is then expanded with the path to the current SConscript later, rather than expanding with the current SConscript. To avoid this, I modified CPPPATH=['.']
to CPPPATH=[Dir('.')]
in src/libA/SConscript
and src/libB/SConscript
. This does not work, because then only build/libA
is included in the CPPPATH, not src/libA
, as shown below.
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o build/libA/a.os -c -fPIC -Ibuild/libA -Ibuild/libB src/libA/a.cc
g++ -o build/libA/liba.so -shared build/libA/a.os
g++ -o build/libB/b.os -c -fPIC -Ibuild/libA -Ibuild/libB src/libB/b.cc
src/libB/b.cc:3:16: fatal error: a.hh: No such file or directory
#include "a.hh"
^
compilation terminated.
scons: *** [build/libB/b.os] Error 1
scons: building terminated because of errors.
Second, I tested this with duplicate=False
. In combination with the first test, using Dir('.')
, this successfully compiles the libraries. However, this is not ideal, because any debug symbols then point to source files within the build
directory. For large projects, after compiling, I like to delete the build
directory to save space, which then makes debugging harder, since gdb can no longer find the source files.
Next, I tried using abolute paths. That is, in libA, I add CPPPATH=['#/src/libA']
, and in libB, I add CPPPATH=['#/src/libB']
. This successfully compiles, with duplicate=False
. However, this is intended as a library that could potentially be included from many different top-level SConstructs. By hard-coding the path into the library's SConscript, it restricts the usage of this library.
Finally, I tried not using VariantDir
at all. In addition to using Dir('.')
as the path for each library, this works, but leaves all of the intermediate files in the src
directory. This clutters up the directory structure, and makes it very tricky to maintain multiple builds (e.g. debug/release).
Is there a design usage that would avoid these issues?
Upvotes: 1
Views: 2886
Reputation: 4052
You state that "By hard-coding the path into the library's SConscript, it restricts the usage of this library.". But what's the alternative? At some point in your build description you have to get specific about which paths should get searched for implicit dependencies (like headers or libs). And if you then move your folders around, the build will break...independent of your build tool choice.
Using SCons "#" paths, specified starting from the top-level SConstruct, works fine and is one solution to your problem.
The other alternative would be to use relative paths, starting from your current SConstruct upwards or downwards. So for src/libB/SConscript
you could use:
Import('env')
env.AppendUnique(CPPPATH=['.', '../libA'])
env.SharedLibrary('b.cc')
This would then at least allow you to move "libA
" and "libB
" simultaneously to a new place. But I don't think you can do better than that...
Upvotes: 1