I have C++ project that are built using Boost.Build. The project consists of 3 subprojects.
. [root]
\-- source
\-- common
\-- config
\-- config.cpp
\-- project_1
\-- Jamfile.jam
\-- project_2
\-- Jamfile.jam
\-- project_3
\-- Jamfile.jam
\-- Jamroot.jam
Jamroot.jam:
project my_project
: requirements
multi
debug:DEBUG
: default-build
static
: build-dir bin
;
alias project_1 : source/project_1 ;
alias project_2 : source/project_2 ;
alias project_3 : source/project_3 ;
install dist : project_1 project_2 project_3
: on EXE
;
Each project has Jamfile.jam according to this template:
project project_N
: requirements
CONFIG_DEFINE_1=
CONFIG_DEFINE_2=
;
lib config : [ glob ../common/config/*.cpp ] ;
exe project_N
: [ glob *.cpp ] config
:
;
config.cpp uses defines CONFIG_DEFINE_1 and CONFIG_DEFINE_2 for conditional compilation (actually they are simply constants), so there's a separate version of config library per project.
The problem is that such approach causes the config library to be rebuilt each time the whole project is built regardless of were the files changed or not. I.e. building the first time everything is compiled and linked, building the second time without doing any modifications - only the config library is built for each project_N. How should I properly setup the building so no redundand compilation occur?
As I understand it, your config library is shared over different projects and uses different defines for each project.
It's not possible to overcome recompilation in that case, irrespective of boost build.or any other build system. In between compiles of the cpp files the preprocessed files have changed.
If you want to avoid recompilation one option is to split of the config library into different libraries for each project, but depending on what config looks like, having a lot of code duplication is rarely desireable either...
The only other option I can think of is reducing the amount of code that needs to be recompiled every time.
e.g. you have a sourcefile LargeFunction.cpp with
#if CONFIG_DEFINE_1
void VeryLargeFunction() {
...
}
#elif CONFIG_DEFINE_2
void VeryLargeFunction() {
...
}
#endif
Split it into three files, one containing the VeryLargeFunction as defined for DEFINE_1, one as defined for DEFINE_2, and one which simply includes these two based on the values of the defines.
#if CONFIG_DEFINE_1
#include "definitionFileFor1"
#elif CONFIG_DEFINE_2
#include "definitionFileFor2"
#endif
This file still needs to be recompiled every time, but the object files which contain the 'real' code, will not.
You'll effectively only relink existing object files on every compile, i.s.o. recompiling everything.
The disadvantage is more maintenance though, and the different function definitions reside in different files, so the code becomes a bit harder to read.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With