Skip to content

Commit dc79416

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 04e8c83 commit dc79416

File tree

1 file changed

+80
-13
lines changed

1 file changed

+80
-13
lines changed

core/base/src/TROOT.cxx

Lines changed: 80 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,7 +110,10 @@ FARPROC dlsym(void *library, const char *function_name)
109110
return ::GetProcAddress((HMODULE)library, function_name);
110111
}
111112
}
113+
#elif defined(__APPLE__)
114+
#include <mach-o/dyld.h>
112115
#else
116+
#include <link.h>
113117
#include <dlfcn.h>
114118
#endif
115119

@@ -3007,23 +3011,86 @@ const TString& TROOT::GetBinDir() {
30073011

30083012
////////////////////////////////////////////////////////////////////////////////
30093013
/// Get the library directory in the installation. Static utility function.
3014+
///
3015+
/// This function inspects the libraries currently loaded in the process
3016+
/// to locate the ROOT core library (`libCore`). Once found, it extracts
3017+
/// and returns the directory containing that library.
3018+
///
3019+
/// The implementation is platform-specific:
3020+
/// - **Linux**: Uses `dl_iterate_phdr()` to iterate over all loaded
3021+
/// ELF objects. When `libCore.so` is found, its parent directory is returned.
3022+
/// - **macOS**: Iterates over all Mach-O images via `_dyld_image_count()`
3023+
/// and `_dyld_get_image_name()`, looking for `libCore.dylib`
3024+
/// (or `libCore.so` for compatibility).
3025+
/// - **Windows**: Uses `EnumProcessModules()` and `GetModuleFileNameA()`
3026+
/// to inspect loaded DLLs, looking for `libCore.dll`.
3027+
///
3028+
/// The result is cached in a static variable so the lookup is only
3029+
/// performed once per process.
3030+
///
3031+
/// \return The directory path (as a `TString`) containing the ROOT core library.
30103032

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;
3033+
const TString &TROOT::GetLibDir()
3034+
{
3035+
static TString rootlibdir;
3036+
if (!rootlibdir.IsNull())
30243037
return rootlibdir;
3038+
3039+
namespace fs = std::filesystem;
3040+
3041+
#ifdef __linux__
3042+
3043+
auto callback = +[](struct dl_phdr_info *info, size_t /*size*/, void *data) -> int {
3044+
TString &libdir = *static_cast<TString *>(data);
3045+
if (!info->dlpi_name)
3046+
return 0;
3047+
3048+
fs::path p = info->dlpi_name;
3049+
if (p.filename() == "libCore.so") {
3050+
libdir = p.parent_path().c_str();
3051+
return 1; // stop iteration
3052+
}
3053+
return 0; // continue
3054+
};
3055+
3056+
dl_iterate_phdr(callback, &rootlibdir);
3057+
3058+
#elif defined(__APPLE__)
3059+
3060+
uint32_t count = _dyld_image_count();
3061+
for (uint32_t i = 0; i < count; i++) {
3062+
const char *path = _dyld_get_image_name(i);
3063+
if (!path)
3064+
continue;
3065+
3066+
fs::path p(path);
3067+
if (p.filename() == "libCore.dylib" || p.filename() == "libCore.so") {
3068+
rootlibdir = p.parent_path().c_str();
3069+
break;
3070+
}
30253071
}
3072+
3073+
#elif defined(_WIN32)
3074+
3075+
HMODULE hMods[1024];
3076+
DWORD cbNeeded;
3077+
3078+
if (EnumProcessModules(::GetCurrentProcess(), hMods, sizeof(hMods), &cbNeeded)) {
3079+
for (unsigned int i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) {
3080+
char szModName[MAX_PATH];
3081+
if (GetModuleFileNameA(hMods[i], szModName, sizeof(szModName) / sizeof(char))) {
3082+
fs::path p(szModName);
3083+
if (p.filename() == "libCore.dll") { // ROOT Windows build
3084+
rootlibdir = p.parent_path().string().c_str();
3085+
break;
3086+
}
3087+
}
3088+
}
3089+
}
3090+
30263091
#endif
3092+
3093+
return rootlibdir;
30273094
}
30283095

30293096
////////////////////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)