How can I build only changed c++ files using Makefile? [duplicate] - c++

This question already has answers here:
Make file Doesn't detect changes in source files
(2 answers)
How do I ensure my makefile detects changes in my header and cpp files?
(2 answers)
Closed 5 months ago.
My folder structure for C++ project is:
└── compiler
├── Makefile
├── README.md
├── build
└── src
├── components
│ ├── lexer
│ │ ├── lexer.cpp
│ │ ├── lexer.h
│ │ └── tokens
│ │ ├── tokens.cpp
│ │ └── tokens.h
│ └── parser
│ ├── parser.cpp
│ ├── parser.h
│ └── syntax
│ ├── syntax.cpp
│ └── syntax.h
├── main.cpp
└── utilities
└── evaluator
├── evaluator.cpp
└── evaluator.h
I want to write my Makefile in such a way that it recompiles only changed .cpp and .h files on command make. My Makefile is:
# Flags
flags_linker = -g -Wall -std=c++11 -lm -ldl -fPIC -rdynamic
flags_compiler = -g -Wall -std=c++11 -fPIC
# Directories and files
# Filenames and paths
main = main
lexer = lexer
tokens = tokens
parser = parser
syntax = syntax
evaluator = evaluator
# Source directories
source_dir = ./src
source_components_dir = $(source_dir)/components
source_lexer_dir = $(source_components_dir)/$(lexer)
source_tokens_dir = $(source_lexer_dir)/$(tokens)
source_parser_dir = $(source_components_dir)/$(parser)
source_syntax_dir = $(source_parser_dir)/$(syntax)
source_utilities_dir = $(source_dir)/utilities
source_evaluator_dir = $(source_utilities_dir)/$(evaluator)
# Build directories
build_dir = ./build
build_components_dir = $(build_dir)/components
build_lexer_dir = $(build_components_dir)/$(lexer)
build_tokens_dir = $(build_lexer_dir)/$(tokens)
build_parser_dir = $(build_components_dir)/$(parser)
build_syntax_dir = $(build_parser_dir)/$(syntax)
build_utilities_dir = $(build_dir)/utilities
build_evaluator_dir = $(build_utilities_dir)/$(evaluator)
run: $(build_dir)/$(main)
$(build_dir)/$(main)
$(build_dir)/$(main):
make executable
executable: compile
g++ $(flags_linker) -v $(build_dir)/$(main).o $(build_lexer_dir)/$(lexer).o $(build_tokens_dir)/$(tokens).o $(build_parser_dir)/$(parser).o $(build_syntax_dir)/$(syntax).o $(build_evaluator_dir)/$(evaluator).o -o $(build_dir)/$(main)
compile: $(main) $(lexer) $(parser) $(evaluator)
$(main): $(source_dir)/$(main).cpp $(lexer) $(parser)
g++ $(flags_compiler) -c $< -o $(build_dir)/$#.o
$(lexer): $(source_lexer_dir)/$(lexer).cpp $(build_lexer_dir) $(tokens)
g++ $(flags_compiler) -c $< -o $(build_lexer_dir)/$#.o
$(tokens): $(source_tokens_dir)/$(tokens).cpp $(build_tokens_dir)
g++ $(flags_compiler) -c $< -o $(build_tokens_dir)/$#.o
$(parser): $(source_parser_dir)/$(parser).cpp $(build_parser_dir) $(syntax)
g++ $(flags_compiler) -c $< -o $(build_parser_dir)/$#.o
$(syntax): $(source_syntax_dir)/$(syntax).cpp $(build_syntax_dir) $(lexer)
g++ $(flags_compiler) -c $< -o $(build_syntax_dir)/$#.o
$(evaluator): $(source_evaluator_dir)/$(evaluator).cpp $(build_evaluator_dir) $(syntax)
g++ $(flags_compiler) -c $< -o $(build_evaluator_dir)/$#.o
$(build_lexer_dir):
mkdir -p $(build_lexer_dir)
$(build_tokens_dir):
mkdir -p $(build_tokens_dir)
$(build_parser_dir):
mkdir -p $(build_parser_dir)
$(build_syntax_dir):
mkdir -p $(build_syntax_dir)
$(build_evaluator_dir):
mkdir -p $(build_evaluator_dir)
clean:
rm -rf ./build/*
My when I run make command, it doesn't recompile the project but just runs the executable. I have just started using Makefiles and not able to figure out what should I change.

Related

Add a source directory to a Makefile

I have the following makefile:
CPP_COMPILER = g++
CPP_COMPILER_FLAGS = -g -O0 -Wall -Wextra -Wpedantic -Wconversion -std=c++17
EXECUTABLE_NAME = mainDebug
CPP_COMPILER_CALL = $(CPP_COMPILER) $(CPP_COMPILER_FLAGS)
INCLUDE_DIR = include
SOURCE_DIR = src1
BUILD_DIR = build
CPP_SOURCES = $(wildcard $(SOURCE_DIR)/*.cpp)
CPP_OBJECTS = $(patsubst $(SOURCE_DIR)/%.cpp, $(BUILD_DIR)/%.o, $(CPP_SOURCES))
build: $(BUILD_DIR)/$(EXECUTABLE_NAME)
TARGET_DEPS = $(CPP_OBJECTS)
$(BUILD_DIR)/$(EXECUTABLE_NAME): $(TARGET_DEPS)
$(CPP_COMPILER_CALL) $^ -o $#
execute:
.$(BUILD_DIR)/$(EXECUTABLE_NAME)
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.cpp
$(CPP_COMPILER_CALL) -I $(INCLUDE_DIR) -c $< -o $#
clean:
rm -rf $(BUILD_DIR)/*.o $(BUILD_DIR)/$(EXECUTABLE_NAME)
And the following folder structure:
.
├── build
├── include
│ ├── mylib.h
│ └── test.h
├── Makefile
├── src1
│ ├── main.cc
│ └── mylib.cc
└── src2
└── test.cc
This works correctly with src1 but when adding src2 to SOURCE_DIR,
SOURCE_DIR = src1\
src2
I get the following error:
/usr/bin/ld: cannot find src1: file format not recognized
collect2: error: ld returned 1 exit status
make: *** [Makefile:22: build/mainDebug] Error 1
What am I doing wrong here ?
Look at how you use SOURCE_DIR:
SOURCE_DIR = src1
...
CPP_SOURCES = $(wildcard $(SOURCE_DIR)/*.cpp)
CPP_OBJECTS = $(patsubst $(SOURCE_DIR)/%.cpp, $(BUILD_DIR)/%.o, $(CPP_SOURCES))
...
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.cpp
$(CPP_COMPILER_CALL) -I $(INCLUDE_DIR) -c $< -o $#
After you define it, you use it three times, each time as a single directory name. You cannot simply add a second name to the variable and expect Make to iterate properly over the list.
First, use addsuffix to get the right pattern for wildcard:
CPP_SOURCES = $(wildcard $(addsuffix /*.cpp,$(SOURCE_DIR)))
Then use CPP_SOURCES instead of SOURCE_DIR:
CPP_OBJECTS = $(patsubst %.cpp, $(BUILD_DIR)/%.o, $(notdir $(CPP_SOURCES)))
Then use vpath to find the sources:
vpath %.cpp $(SOURCE_DIR)
$(BUILD_DIR)/%.o: %.cpp
$(CPP_COMPILER_CALL) -I $(INCLUDE_DIR) -c $< -o $#

Bazel can'f find my external lib header files

I'm testing bazel and now have a problem with external library.
My demo project is like this: a simple main.cpp trying to use 3rd party libary of fastcdr.
bazel-demo/
├── src
│   ├── BUILD
│   └── main.cpp
├── third_party
│   └── fastcdr
│   └── fastcdr.BUILD
└── WORKSPACE
my WORKSPACE file:
new_local_repository(
name = "fastcdr",
path = "/usr/local/fast-rtps/include",
build_file = "third_party/fastcdr/fastcdr.BUILD",
)
it defines a new package in /usr/local/fast-rtps/include, where the fastcdr library is pre-built and installed. (Please note that this is not standard /usr/local/include)
The main BUILD is like:
cc_binary(
name = "main",
srcs = [
"main.cpp",
],
deps = [
"#fastcdr"
],
)
I have added fastcdr as deps to main target.
In my fastcdr.BUILD,
cc_library(
name = "fastcdr",
includes = [
".",
],
linkopts = [
"-L/usr/local/fast-rtps/lib",
"-lfastcdr",
],
visibility = ["//visibility:public"],
)
this is the place I'm not very sure about, but it looks correct to me.
3rd party files are already there:
/usr/local/fast-rtps/
├── examples
│ └── C++
├── include
│ ├── fastcdr
│ │ ├── Cdr.h
│ │ ├── config.h
├── lib
│ ├── libfastcdr.so.1.0.7
│ └── libfastrtps.so.1.5.0
└── share
My understand is that /usr/local/fast-rtps/include is already added into the system include, so in my main.cpp, I can include the file like this:
//#include "fastrcdr/Cdr.h"
#include <fastrcdr/config.h>
int main()
{
return 0;
}
but bazel does not compile and has an error:
src/main.cpp:4:10: fatal error: fastrcdr/config.h: No such file or directory
#include <fastrcdr/config.h>
^~~~~~~~~~~~~~~~~~~
then I use --sandbox_debug to debug like this (re-formatted a little bit):
ERROR: /home/f/gitlab/bazel-demo/src/BUILD:1:10: Compiling src/main.cpp failed: (Exit 1): linux-sandbox failed: error executing command
(cd /home/f/.cache/bazel/_bazel_f/dc41fd263ad6b7cccaa1b7608cdfd5aa/sandbox/linux-sandbox/32/execroot/__main__ && \
exec env - \
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin \
PWD=/proc/self/cwd \
TMPDIR=/tmp \
/home/f/.cache/bazel/_bazel_f/install/64841bf12de13c7518c7ada0994bafe2/linux-sandbox -t 15
-w /home/f/.cache/bazel/_bazel_f/dc41fd263ad6b7cccaa1b7608cdfd5aa/sandbox/linux-sandbox/32/execroot/__main__
-w /tmp -w /dev/shm -D -- /usr/bin/gcc -U_FORTIFY_SOURCE -fstack-protector
-Wall -Wunused-but-set-parameter -Wno-free-nonheap-object -fno-omit-frame-pointer '-std=c++0x'
-MD -MF bazel-out/k8-fastbuild/bin/src/_objs/main/main.pic.d '-frandom-seed=bazel-out/k8-fastbuild/bin/src/_objs/main/main.pic.o' -fPIC -iquote .
-iquote bazel-out/k8-fastbuild/bin
-iquote external/bazel_tools -iquote bazel-out/k8-fastbuild/bin/external/bazel_tools
-iquote external/fastcdr -iquote bazel-out/k8-fastbuild/bin/external/fastcdr
-isystem external/fastcdr -isystem bazel-out/k8-fastbuild/bin/external/fastcdr
-fno-canonical-system-headers -Wno-builtin-macro-redefined '-D__DATE__="redacted"' '-D__TIMESTAMP__="redacted"' '-D__TIME__="redacted"'
-c src/main.cpp -o bazel-out/k8-fastbuild/bin/src/_objs/main/main.pic.o)
From this line
-w /home/f/.cache/bazel/_bazel_f/dc41fd263ad6b7cccaa1b7608cdfd5aa/sandbox/linux-sandbox/32/execroot/__main__
I know my working path.
From these two lines:
-iquote external/fastcdr -iquote bazel-out/k8-fastbuild/bin/external/fastcdr
-isystem external/fastcdr -isystem bazel-out/k8-fastbuild/bin/external/fastcdr
I know external/fastcdr & bazel-out/k8-fastbuild/bin/external/fastcdr are added into my system include.
They are relative paths, so what's the full absolute path? I assume the external and bazel-out are below my working path. I check them, neither folder has the fastcdr path.
But if I go several folder level above, there is another external folder:
dc41fd263ad6b7cccaa1b7608cdfd5aa/
├── execroot
│   └── __main__
├── external <- another `external` folder here
│   ├── bazel_tools -> /home/f/.cache/bazel/_bazel_f/install/64841bf12de13c7518c7ada0994bafe2/embedded_tools
│   ├── #bazel_tools.marker
│   ├── fastcdr <- but fastcdr is here!!!!
│   ├── #fastcdr.marker
│   ├── fastrtps
│   ├── #fastrtps.marker
│   ├── local_config_cc
├── sandbox
│   ├── inaccessibleHelperDir
│   ├── inaccessibleHelperFile
│   └── linux-sandbox <- the working path in bazel output, no fastcdr
I guess I'm very close to fix the problem, but what BUILD file should I change?
Thanks.

Makefile for project with code in multiple directories but same directory structure

I have the following directory structure for a C++ project:
.
├── bin
├── build
├── include
│   ├── dir1
│   │   ├── file1.hpp
│ │ └── file2.hpp
│ ├── dir2
│ │ ├── file3.hpp
│ │ └── file4.hpp
│   └── third_party
│   └── catch.hpp
├── Makefile
├── src
│   ├── dir1
│ │ ├── file1.cpp
│ │ └── file2.cpp
│ └── dir2
│ ├── file3.cpp
│ └── file4.cpp
└── test
├── dir1
│ ├── file1.test.cpp
│ └── file2.test.cpp
└── dir2
├── file3.test.cpp
└── file4.test.cpp
How can I write the Makefile to compile the code in src and test directories and obtain the object files in the build directory and the binaries in the bin directory, maintaining the same directory structure within them, without having to name every file and its dependency explicitly? Would it be better to use multiple Makefiles in each dir* within src and test?
My Makefile currently looks like this: (it's probably nonsensical, sorry about that!)
binaries_dir = bin
build_dir = build
sources_dir = src
include_dir = include
compile_flags = -std=c++14 -Wall
binaries := $(wildcard *.out)
objects := $(wildcard *.o)
sources := $(wildcard *.cpp)
headers := $(wildcard *.hpp)
objects: $(sources)
g++ $(compile_flags) -c $(sources_dir)/$(sources) -I $(include_dir)
binaries: $(objects)
for object in $(objects); do
g++ $(compile_flags) -o $(binaries_dir)/ $(build_dir)/$object
done
I don't think this is fool proof but I think it pretty much does what you are after. You should study up on building Makefiles because it this turns out not to quite fit your needs, how are you going to fix it?
CXX := g++
RM := rm -f
MD := mkdir -p
# don't change, this is for dependencies
CXXFLAGS += -MMD -MP
# add compiler flags here
CXXFLAGS += -std=c++14 -pedantic-errors
CXXFLAGS += -Wall -Wextra
CXXFLAGS += -g3 -O0
# add external includes here
CPPFLAGS += -Iinclude
# add library flags here
LDFLAGS +=
DIRS := $(patsubst src/%, %, $(wildcard src/*))
DIRS += $(patsubst test/%, %, $(wildcard test/*))
PROG_SOURCES := $(wildcard src/*/*.cpp)
TEST_SOURCES := $(wildcard test/*/*.cpp)
OBJECTS := $(patsubst src/%.cpp, build/%.o, $(PROG_SOURCES))
OBJECTS += $(patsubst test/%.cpp, build/%.o, $(TEST_SOURCES))
EXECUTABLES := $(patsubst src/%.cpp, bin/%, $(PROG_SOURCES))
EXECUTABLES += $(patsubst test/%.cpp, bin/%, $(TEST_SOURCES))
DEPENDENCIES := $(patsubst src/%.cpp, build/%.d, $(PROG_SOURCES))
DEPENDENCIES += $(patsubst test/%.cpp, build/%.d, $(TEST_SOURCES))
all: dirs $(EXECUTABLES)
build/%.o: src/%.cpp
$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -o $# $<
build/%.o: test/%.cpp
$(CXX) -c $(CXXFLAGS) $(CPPFLAGS) -o $# $<
bin/%: build/%.o
$(CXX) $(CXXFLAGS) -o $# $< $(LDFLAGS)
-include $(DEPENDENCIES)
clean:
#echo Removing build files
#$(RM) $(EXECUTABLES) $(OBJECTS) $(DEPENDENCIES)
dirs:
#$(MD) $(patsubst %, build/%, $(DIRS)) $(patsubst %, bin/%, $(DIRS))
.PHONY: show dirs
You might find some inspiration from this: https://github.com/jschmerge/DasBuild

Qt Automake separate include, ui, resource folders

Based on this link, I created a Autotools-based build system that accepts Qt UI and RSC files without the need to call QMAKE.
I however wish to separate the source, headers and ui-files into folders in the the following fashion:
${srcdir}
├── Makefile.am
├── main.cc
├── include
│   └── mainwidget.h
├── src
│   └── mainwidget.cc
└── ui
└── mainwidget.ui
And have the build directory ordered in the following way
${builddir}
├── include
│   └── ui_mainwidget.h
├── Makefile
├── main.o
├── mainwidget.o
└── moc_mainwidget.o
My Makefile.am currently looks like this:
moc_%.cc: %.h
#MOC# -o$# $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(MOC_CPPFLAGS) $<
ui_%.h: %.ui
#UIC# -o $# $<
qrc_%.cc: %.qrc
#RCC# -o $# $<
bin_PROGRAMS = qthello
BUILT_SOURCES = ui_mainwidget.h
qthello_CXXFLAGS = -I$(srcdir)/include -I$(builddir)/include
qthello_CPPFLAGS = $(QT_CPPFLAGS)
qthello_LDFLAGS = $(QT_LDFLAGS)
qthello_LDADD = $(QT_LIBS)
qthello_SOURCES = \
moc_mainwidget.cc \
mainwidget.cc \
main.cc
Which works fine if the ui-class files are located in $(srcdir), but simply moving them to the desired directories and changing the expected lines in the Makefile.am does not yeld the desired result. That is, doing these changes does not work:
BUILT_SOURCES = include/ui_mainwidget.h
[ ... ]
qthello_SOURCES = \
src/moc_mainwidget.cc \
src/mainwidget.cc \
main.cc
It occurs to me that some changes have to be made to the build rules to ensure that the include, src, ui -directories exist in $(builddir), and that the correct input files are passed. I am however inexperienced in writing such build rules and google does not seem to have the answer.
Are there any easy portable ways of achieving this?
So I did eventually find a solution to this thanks to this post.
Following is the final Makefile.am
moc_%.cc: ../include/%.h
$(MKDIR_P) $(#D)
#MOC# -o$# $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(MOC_CPPFLAGS) $<
ui_%.h: ../ui/%.ui
$(MKDIR_P) $(#D)
#UIC# -o $# $<
qrc_%.cc: %.qrc
$(MKDIR_P) $(#D)
#RCC# -o $# $<
clean-local:
rm -rf ui/ include/
bin_PROGRAMS = qthello
BUILT_SOURCES = \
include/ui_mainwidget.h
qthello_CXXFLAGS = \
-I$(srcdir)/include \
-I$(builddir)/include
qthello_CPPFLAGS = $(QT_CPPFLAGS)
qthello_LFLAGS = $(QT_LDFLAGS)
qthello_LDADD = $(QT_LIBS)
qthello_SOURCES = \
ui/moc_mainwidget.cc \
src/mainwidget.cc \
main.cc
Keep in mind that AC_PROG_MKDIR_P must be added to configure.ax.

explicit dependency not being picked correctly with scons

I have a scons build environment set up something like :
--SConstruct [Top level file]
--dir1
--Sconscript
--src
--inc
--dir2
--Sconscript
--src
--inc
[dir1]
building dir1 results in several .so being generated, lets say libdir1_a.so, libdir1_b.so, libdir1_c.so etc.
all these shared libs ar eplaced in some folder - $install/dir1/lib/
[dir2]
when building src for dir2, it needs one library to be linked from dir1, libdir1_b.so
I use
env.Depends(dir2_target, $install/dir1/lib/libdir1_b.so)
to specify the dependency.
However, when building source sin dir2 it fails saying explicit dependency not found.
What do i need to do to make sure dir1 builds before dir ?
The solution for your use case is to not use explicit dependencies. The Depends function is not needed here. SCons is smart enough to figure out these types of dependencies.
Here is a working example, because that always makes an explanation better!
>> scons --version
SCons by Steven Knight et al.:
script: v2.3.6.rel_2.3.5:3347:d31d5a4e74b6[MODIFIED], 2015/07/31 14:36:10, by bdbaddog on hpmicrodog
engine: v2.3.6.rel_2.3.5:3347:d31d5a4e74b6[MODIFIED], 2015/07/31 14:36:10, by bdbaddog on hpmicrodog
engine path: ['/usr/lib/scons/SCons']
Copyright (c) 2001 - 2015 The SCons Foundation
>> tree
.
├── dir1
│   ├── include
│   │   ├── dir1_a.h
│   │   ├── dir1_b.h
│   │   └── dir1_c.h
│   ├── SConscript
│   └── src
│   ├── dir1_a.cpp
│   ├── dir1_b.cpp
│   └── dir1_c.cpp
├── dir2
│   ├── include
│   │   └── dir2_a.h
│   ├── SConscript
│   └── src
│   └── dir2_a.cpp
└── SConstruct
6 directories, 11 files
>> find . -type f | xargs awk 'FNR==1{print FILENAME; }{ print }'
./dir2/src/dir2_a.cpp
#include <dir2_a.h>
#include <dir1_a.h>
#include <iostream>
void dir2_a::myhello() {dir1_a::hello();}
./dir2/include/dir2_a.h
#include <iostream>
namespace dir2_a { void myhello();}
./dir2/SConscript
Import('env')
local_env = env.Clone()
local_env.Append(CPPPATH=['include', '#include'],
LIBPATH=['#lib'],
LIBS=['dir1_a'],
RPATH=['$$$$\\{ORIGIN}/.'])
liba = local_env.SharedLibrary('src/dir2_a.cpp')
Install('#lib', [liba])
Install('#include', Glob('include/*.h'))
./SConstruct
env = Environment()
Export('env')
SConscript('dir1/SConscript')
SConscript('dir2/SConscript')
./dir1/src/dir1_a.cpp
#include <dir1_a.h>
#include <iostream>
void dir1_a::hello() {std::cout << "A" << std::endl;}
./dir1/src/dir1_b.cpp
#include <dir1_b.h>
#include <iostream>
void dir1_b::hello() {std::cout << "B" << std::endl;}
./dir1/src/dir1_c.cpp
#include <dir1_c.h>
#include <iostream>
void dir1_c::hello() {std::cout << "C" << std::endl;}
./dir1/include/dir1_c.h
#include <iostream>
namespace dir1_c { void hello();}
./dir1/include/dir1_b.h
#include <iostream>
namespace dir1_b { void hello();}
./dir1/include/dir1_a.h
#include <iostream>
namespace dir1_a { void hello();}
./dir1/SConscript
Import('env')
local_env = env.Clone()
local_env.Append(CPPPATH='include')
liba = local_env.SharedLibrary('src/dir1_a.cpp')
libb = local_env.SharedLibrary('src/dir1_b.cpp')
libc = local_env.SharedLibrary('src/dir1_c.cpp')
Install('#lib', [liba, libb, libc])
Install('#include', Glob('include/*.h'))
>> scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o dir1/src/dir1_a.os -c -fPIC -Idir1/include dir1/src/dir1_a.cpp
g++ -o dir1/src/dir1_b.os -c -fPIC -Idir1/include dir1/src/dir1_b.cpp
g++ -o dir1/src/dir1_c.os -c -fPIC -Idir1/include dir1/src/dir1_c.cpp
g++ -o dir1/src/libdir1_a.so -shared dir1/src/dir1_a.os
g++ -o dir1/src/libdir1_b.so -shared dir1/src/dir1_b.os
g++ -o dir1/src/libdir1_c.so -shared dir1/src/dir1_c.os
Install file: "dir1/include/dir1_a.h" as "include/dir1_a.h"
g++ -o dir2/src/dir2_a.os -c -fPIC -Idir2/include -Iinclude dir2/src/dir2_a.cpp
Install file: "dir1/src/libdir1_a.so" as "lib/libdir1_a.so"
g++ -o dir2/src/libdir2_a.so -shared -Wl,-rpath=$\{ORIGIN}/. dir2/src/dir2_a.os -Llib -ldir1_a
Install file: "dir1/include/dir1_b.h" as "include/dir1_b.h"
Install file: "dir1/include/dir1_c.h" as "include/dir1_c.h"
Install file: "dir2/include/dir2_a.h" as "include/dir2_a.h"
Install file: "dir1/src/libdir1_b.so" as "lib/libdir1_b.so"
Install file: "dir1/src/libdir1_c.so" as "lib/libdir1_c.so"
Install file: "dir2/src/libdir2_a.so" as "lib/libdir2_a.so"
scons: done building targets.
>> tree
.
├── dir1
│   ├── include
│   │   ├── dir1_a.h
│   │   ├── dir1_b.h
│   │   └── dir1_c.h
│   ├── SConscript
│   └── src
│   ├── dir1_a.cpp
│   ├── dir1_a.os
│   ├── dir1_b.cpp
│   ├── dir1_b.os
│   ├── dir1_c.cpp
│   ├── dir1_c.os
│   ├── libdir1_a.so
│   ├── libdir1_b.so
│   └── libdir1_c.so
├── dir2
│   ├── include
│   │   └── dir2_a.h
│   ├── SConscript
│   └── src
│   ├── dir2_a.cpp
│   ├── dir2_a.os
│   └── libdir2_a.so
├── include
│   ├── dir1_a.h
│   ├── dir1_b.h
│   ├── dir1_c.h
│   └── dir2_a.h
├── lib
│   ├── libdir1_a.so
│   ├── libdir1_b.so
│   ├── libdir1_c.so
│   └── libdir2_a.so
└── SConstruct
8 directories, 27 files
>> ldd lib/libdir2_a.so
linux-vdso.so.1 (0x00007ffdb53a5000)
libdir1_a.so => ./libdir1_a.so (0x00007f0707bd7000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f070782f000)
libm.so.6 => /lib64/libm.so.6 (0x00007f070752d000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f0707316000)
libc.so.6 => /lib64/libc.so.6 (0x00007f0706f54000)
/lib64/ld-linux-x86-64.so.2 (0x000055bd342e4000)
If you want to see that the dependency tree is really being automatically setup, just execute the following...
>> scons --tree=prune
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
g++ -o dir1/src/dir1_a.os -c -fPIC -Idir1/include dir1/src/dir1_a.cpp
g++ -o dir1/src/dir1_b.os -c -fPIC -Idir1/include dir1/src/dir1_b.cpp
g++ -o dir1/src/dir1_c.os -c -fPIC -Idir1/include dir1/src/dir1_c.cpp
g++ -o dir1/src/libdir1_a.so -shared dir1/src/dir1_a.os
g++ -o dir1/src/libdir1_b.so -shared dir1/src/dir1_b.os
g++ -o dir1/src/libdir1_c.so -shared dir1/src/dir1_c.os
Install file: "dir1/include/dir1_a.h" as "include/dir1_a.h"
g++ -o dir2/src/dir2_a.os -c -fPIC -Idir2/include -Iinclude dir2/src/dir2_a.cpp
Install file: "dir1/src/libdir1_a.so" as "lib/libdir1_a.so"
g++ -o dir2/src/libdir2_a.so -shared -Wl,-rpath=$\{ORIGIN}/. dir2/src/dir2_a.os -Llib -ldir1_a
Install file: "dir1/include/dir1_b.h" as "include/dir1_b.h"
Install file: "dir1/include/dir1_c.h" as "include/dir1_c.h"
Install file: "dir2/include/dir2_a.h" as "include/dir2_a.h"
Install file: "dir1/src/libdir1_b.so" as "lib/libdir1_b.so"
Install file: "dir1/src/libdir1_c.so" as "lib/libdir1_c.so"
Install file: "dir2/src/libdir2_a.so" as "lib/libdir2_a.so"
+-.
+-SConstruct
+-dir1
| +-dir1/SConscript
| +-dir1/include
| | +-dir1/include/dir1_a.h
| | +-dir1/include/dir1_b.h
| | +-dir1/include/dir1_c.h
| +-dir1/src
| +-dir1/src/dir1_a.cpp
| +-dir1/src/dir1_a.os
| | +-dir1/src/dir1_a.cpp
| | +-dir1/include/dir1_a.h
| | +-/bin/g++
| +-dir1/src/dir1_b.cpp
| +-dir1/src/dir1_b.os
| | +-dir1/src/dir1_b.cpp
| | +-dir1/include/dir1_b.h
| | +-/bin/g++
| +-dir1/src/dir1_c.cpp
| +-dir1/src/dir1_c.os
| | +-dir1/src/dir1_c.cpp
| | +-dir1/include/dir1_c.h
| | +-/bin/g++
| +-dir1/src/libdir1_a.so
| | +-[dir1/src/dir1_a.os]
| +-dir1/src/libdir1_b.so
| | +-[dir1/src/dir1_b.os]
| +-dir1/src/libdir1_c.so
| +-[dir1/src/dir1_c.os]
+-dir2
| +-dir2/SConscript
| +-dir2/include
| | +-dir2/include/dir2_a.h
| +-dir2/src
| +-dir2/src/dir2_a.cpp
| +-dir2/src/dir2_a.os
| | +-dir2/src/dir2_a.cpp
| | +-include/dir1_a.h
| | | +-dir1/include/dir1_a.h
| | +-dir2/include/dir2_a.h
| | +-/bin/g++
| +-dir2/src/libdir2_a.so
| +-[dir2/src/dir2_a.os]
| +-lib/libdir1_a.so
| +-[dir1/src/libdir1_a.so]
+-include
| +-[include/dir1_a.h]
| +-include/dir1_b.h
| | +-dir1/include/dir1_b.h
| +-include/dir1_c.h
| | +-dir1/include/dir1_c.h
| +-include/dir2_a.h
| +-dir2/include/dir2_a.h
+-lib
+-[lib/libdir1_a.so]
+-lib/libdir1_b.so
| +-[dir1/src/libdir1_b.so]
+-lib/libdir1_c.so
| +-[dir1/src/libdir1_c.so]
+-lib/libdir2_a.so
+-[dir2/src/libdir2_a.so]
scons: done building targets.