Skip to content

[cling] Anchor the interpreter's clang driver on $ROOTSYS/bin#22754

Open
chrisburr wants to merge 1 commit into
root-project:masterfrom
chrisburr:fix/cling-anchor-driver-on-rootsys
Open

[cling] Anchor the interpreter's clang driver on $ROOTSYS/bin#22754
chrisburr wants to merge 1 commit into
root-project:masterfrom
chrisburr:fix/cling-anchor-driver-on-rootsys

Conversation

@chrisburr

@chrisburr chrisburr commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

This PR fixes conda-forge/root-feedstock#372. I debugged the issue with the help of LLMs and the final patch was written by an LLM. Normally I would have cleaned up the comment but in this case I think it might be warrented.


🤖 Below is a mostly LLM generated explanation of what the problem is but I think it explains the situation:

On Linux GetExecutablePath() resolves /proc/self/exe, i.e. the path of the embedding application rather than of ROOT/cling itself.

clang's driver derives its installed directory -- and therefore its GCC-installation and C-system-header sysroot detection -- from that path. When libCore is embedded in an executable that does not live next to the ROOT installation (e.g. a user application built against a relocatable / conda-forge ROOT), the sysroot is misdetected and the interpreter cannot find the C system headers (assert.h, time.h, ...) even though they ship with the installation. It surfaces as:

C system headers (glibc/Xcode/Windows SDK) must be installed.
fatal error: 'assert.h' file not found

The resource dir and -I include paths are already made ROOTSYS-relative in TCling; only the sysroot was still left to clang's /proc/self/exe-based install-dir guess. Anchor the driver on $ROOTSYS/bin (reusing the LLVMDir / resource-dir location that is already ROOTSYS-relative) so toolchain and sysroot detection follow the ROOT installation regardless of where the host executable lives.

On Linux GetExecutablePath() resolves /proc/self/exe, i.e. the path of the
embedding application rather than of ROOT/cling itself. clang's driver derives
its installed directory -- and therefore its GCC-installation and
C-system-header sysroot detection -- from that path. When libCore is embedded
in an executable that does not live next to the ROOT installation (e.g. a user
application built against a relocatable / conda-forge ROOT), the sysroot is
misdetected and the interpreter cannot find the C system headers (assert.h,
time.h, ...) even though they ship with the installation. It surfaces as:

    C system headers (glibc/Xcode/Windows SDK) must be installed.
    fatal error: 'assert.h' file not found

The resource dir and -I include paths are already made ROOTSYS-relative in
TCling; only the sysroot was still left to clang's /proc/self/exe-based
install-dir guess. Anchor the driver on $ROOTSYS/bin (reusing the LLVMDir /
resource-dir location that is already ROOTSYS-relative) so toolchain and
sysroot detection follow the ROOT installation regardless of where the host
executable lives.

Fixes: conda-forge/root-feedstock#372
// already made ROOTSYS-relative below. LLVMDir is $ROOTSYS/etc/cling.
if (LLVMDir) {
llvm::SmallString<512> rootDriver(LLVMDir);
llvm::sys::path::append(rootDriver, "..", "..", "bin", "rootcling");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also work with builtin_cling=OFF or builtin_llvm=OFF ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conda-forge is only using external clang/llvm. I had to leave before testing the build but I'll definitely test that case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've confirmed now that this works as expected.

@chrisburr chrisburr marked this pull request as ready for review July 3, 2026 21:08
@chrisburr chrisburr requested review from dpiparo and hahnjo as code owners July 3, 2026 21:08
@dpiparo

dpiparo commented Jul 4, 2026

Copy link
Copy Markdown
Member

Thanks @chrisburr, I started the tests. While experts review, could you perhaps clarify if also the code was created with the help of LLMs (https://github.com/root-project/root/blob/master/CONTRIBUTING.md#ai-assisted-coding-disclosure, https://github.com/root-project/root/pulls?q=is%3Aopen+is%3Apr+label%3A🤖AI-Assisted)

@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown

Test Results

    23 files      23 suites   3d 16h 16m 26s ⏱️
 3 874 tests  3 853 ✅ 0 💤 21 ❌
79 709 runs  79 688 ✅ 0 💤 21 ❌

For more details on these failures, see this check.

Results for commit b639a9fa.

@dpiparo dpiparo requested a review from vepadulano July 4, 2026 08:33
@chrisburr

Copy link
Copy Markdown
Contributor Author

@dpiparo thanks for the reminder, I've updated the PR decription accordingly.

@vepadulano

vepadulano commented Jul 10, 2026

Copy link
Copy Markdown
Member

FWIW, the following program

#include <TROOT.h>
int main() {
  gROOT;
}

Compiled and executed with ROOT master and this trivial print statement patch

diff --git a/interpreter/cling/lib/Interpreter/CIFactory.cpp b/interpreter/cling/lib/Interpreter/CIFactory.cpp
index 146167846cf..cd609e5c0c3 100644
--- a/interpreter/cling/lib/Interpreter/CIFactory.cpp
+++ b/interpreter/cling/lib/Interpreter/CIFactory.cpp
@@ -55,6 +55,7 @@
 #include <ctime>
 #include <limits>
 #include <memory>
+#include <iostream>
 
 using namespace clang;
 using namespace cling;
@@ -1428,6 +1429,7 @@ namespace {
 #endif
     // Add host specific includes, -resource-dir if necessary, and -isysroot
     std::string ClingBin = GetExecutablePath(argv[0]);
+    std::cout << "\nClingBin=" << ClingBin << "\n"; 
     AddHostArguments(ClingBin, argvCompile, LLVMDir, COpts);

Gives

$: g++ -g $(root-config --cflags --libs) -o reproducer.out  reproducer.cpp
$:./reproducer.out 

ClingBin=/home/vpadulan/Projects/rootcode/github/root-feedstock/372/reproducer.out

Just to confirm that indeed GetExecutablePath resolves to the path of the current compiled executable.

chrisburr added a commit to conda-forge/root-feedstock that referenced this pull request Jul 13, 2026
chrisburr added a commit to conda-forge/root-feedstock that referenced this pull request Jul 13, 2026
chrisburr added a commit to conda-forge/root-feedstock that referenced this pull request Jul 13, 2026

@hahnjo hahnjo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apart from the violation of putting details about the ROOT setup into Cling, I don't understand why this works. The commit message mentions "toolchain and sysroot detection", but where does this happen? We should not be setting sysroot to the ROOT installation directory because there are valid use cases for using libraries installed system-wide...

Comment on lines +1439 to +1440
// Anchor the driver on $ROOTSYS/bin instead, mirroring how -resource-dir is
// already made ROOTSYS-relative below. LLVMDir is $ROOTSYS/etc/cling.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where "below"? The commit message says TCling, which is not in interpreter/cling...

// already made ROOTSYS-relative below. LLVMDir is $ROOTSYS/etc/cling.
if (LLVMDir) {
llvm::SmallString<512> rootDriver(LLVMDir);
llvm::sys::path::append(rootDriver, "..", "..", "bin", "rootcling");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... and for good reason: Cling should remain agnostic of details about the ROOT setup!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fatal error from interpreter when initializing gROOT

5 participants