From 17d385a6232d590ffc5ac11f89a6a8931228f8da Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 4 Jun 2026 20:29:50 +0200 Subject: [PATCH] build: Fix compilation and runtime errors with LLVM 22 This commit fixes compilation and runtime errors of the OSL against specific builds of LLVM 22. When LLVM is compiled with LLVM_LINK_LLVM_DYLIB=OFF (default value) an extra set of libraries needs to be used for Clang: - The clangOptions library is needed because getDriverOptTable() used from clangFrontend was moved from clangDriver to clangOptions. - Similarly, printStats() used from clangSema has been moved to clangAnalysisLifetimeSafety. This linking error could be reproduced when LLVM is compiled with the following options: ``` cmake \ -GNinja \ -DCMAKE_BUILD_TYPE=Release \ -DLLVM_INCLUDE_TESTS=OFF \ -DLLVM_INCLUDE_EXAMPLES=OFF \ -DLLVM_BUILD_LLVM_C_DYLIB=OFF \ -DLLVM_ENABLE_UNWIND_TABLES=OFF \ -DLLVM_ENABLE_ZSTD=OFF \ -DLLVM_ENABLE_ZLIB=OFF \ -DLLVM_ENABLE_PROJECTS=clang \ -DCMAKE_INSTALL_PREFIX=/opt/local/llvm/22.1.7 \ ../llvm ``` A couple of notes: - The linking issue can not be reproduced when using Homebrew's LLVM 22 because it uses LLVM_LINK_LLVM_DYLIB=ON. This seems to be leading to a situation when the linker issue is side-steps because of the symbols that are pulled by the dynamic LLVM library. - Passing LLVM_STATIC does not help with this case, since this flag only affects the way LLVM libraries are handled and does not change the way Clang libraries are handled: `llvm-config --libfiles --link-static` does not print any Clang-related libraries. Since LLVM version 22 the VFS is to be explicitly created for the CompilerInstance. Prior to version 22 this was done implicitly by the LLVM when calling createFileManager(), but now this is no longer the case, and LLVM has an assertion for it. The createVirtualFileSystem() with default arguments solves this problem, and initializes CompilerInstance's VFS the same way how it was done implicitly in the older versions of LLVM. Without this, compilation of OSO triggers an assert() in LLVM: ``` Assertion failed: (VFS && "CompilerInstance needs a VFS for creating FileManager"), function createFileManager, file CompilerInstance.cpp, line 387. ``` It is unclear whether this was causing any actual issue with release builds of LLVM, but it is better to use the API in the way it is expected to be used and create the VFS. Last but not least, this change also fixes the following assert on the LLVM side when running OSL's test suite on macOS: ``` Assertion failed: ((isUIntN(8 * Size, Value) || isIntN(8 * Size, Value)) && "Invalid size"), function emitIntValue, file MCStreamer.cpp, line 135. ``` The value that trips on this assert statement comes from the DW_AT_APPLE_major_runtime_vers that the code in DwarfDebug.cpp, and it comes from the RuntimeVersion (RV) argument of the createCompileUnit(). This runtime value is supposed to indicate Obj-C runtime version which is either 1 or 2 (value 2 is for Objective-C 2.0). Passing OSL version as the runtime version does not fit single byte, and that is why the assertion trips. This change follows Clang's code which sets the runtime version to 0 for non-Objective-C languages. It is unclear what side-effects this change could bring, but it is also a bit strange to use OSL version for things that distinguish system runtime. In order to be able to run OSL regression tests with LLVM compiled in debug mode, LLVM_LINK_LLVM_DYLIB=ON had to be used. Without this, the following assert in the LLVM triggers upon testrender startup: ``` : CommandLine Error: Option 'openmp-ir-builder-optimistic-attributes' registered more than once! LLVM ERROR: inconsistency in registered CommandLine options ``` This is to do with the way how LLVM registers command line arguments. It uses static variable initialization for this, and having LLVM as a static library that is pulled via CLang into both oslcomp and oslexec that are then pulled into testrender causes this situation to happen. For some reason, it does not happen if LLVM is compiled as static but release library. The need of debug versions of OSL and LLVM libraries comes from the need to compile Blender on Windows in Debug mode, and libraries need to be compiled with a different CRT ABI. Tested with the ctest with both LLVM 20 and 22 compiled in release. With all these changes the test suite passes to the same degree for LLVM 20 and 22, both Debug and Release. The only failing tests are related to Python module, and those I did not yet manage to get passing on a local development machine. Signed-off-by: Sergey Sharybin --- src/cmake/modules/FindLLVM.cmake | 3 ++- src/liboslcomp/oslcomp.cpp | 3 +++ src/liboslexec/llvm_util.cpp | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/cmake/modules/FindLLVM.cmake b/src/cmake/modules/FindLLVM.cmake index 2e7e5f589..56809dc3a 100644 --- a/src/cmake/modules/FindLLVM.cmake +++ b/src/cmake/modules/FindLLVM.cmake @@ -119,7 +119,8 @@ endif () foreach (COMPONENT clangFrontend clangDriver clangSerialization clangParse clangSema clangAnalysis clangAST clangASTMatchers clangEdit clangLex - clangSupport clangAPINotes clangBasic) + clangSupport clangAPINotes clangBasic + clangOptions clangAnalysisLifetimeSafety) find_library ( _CLANG_${COMPONENT}_LIBRARY NAMES ${COMPONENT} PATHS ${LLVM_LIB_DIR} diff --git a/src/liboslcomp/oslcomp.cpp b/src/liboslcomp/oslcomp.cpp index f978dd101..b7dedd90e 100644 --- a/src/liboslcomp/oslcomp.cpp +++ b/src/liboslcomp/oslcomp.cpp @@ -200,6 +200,9 @@ OSLCompilerImpl::preprocess_buffer(const std::string& buffer, inst.setTarget(target); +#if OSL_LLVM_VERSION >= 220 + inst.createVirtualFileSystem(); +#endif inst.createFileManager(); #if OSL_LLVM_VERSION >= 220 inst.createSourceManager(); diff --git a/src/liboslexec/llvm_util.cpp b/src/liboslexec/llvm_util.cpp index a6a1e75e0..e293ee651 100644 --- a/src/liboslexec/llvm_util.cpp +++ b/src/liboslexec/llvm_util.cpp @@ -684,7 +684,7 @@ LLVM_Util::debug_setup_compilation_unit(const char* compile_unit_name) osl_identity, // Identify the producer of debugging information and code. Usually this is a compiler version string. true, // isOptimized "", // This string lists command line options. This string is directly embedded in debug info output which may be used by a tool analyzing generated debugging information. - OSL_VERSION, // This indicates runtime version for languages like Objective-C + 0, // This indicates runtime version for languages like Objective-C llvm::StringRef(), // SplitName = he name of the file that we'll split debug info out into. llvm::DICompileUnit::DebugEmissionKind:: LineTablesOnly, // DICompileUnit::DebugEmissionKind