Skip to content

Make non-system include paths accessible at runtime #19179

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

LukasBreitwieser
Copy link
Contributor

The current implementation faces issues with accessing header files from external libraries stored in non-system paths when the C++ interpreter tries to resolve them at runtime. This access is necessary under certain conditions even if a corresponding module file exists. Related issues: SPI-2794, #18949

To address this issue, we need to ensure that non-system path includes, which are known at build time, remain accessible at runtime. The proposed solution leverages the existing ROOT_INCLUDE_PATH environment variable.

This commit introduces a new CMake variable DEFAULT_ROOT_INCLUDE_PATH and a helper function IF_NOT_SYSTEM_PATH_APPEND. This function allows us to conditionally append include paths of external libraries to DEFAULT_ROOT_INCLUDE_PATH, for example IF_NOT_SYSTEM_PATH_APPEND("${Vc_INCLUDE_DIR}" DEFAULT_ROOT_INCLUDE_PATH)

The DEFAULT_ROOT_INCLUDE_PATH variable is then utilized to populate the ROOT_INCLUDE_PATH environment variable in the configuration files (thisroot.{sh,csh,fish,bat}).

If the library's include path is dynamically modified between build and run time, the configuration can be updated by patching the thisroot.{sh,csh,fish,bat} files.

The current implementation faces issues with accessing header files
from external libraries stored in non-system paths when the C++
interpreter tries to resolve them at runtime. This access is necessary
under certain conditions even if a corresponding module file exists.

To address this issue, we need to ensure that non-system path includes,
which are known at build time, remain accessible at runtime. The
proposed solution leverages the existing `ROOT_INCLUDE_PATH` environment
variable.

This commit introduces a new CMake variable `DEFAULT_ROOT_INCLUDE_PATH`
and a helper function `IF_NOT_SYSTEM_PATH_APPEND`. This function allows
us to conditionally append include paths of external libraries to
`DEFAULT_ROOT_INCLUDE_PATH`, for example
`IF_NOT_SYSTEM_PATH_APPEND("${Vc_INCLUDE_DIR}" DEFAULT_ROOT_INCLUDE_PATH)`

The `DEFAULT_ROOT_INCLUDE_PATH` variable is then utilized to populate the
`ROOT_INCLUDE_PATH` environment variable in the configuration files
(`thisroot.{sh,csh,fish,bat}`).

If the library's include path is dynamically modified between build and
run time, the configuration can be updated by patching the
`thisroot.{sh,csh,fish,bat}` files.
Copy link

github-actions bot commented Jun 25, 2025

Test Results

    20 files      20 suites   3d 9h 25m 7s ⏱️
 3 192 tests  3 184 ✅   0 💤 8 ❌
62 241 runs  62 102 ✅ 131 💤 8 ❌

For more details on these failures, see this check.

Results for commit 6feedf8.

♻️ This comment has been updated with latest results.

Copy link
Member

@hageboeck hageboeck left a comment

Choose a reason for hiding this comment

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

Nice! I added a few comments below

Comment on lines 2147 to 2150
set(${is_system_path} true PARENT_SCOPE)
endif()
endforeach()
set(${is_system_path} false PARENT_SCOPE)
Copy link
Member

@hageboeck hageboeck Jun 26, 2025

Choose a reason for hiding this comment

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

The canonical bools are all caps, and we can break out early:

Suggested change
set(${is_system_path} true PARENT_SCOPE)
endif()
endforeach()
set(${is_system_path} false PARENT_SCOPE)
set(${is_system_path} TRUE PARENT_SCOPE)
return()
endif()
endforeach()
set(${is_system_path} FALSE PARENT_SCOPE)

@@ -89,6 +89,10 @@ clean_environment()
default_manpath=""
fi
fi
if [ -n "${ROOT_INCLUDE_PATH-}" ]; then
drop_from_path "$ROOT_INCLUDE_PATH" "@DEFAULT_ROOT_INCLUDE_PATH@"
ROOT_INCLUDE_PATH=$newpath
Copy link
Member

