Skip to content

Commit 47caba5

Browse files
committed
[core] Generalize TROOT::GetLibDir()
The problem with `TROOT::GetLibDir()` was that it either hardcodes the install directory inside it if `ROOTLIBDIR` was set (which is the case for `gnuinstall=ON`), or it assumes that it's always called `lib` and is inside the `$ROOTSYS`, which might or might not be set. This is broken if the `CMAKE_INSTALL_LIBDIR` is different from the default `lib`. This commit suggests to automatically figure out the ROOT library directory instead. Closes the following JIRA ticket: https://its.cern.ch/jira/browse/ROOT-9569
1 parent 40bf9e1 commit 47caba5

File tree

2 files changed

+81
-13
lines changed

2 files changed

+81
-13
lines changed

core/base/CMakeLists.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,21 @@ target_include_directories(Core PUBLIC
207207
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/inc>
208208
)
209209

210+
if(ROOT_NEED_STDCXXFS)
211+
target_link_libraries(Core PRIVATE stdc++fs)
212+
endif()
213+
214+
# This code about the LIB_CORE_NAME define is important for TROOT::GetLibDir()
215+
get_target_property(core_prefix Core PREFIX)
216+
get_target_property(core_suffix Core SUFFIX)
217+
get_target_property(core_soversion Core SOVERSION)
218+
if(core_soversion)
219+
set(full_core_filename "${core_prefix}Core${core_suffix}.${core_soversion}")
220+
else()
221+
set(full_core_filename "${core_prefix}Core${core_suffix}")
222+
endif()
223+
target_compile_options(Core PRIVATE -DLIB_CORE_NAME=${full_core_filename})
224+
210225
if(PCRE2_FOUND)
211226
target_link_libraries(Core PRIVATE PCRE2::PCRE2)
212227
set_source_files_properties(src/TPRegexp.cxx

core/base/src/TROOT.cxx

Lines changed: 66 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ of a main program creating an interactive version is shown below:
7171
#include <ROOT/RVersion.hxx>
7272
#include "RConfigure.h"
7373
#include "RConfigOptions.h"
74+
#include <filesystem>
7475
#include <string>
7576
#include <map>
7677
#include <set>
@@ -109,8 +110,12 @@ FARPROC dlsym(void *library, const char *function_name)
109110
return ::GetProcAddress((HMODULE)library, function_name);
110111
}
111112
}
113+
#elif defined(__APPLE__)
114+
#include <dlfcn.h>
115+
#include <mach-o/dyld.h>
112116
#else
113117
#include <dlfcn.h>
118+
#include <link.h>
114119
#endif
115120

116121
#include <iostream>
@@ -3007,23 +3012,71 @@ const TString& TROOT::GetBinDir() {
30073012

30083013
////////////////////////////////////////////////////////////////////////////////
30093014
/// Get the library directory in the installation. Static utility function.
3015+
///
3016+
/// This function inspects the libraries currently loaded in the process to
3017+
/// locate the ROOT Core library. Once found, it extracts and returns the
3018+
/// directory containing that library. If the ROOT Core library was not found,
3019+
/// it will return an empty string.
3020+
///
3021+
/// The result is cached in a static variable so the lookup is only performed
3022+
/// once per process, and the implementation is platform-specific.
3023+
///
3024+
/// \return The directory path (as a `TString`) containing the ROOT core library.
30103025

3011-
const TString& TROOT::GetLibDir() {
3012-
#ifdef ROOTLIBDIR
3013-
if (IgnorePrefix()) {
3014-
#endif
3015-
static TString rootlibdir;
3016-
if (rootlibdir.IsNull()) {
3017-
rootlibdir = "lib";
3018-
gSystem->PrependPathName(GetRootSys(), rootlibdir);
3019-
}
3020-
return rootlibdir;
3021-
#ifdef ROOTLIBDIR
3022-
} else {
3023-
const static TString rootlibdir = ROOTLIBDIR;
3026+
const TString &TROOT::GetLibDir()
3027+
{
3028+
static bool haveLooked = false;
3029+
static TString rootlibdir;
3030+
if (haveLooked)
30243031
return rootlibdir;
3032+
3033+
haveLooked = true;
3034+
3035+
namespace fs = std::filesystem;
3036+
3037+
#define TO_LITERAL(string) _QUOTE_(string)
3038+
3039+
#if defined(__APPLE__)
3040+
3041+
uint32_t count = _dyld_image_count();
3042+
for (uint32_t i = 0; i < count; i++) {
3043+
const char *path = _dyld_get_image_name(i);
3044+
if (!path)
3045+
continue;
3046+
3047+
fs::path p(path);
3048+
if (p.filename() == TO_LITERAL(LIB_CORE_NAME)) {
3049+
rootlibdir = p.parent_path().c_str();
3050+
break;
3051+
}
30253052
}
3053+
3054+
#elif defined(_WIN32)
3055+
3056+
// Or Windows, the original hardcoded path is kept for now.
3057+
rootlibdir = "lib";
3058+
gSystem->PrependPathName(GetRootSys(), rootlibdir);
3059+
3060+
#else
3061+
3062+
auto callback = +[](struct dl_phdr_info *info, size_t /*size*/, void *data) -> int {
3063+
TString &libdir = *static_cast<TString *>(data);
3064+
if (!info->dlpi_name)
3065+
return 0;
3066+
3067+
fs::path p = info->dlpi_name;
3068+
if (p.filename() == TO_LITERAL(LIB_CORE_NAME)) {
3069+
libdir = p.parent_path().c_str();
3070+
return 1; // stop iteration
3071+
}
3072+
return 0; // continue
3073+
};
3074+
3075+
dl_iterate_phdr(callback, &rootlibdir);
3076+
30263077
#endif
3078+
3079+
return rootlibdir;
30273080
}
30283081

30293082
////////////////////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)