clc: retrieve libclang path at runtime.
What does this MR?
While cross compiling, libclang path is retrieved at runtime using libdl.
Why?
I wanted to use rusticl in an embedded context (on a Khadas Vim3 card). When using clpeak the following error message appeared:
“Build Log: <built-in>:1:10: fatal error: 'opencl-c-base.h' file not found”.
This file is required during a rusticl runtime compilation. In clc_helpers.cpp.
However, the header is not found because its path is wrong. Indeed, when compiling mesa, the variable DLLVM_LIB_DIR
is incorrectly defined. This variable is used at runtime to retrive the headers using the following steps:
- The path to the clang library is created: (src/compiler/clc/clc_helpers.cpp)
auto libclang_path = fs::path(LLVM_LIB_DIR) / "libclang.so";
- The path leading to the header is calculated relative to libclang_path: (src/compiler/clc/clc_helpers.cpp)
auto clang_res_path = fs::path(clang::driver::Driver::GetResourcesPath(libclang_path.string(), CLANG_RESOURCE_DIR)) / "include";
- The path is defined as the directory to the compiler resource files: (src/compiler/clc/clc_helpers.cpp)
c->getHeaderSearchOpts().ResourceDir = clang_res_path.string();
- Depending on LLVM version, the correct header is added to preprocessor includes: (src/compiler/clc/clc_helpers.cpp)
#if LLVM_VERSION_MAJOR >= 15
c->getPreprocessorOpts().Includes.push_back("opencl-c-base.h");
#else
c->getPreprocessorOpts().Includes.push_back("opencl-c.h");
#endif
clang::driver::Driver::GetResourcesPath()
is a function that retrive the libclang resource dir based on a given binary or library. It works by following these steps:
- Retrieve the parent file of the libclang library.
- Adds
CLANG_RESOURCE_DIR
to the path if the variable is non-zero. (This variable allow you to modify the path relative to the library path, it is therefore zero by default.) - Calculate the parent directory.
- Add
lib<CLANG_LIBDIR_SUFFIX>
. - Add “clang”.
- Add Clang version.
// static
std::string Driver::GetResourcesPath(StringRef BinaryPath,
StringRef CustomResourceDir) {
// Since the resource directory is embedded in the module hash, it's important
// that all places that need it call this function, so that they get the
// exact same string ("a/../b/" and "b/" get different hashes, for example).
// Dir is bin/ or lib/, depending on where BinaryPath is.
std::string Dir = std::string(llvm::sys::path::parent_path(BinaryPath));
SmallString<128> P(Dir);
if (CustomResourceDir != "") {
llvm::sys::path::append(P, CustomResourceDir);
} else {
// On Windows, libclang.dll is in bin/.
// On non-Windows, libclang.so/.dylib is in lib/.
// With a static-library build of libclang, LibClangPath will contain the
// path of the embedding binary, which for LLVM binaries will be in bin/.
// ../lib gets us to lib/ in both cases.
P = llvm::sys::path::parent_path(Dir);
llvm::sys::path::append(P, Twine("lib") + CLANG_LIBDIR_SUFFIX, "clang",
CLANG_VERSION_STRING);
}
return std::string(P.str());
}
The opencl-c-base path is therefore calculated relative to the LLVM_LIB_DIR
variable which is an host absolute path. This variable is defined by meson during mesa's compilation and is initialized to llvm_libdir
:
src/compiler/clc/meson.build :
_libclc_cpp_args = ['-DLLVM_LIB_DIR="@0@"'.format(llvm_libdir)]
How does this MR fixes the issue?
llvm_libdir
can't be modified because it is used when cross-compiling on the host machine by the meson.build
at the root of mesa. Moreover, LLVM_LIB_DIR
can't be set to an arbitrary path as we don't know the path of the libclang library on the target.
The solution is to retrieve the libclang path at runtime using libdl. This is done by using the dladdr
function which returns information about a loaded library. The path to the libclang library can therefore be retrieved using one of its functions (e.g. clang::getClangFullVersion
). The dlinfo
function can't be used here as we don't know the name of the libclang library (libclang.so.X
or libclang-cpp.so.X
).
For the moment, only the UNIX version is implemented.
Commit message:
clc: retrieve libclang path at runtime.
LLVM_LIB_DIR
is a variable used for runtime compilations.When cross compiling, LLVM_LIB_DIR
must be set to thelibclang path on the target. So, this path should notbe retrieved during compilation but at runtime.
dladdr uses an address to search for a loaded library.If a library is found, it returns information about it.The path to the libclang library can therefore beretrieved using one of its functions. This is usefulbecause we don't know the name of the libclang library (libclang.so.X
or libclang-cpp.so.X
)
Fixes: e22491c8 ("clc: fetch clang resource dir at runtime")
Signed-off-by: Antoine Coutant antoine.coutant@smile.fr