diff --git a/cmake/modules/RootConfiguration.cmake b/cmake/modules/RootConfiguration.cmake
index 1fd7e8a496185..489281df231fd 100644
--- a/cmake/modules/RootConfiguration.cmake
+++ b/cmake/modules/RootConfiguration.cmake
@@ -548,6 +548,19 @@ endif()
string(REGEX MATCH "__cplusplus[=| ]([0-9]+)" __cplusplus "${__cplusplus_PPout}")
set(__cplusplus ${CMAKE_MATCH_1}L)
+# To mark the build tree. Important for automatic resolution of relative paths,
+# for example to the include directory. Use custom target to ensure re-creation
+# when someone deletes the marker.
+set(build_tree_marker "${localruntimedir}/root-build-tree-marker")
+add_custom_command(
+ OUTPUT "${build_tree_marker}"
+ COMMAND ${CMAKE_COMMAND} -E touch "${build_tree_marker}"
+ COMMENT "Ensuring that \"${build_tree_marker}\" exists"
+)
+add_custom_target(ensure_build_tree_marker ALL
+ DEPENDS "${build_tree_marker}"
+)
+
configure_file(${PROJECT_SOURCE_DIR}/config/RConfigure.in ginclude/RConfigure.h NEWLINE_STYLE UNIX)
install(FILES ${CMAKE_BINARY_DIR}/ginclude/RConfigure.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
diff --git a/config/RConfigure.in b/config/RConfigure.in
index d8fa08521d0c9..09931572afe88 100644
--- a/config/RConfigure.in
+++ b/config/RConfigure.in
@@ -9,7 +9,6 @@
#define ROOTPREFIX "@prefix@"
#define ROOTBINDIR "@bindir@"
#define ROOTLIBDIR "@libdir@"
-#define ROOTINCDIR "@incdir@"
#define ROOTETCDIR "@etcdir@"
#define ROOTDATADIR "@datadir@"
#define ROOTDOCDIR "@docdir@"
diff --git a/core/base/CMakeLists.txt b/core/base/CMakeLists.txt
index 97fffc3e9b6bb..26177a4d446cc 100644
--- a/core/base/CMakeLists.txt
+++ b/core/base/CMakeLists.txt
@@ -236,9 +236,21 @@ if(core_soversion)
else()
set(full_core_filename "${core_prefix}Core${core_suffix}")
endif()
+
+# Absolue CMAKE_INSTALL_
paths are discouraged in CMake, but some
+# packagers use them anyway. So we support it.
+if(IS_ABSOLUTE ${CMAKE_INSTALL_INCLUDEDIR})
+ set(install_includedir_is_absolute 1)
+else()
+ set(install_includedir_is_absolute 0)
+endif()
+file(TO_NATIVE_PATH "${CMAKE_INSTALL_INCLUDEDIR}" install_includedir_native)
+
target_compile_options(Core PRIVATE -DLIB_CORE_NAME=${full_core_filename}
- -DCMAKE_INSTALL_INCLUDEDIR=${CMAKE_INSTALL_INCLUDEDIR}
+ -DINSTALL_INCLUDEDIR=${install_includedir_native}
+ -DINSTALL_INCLUDEDIR_IS_ABSOLUTE=${install_includedir_is_absolute}
)
+add_dependencies(Core ensure_build_tree_marker)
if(PCRE2_FOUND)
target_link_libraries(Core PRIVATE PCRE2::PCRE2)
diff --git a/core/base/src/TROOT.cxx b/core/base/src/TROOT.cxx
index af0068d8c1bff..f557c4d440977 100644
--- a/core/base/src/TROOT.cxx
+++ b/core/base/src/TROOT.cxx
@@ -1993,9 +1993,7 @@ void TROOT::InitSystem()
if (gSystem->Init())
fprintf(stderr, "Fatal in : can't init operating system layer\n");
- TString rootincludedir = _R_QUOTEVAL_(CMAKE_INSTALL_INCLUDEDIR);
- gSystem->PrependPathName(GetRootSys(), rootincludedir);
- gSystem->SetIncludePath(("-I" + rootincludedir).Data());
+ gSystem->SetIncludePath(("-I" + GetIncludeDir()).Data());
if (!gSystem->HomeDirectory()) {
fprintf(stderr, "Fatal in : HOME directory not set\n");
@@ -3098,11 +3096,29 @@ const TString& TROOT::GetSharedLibDir() {
////////////////////////////////////////////////////////////////////////////////
/// Get the include directory in the installation. Static utility function.
-const TString& TROOT::GetIncludeDir() {
- // Avoid returning a reference to a temporary because of the conversion
- // between std::string and TString.
- const static TString includedir = ROOT::FoundationUtils::GetIncludeDir();
- return includedir;
+const TString &TROOT::GetIncludeDir()
+{
+ static TString rootincdir;
+
+ if (!rootincdir.IsNull())
+ return rootincdir;
+
+ const std::string &sep = ROOT::FoundationUtils::GetPathSeparator();
+
+ // Check if we are in the build tree using the build tree marker file
+ const bool isBuildTree = std::filesystem::exists((GetSharedLibDir() + sep + "root-build-tree-marker").Data());
+
+ if (isBuildTree) {
+ rootincdir = GetRootSys() + sep + "include";
+ } else {
+#if INSTALL_INCLUDEDIR_IS_ABSOLUTE
+ rootincdir = _R_QUOTEVAL_(INSTALL_INCLUDEDIR);
+#else
+ rootincdir = GetRootSys() + sep + _R_QUOTEVAL_(INSTALL_INCLUDEDIR);
+#endif
+ }
+
+ return rootincdir;
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/core/foundation/res/ROOT/FoundationUtils.hxx b/core/foundation/res/ROOT/FoundationUtils.hxx
index ce224f1067130..c4ba65cfe093c 100644
--- a/core/foundation/res/ROOT/FoundationUtils.hxx
+++ b/core/foundation/res/ROOT/FoundationUtils.hxx
@@ -67,10 +67,6 @@ namespace FoundationUtils {
///
const std::string& GetRootSys();
- ///\ returns the include directory in the installation.
- ///
- const std::string& GetIncludeDir();
-
///\returns the sysconfig directory in the installation.
const std::string& GetEtcDir();
diff --git a/core/foundation/src/FoundationUtils.cxx b/core/foundation/src/FoundationUtils.cxx
index 702c00377c8c2..b1b73b2d47fe6 100644
--- a/core/foundation/src/FoundationUtils.cxx
+++ b/core/foundation/src/FoundationUtils.cxx
@@ -167,8 +167,10 @@ const std::string& GetRootSys() {
if (rootsys.empty()) {
if (const char* envValue = std::getenv("ROOTSYS")) {
rootsys = envValue;
+#ifndef WIN32
// We cannot use gSystem->UnixPathName.
ConvertToUnixPath(rootsys);
+#endif
}
}
// FIXME: Should this also call UnixPathName for consistency?
@@ -177,22 +179,6 @@ const std::string& GetRootSys() {
return rootsys;
}
-
-const std::string& GetIncludeDir() {
-#ifdef ROOTINCDIR
- if (!IgnorePrefix()) {
- const static std::string rootincdir = ROOTINCDIR;
- return rootincdir;
- }
-#endif
- static std::string rootincdir;
- if (rootincdir.empty()) {
- const std::string& sep = GetPathSeparator();
- rootincdir = GetRootSys() + sep + "include" + sep;
- }
- return rootincdir;
-}
-
const std::string& GetEtcDir() {
#ifdef ROOTETCDIR
if (!IgnorePrefix()) {