IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Keeping pace with LLVM: compatibility strategies

    MaskRay发表于 2024-11-10 02:04:13
    love 0

    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_MAJORmacro. 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
    2
    3
    4
    5
    6
    #if LLVM_VERSION_MAJOR < 8
    // D52783 Lift VFS from clang to llvm
    namespace llvm {
    namespace vfs = clang::vfs;
    }
    #endif

    In Mar 2019, https://reviews.llvm.org/D59377 removed the membervariable VirtualFileSystem and removedsetVirtualFileSystem. I added

    1
    2
    3
    4
    5
    6
    #if LLVM_VERSION_MAJOR >= 9 // rC357037
    Clang->createFileManager(FS);
    #else
    Clang->setVirtualFileSystem(FS);
    Clang->createFileManager();
    #endif

    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
    #if LLVM_VERSION_MAJOR < 12 // llvmorg-12-init-5498-g257b29715bb
    driver::Driver d(args[0], llvm::sys::getDefaultTargetTriple(), *diags, vfs);
    #else
    driver::Driver d(args[0], llvm::sys::getDefaultTargetTriple(), *diags, "ccls", vfs);
    #endif

    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
    7
    std::unique_ptr<llvm::MemoryBuffer> buf =
    llvm::MemoryBuffer::getMemBuffer(content);
    #if LLVM_VERSION_MAJOR >= 12 // llvmorg-12-init-11522-g4c55c3b66de
    auto bounds = ComputePreambleBounds(*ci.getLangOpts(), *buf, 0);
    #else
    auto bounds = ComputePreambleBounds(*ci.getLangOpts(), buf.get(), 0);
    #endif

    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
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
      void ProcessOverloadCandidates(Sema &s, unsigned currentArg,
    OverloadCandidate *candidates,
    unsigned numCandidates
    #if LLVM_VERSION_MAJOR >= 8
    ,
    SourceLocation openParLoc
    #endif
    #if LLVM_VERSION_MAJOR >= 14
    ,
    bool braced
    #endif
    ) override {

    In late 2022 and early 2023, there were many changes to migrate fromllvm::Optional to std::optional.

    1
    2
    3
    4
    5
    6
    7
    8
    #if LLVM_VERSION_MAJOR >= 16 // llvmorg-16-init-12589-ge748db0f7f09
    std::array<std::optional<StringRef>, 3>
    #else
    std::array<Optional<StringRef>, 3>
    #endif
    redir{StringRef(stdinPath), StringRef(path), StringRef()}; 0 ref
    std::vector<StringRef> args{g_config->compilationDatabaseCommand, root}; 0 ref
    if (sys::ExecuteAndWait(args[0], args, {}, redir, 0, 0, &err_msg) < 0) {

    In Dec 2022, https://reviews.llvm.org/D137838 added a new LLVMlibrary LLVMTargetParser. I adjusted ccls's CMakeLists.txt:

    1
    2
    3
    4
    target_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
    #if LLVM_VERSION_MAJOR >= 18
    ci->getLangOpts().SpellChecking = false;
    ci->getLangOpts().RecoveryAST = true;
    ci->getLangOpts().RecoveryASTType = true;
    #else
    ci->getLangOpts()->SpellChecking = false;
    #if LLVM_VERSION_MAJOR >= 11
    ci->getLangOpts()->RecoveryAST = true;
    ci->getLangOpts()->RecoveryASTType = true;
    #endif
    #endif

    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
    2
    3
    4
    #if LLVM_VERSION_MAJOR >= 19
    #define startswith starts_with
    #define endswith ends_with
    #endif

    It's important to note that the converse approach

    1
    2
    #define starts_with startswith
    #define ends_with endswith

    could break code that callsstd::string_view::starts_with.

    LLVM C API

    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:

    • Firstdraft: replace libclang indexer with clangIndex
    • UseClang C++ for completion and diagnostics


沪ICP备19023445号-2号
友情链接