LLVM's C++ API doesn't offer a stability guarantee. This meansfunction signatures can change or be removed between versions, forcingprojects to adapt.
On the other hand, LLVM has an extensive API surface. When a librarylike llvm/lib/Y
relies functionality from another library,the API is often exported in header files underllvm/include/llvm/X/
, even if it is not intended to beuser-facing.
To be compatible with multiple LLVM versions, many projects rely on#if
directives based on the LLVM_VERSION_MAJOR
macro. This post explores the specific techniques used by ccls to ensurecompatibility with LLVM versions 7 to 19.
Given the tight coupling between LLVM and Clang, theLLVM_VERSION_MAJOR
macro can be used for both versiondetection. There's no need to checkCLANG_VERSION_MAJOR
.
This post explores the specific techniques used by ccls to maintaincompatibility with LLVM versions 7 to 19. For the latest release,support for LLVM versions 7 to 9 has been discontinued.
In Oct 2018, https://reviews.llvm.org/D52783 moved the namespaceclang::vfs
to llvm::vfs
. To remaincompatibility, I renamed clang::vfs
uses and added anamespace alias:
1 |
|
In Mar 2019, https://reviews.llvm.org/D59377 removed the membervariable VirtualFileSystem
and removedsetVirtualFileSystem
. I added 1
2
3
4
5
6
Clang->createFileManager(FS);
Clang->setVirtualFileSystem(FS);
Clang->createFileManager();
In April 2020, the LLVM monorepo integrated a new subproject: flang.flang developers made many changes to clangDriver to reuse it for flang.https://reviews.llvm.org/D86089 changed the constructorclang::driver::Driver
. I added 1
2
3
4
5
driver::Driver d(args[0], llvm::sys::getDefaultTargetTriple(), *diags, vfs);
driver::Driver d(args[0], llvm::sys::getDefaultTargetTriple(), *diags, "ccls", vfs);
In November 2020, https://reviews.llvm.org/D90890 changed an argument ofComputePreambleBounds
fromconst llvm::MemoryBuffer *Buffer
toconst llvm::MemoryBufferRef &Buffer
. 1
2
3
4
5
6
7std::unique_ptr<llvm::MemoryBuffer> buf =
llvm::MemoryBuffer::getMemBuffer(content);
auto bounds = ComputePreambleBounds(*ci.getLangOpts(), *buf, 0);
auto bounds = ComputePreambleBounds(*ci.getLangOpts(), buf.get(), 0);
https://reviews.llvm.org/D91297 made a similar changeand I adapted it similarly.
In Jan 2022, https://reviews.llvm.org/D116317 added a new parameterbool Braced
toCodeCompleteConsumer::ProcessOverloadCandidates
.
1 | void ProcessOverloadCandidates(Sema &s, unsigned currentArg, |
In late 2022 and early 2023, there were many changes to migrate fromllvm::Optional
to std::optional
.
1 |
|
In Dec 2022, https://reviews.llvm.org/D137838 added a new LLVMlibrary LLVMTargetParser. I adjusted ccls's CMakeLists.txt
:1
2
3
4target_link_libraries(ccls PRIVATE LLVMOption LLVMSupport)
if(LLVM_VERSION_MAJOR GREATER_EQUAL 16) # llvmorg-16-init-15123-gf09cf34d0062
target_link_libraries(ccls PRIVATE LLVMTargetParser)
endif()
In Sep 2023, https://github.com/llvm/llvm-project/pull/65647 changedCompilerInvocationRefBase
toCompilerInvocationBase
. I duplicated the code with.
. 1
2
3
4
5
6
7
8
9
10
11
ci->getLangOpts().SpellChecking = false;
ci->getLangOpts().RecoveryAST = true;
ci->getLangOpts().RecoveryASTType = true;
ci->getLangOpts()->SpellChecking = false;
ci->getLangOpts()->RecoveryAST = true;
ci->getLangOpts()->RecoveryASTType = true;
In April 2024, https://github.com/llvm/llvm-project/pull/89548/ removedllvm::StringRef::startswith
in favor ofstarts_with
. starts_with
has been available since Oct 2022 andstartswith
had been deprecated. I added the followingsnippet:
1 |
It's important to note that the converse approach 1
2
could break code that callsstd::string_view::starts_with
.
While LLVM offers a C API with an effort made towards compatibility,its capabilities often fall short.
Clang provides a C API called libclang. Whilehighly stable, libclang's limited functionality makes it unsuitable formany tasks.
In 2018, when creating ccls (a fork of cquery), I encounteredmultiple limitations in libclang's ability to handle code completion andindexing. This led to rewriting the relevant code to leverage the ClangC++ API for a more comprehensive solution. The following commits offerinsights into how the C API and the mostly equivalent but better C++ APIworks: