Make CMAKE_SOURCE_DIR and CMAKE_BINARY_DIR refer to subdirectory's root and introduce CMAKE_ROOT_SOURCE_DIR and CMAKE_ROOT_BINARY_DIR variables
Currently, CMake is used to include dependencies within a project in the build output to great effect (namely with Ninja, which speeds up dependency + top level application speeds quite a bit by creating a single graph with all nested dependencies!)
However, there comes a few problems with file namespacing. Right now, CMAKE_SOURCE_DIR
and CMAKE_BINARY_DIR
refer to the top level CMake project directories and their generated locations, respectively. This causes problems with dependencies loaded in via add_subdirectory()
that use CMAKE_SOURCE_DIR
and rely on it to point to their top level locations.
Currently, the 'proper' way to address this would be to substitute such variables out in lieu of CMAKE_CURRENT_SOURCE_DIR
and CMAKE_CURRENT_BINARY_DIR
-- however, this doesn't solve the problem in many cases, and legacy build scripts (e.g. WebKit's CMake system) that are extensive and aren't likely to be changed by the maintainers will still suffer from being included as dependencies.
Such dependencies will break their builds if included as subdirectory projects.
I propose the following:
-
CMAKE_SOURCE_DIR
andCMAKE_BINARY_DIR
change to refer to the current "subdirectory" root - that is, projects that are referred to directly via thecmake
command behave the same, but projects initialized viaadd_subdirectory
no longer refer to the parent project's root directory. - Two new variables,
CMAKE_ROOT_SOURCE_DIR
andCMAKE_ROOT_BINARY_DIR
, be introduced that function identically to the currentCMAKE_SOURCE_DIR
andCMAKE_BINARY_DIR
. -
add_subdirectory()
changes its functionality to setCMAKE_SOURCE_DIR
andCMAKE_BINARY_DIR
to point to the root of the subdirectory being included.
These changes would only break projects that explicitly rely upon a parent project's directory hierarchy via the CMAKE_SOURCE_DIR
or CMAKE_BINARY_DIR
variables, in which case replacing such occurrences with CMAKE_ROOT_SOURCE_DIR
and CMAKE_ROOT_BINARY_DIR
would be the fix.
CMAKE_CURRENT_SOURCE_DIR
and CMAKE_CURRENT_BINARY_DIR
would remain unchanged.
These changes would only affect calls to add_subdirectory
, not include()
.
For example, if I have projects Foo
and Bar
and I build them in a directory called build
:
/
CMakeLists.txt
foo.c
bar/
CMakeLists.txt
bar.c
bar.h
sub-bar/
sub-bar.cmake
sub-bar.c
# /CMakeLists.txt
project (Foo)
add_subdirectory (bar)
add_library (foo "${CMAKE_SOURCE_DIR}/foo.c")
# /bar/CMakeLists.txt
project (Bar)
add_library (bar "${CMAKE_SOURCE_DIR}/bar.c")
include (sub-bar)
# /bar/sub-bar/sub-bar.cmake
include_directories (${CMAKE_SOURCE_DIR})
add_library (subbar "${CMAKE_CURRENT_SOURCE_DIR}/sub-bar.c")
The variables would be set to:
# Foo
CMAKE_SOURCE_DIR=/
CMAKE_CURRENT_SOURCE_DIR=/
CMAKE_ROOT_SOURCE_DIR=/
CMAKE_BINARY_DIR=/build/
CMAKE_CURRENT_BINARY_DIR=/build/
CMAKE_ROOT_BINARY_DIR=/build/
# Bar
CMAKE_SOURCE_DIR=/bar/
CMAKE_CURRENT_SOURCE_DIR=/bar/
CMAKE_ROOT_SOURCE_DIR=/
CMAKE_BINARY_DIR=/build/bar/
CMAKE_CURRENT_BINARY_DIR=/build/bar/
CMAKE_ROOT_BINARY_DIR=/build/
# Bar/sub-bar
CMAKE_SOURCE_DIR=/bar/
CMAKE_CURRENT_SOURCE_DIR=/bar/sub-bar/
CMAKE_ROOT_SOURCE_DIR=/
CMAKE_BINARY_DIR=/build/bar/
CMAKE_CURRENT_BINARY_DIR=/build/bar/sub-bar/
CMAKE_ROOT_BINARY_DIR=/build/