Choose a reason for hiding this comment

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

newpath seems to be undefined here, or did I miss something?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

newpath is set by the function drop_from_path.

# The 2nd argument is the variable that the path gets appended to if it is
# not a system path.
#----------------------------------------------------------------------------
function (IF_NOT_SYSTEM_PATH_APPEND path variable)
Copy link
Member

Choose a reason for hiding this comment

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

Is this function ever going to be called with another variable than the default root include path? If yes, fair enough, otherwise I would call it something like BUILD_ROOT_INCLUDE_PATH("${Vc_INCLUDE_DIR}"), and remove the second argument, since any negations in names are hard to parse.

Comment on lines +171 to +175
ROOT_INCLUDE_PATH=@DEFAULT_ROOT_INCLUDE_PATH@
export ROOT_INCLUDE_PATH
else
ROOT_INCLUDE_PATH=@DEFAULT_ROOT_INCLUDE_PATH@:$ROOT_INCLUDE_PATH
export ROOT_INCLUDE_PATH
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
ROOT_INCLUDE_PATH=@DEFAULT_ROOT_INCLUDE_PATH@
export ROOT_INCLUDE_PATH
else
ROOT_INCLUDE_PATH=@DEFAULT_ROOT_INCLUDE_PATH@:$ROOT_INCLUDE_PATH
export ROOT_INCLUDE_PATH
export ROOT_INCLUDE_PATH=@DEFAULT_ROOT_INCLUDE_PATH@
else
export ROOT_INCLUDE_PATH=@DEFAULT_ROOT_INCLUDE_PATH@:$ROOT_INCLUDE_PATH

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For the sake of consistency, I followed the style of all other environment variables in thisroot.sh

@hageboeck
Copy link
Member

@LukasBreitwieser, what happens when you install (and therefore relocate) ROOT? Given that these paths are system paths, things should continue to work, won't they?

ROOT_INCLUDE_PATH=@DEFAULT_ROOT_INCLUDE_PATH@
export ROOT_INCLUDE_PATH
else
ROOT_INCLUDE_PATH=@DEFAULT_ROOT_INCLUDE_PATH@:$ROOT_INCLUDE_PATH
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you consider this an issue if DEFAULT_ROOT_INCLUDE_PATH is empty? Not just here but in the other shell setups?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think this should be an issue. This case is also covered by all GHA runners.

@andresailer
Copy link
Contributor

I am getting an error in the lcg build with this

[100%] Generating tutorials/hsimple.root
root.exe: /build/jenkins/workspace/lcg_nightly_pipeline/build/projects/ROOT-default-root-include-path/src/ROOT/default-root-include-path/interpreter/llvm-project/clang/lib/Serialization/ASTReader.cpp:4332: clang::ASTReader::ASTReadResult clang::ASTReader::ReadModuleMapFileBlock(RecordData&, ModuleFile&, const ModuleFile*, unsigned int): Assertion `M && M->Name == F.ModuleName && "found module with different name"' failed.

https://lcgapp-services.cern.ch/cdash/build/98193/files

@pcanal
Copy link
Member

pcanal commented Jun 27, 2025

What do you practically mean by:

If the library's include path is dynamically modified between build and run time, the configuration can be updated by patching the thisroot.{sh,csh,fish,bat} files.

?

@LukasBreitwieser
Copy link
Contributor Author

Thank you all for your comments!

@hageboeck

@LukasBreitwieser, what happens when you install (and therefore relocate) ROOT? Given that these paths are system paths, things should continue to work, won't they?

Yes this works. Only third party include paths (i.e., include paths outside the root src/build/install directories) should be added. Perhaps a good idea to add additional checks for these conditions.

@pcanal
If the include path (to e.g. Vc) at runtime is different to the one at build time, which might happen for spack installations using its binary cache.
In that case the thisroot.* files must be patched.

@andresailer
Thank you for running the lcg build. Will investigate the failure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants