Solvedccls ccls c++ header completion on osx

OS: macOS Mojave 10.14.2
emacs: 26.1
Spacemacs: develop
Problem: header file can't be completed correctly

And ccls reported error on string and vector even if the correct header file is included

.ccls content:
%c -std=gnu11
%cpp -std=c++11
%cpp -stdlib=libc++

cmake_minimum_required(VERSION 3.13)
add_executable(test_ccls main.cpp)

I have generated and linked the compile_commands.json file.
Solutions mentioned in #125 and #160 seem not work here.
Solutions in wiki also don't work.

39 Answers

✔️Accepted Answer

@alxiong thanks for your comment, it works. I am using neovim with coc.nvim on macOS Catalina, here is my coc-settings.json for anyone who might need

    "languageserver": {
        "ccls": {
            "command": "ccls",
            "filetypes": ["c", "cpp", "objc", "objcpp"],
            "rootPatterns": [".ccls", "compile_commands.json", ".vim/", ".git/", ".hg/"],
            "initializationOptions": {
                "cache": {
                    "directory": "/tmp/ccls"
                // see
                "clang": {
                    // from clang -v -fsyntax-only -x c++ /dev/null
                    "extraArgs": [
                    //From clang -print-resource-dir
                    "resourceDir": "/Applications/"

Other Answers:

@randy3k thanks for your reply, I have resolve my issue, for future reference, I use emacs, thus the following config:

  1. clang -v -fsyntax-only -x c++ /dev/null
    will output a list of paths/header folders clang would look for. (I assume that there are so many of them because OSX update also changes the location of many of these header files, thus to keep backward compatibility, Apple Clang would just scan through all possible paths)
    p.s. without including all of these paths in extraArgs, some macros such as size_t might not be found
    They are all over the place!! 😅

  2. clang -print-resource-dir
    will give another initialization options (I'm not personally sure this config has any effect, but I followed this faq)

  3. configure my emacs:

(after! ccls
  (setq ccls-initialization-options
        '(:clang (:extraArgs ["-isystem/Library/Developer/CommandLineTools/usr/include/c++/v1"
                  :resourceDir "/Applications/")))


This was always an issue with clang < 8 on Mac OS X. The work around is to pass -isystem /Library/Developer/CommandLineTools/usr/include/c++/v1, either through clang.extraArgs or .ccls.

It was actually a clangDriver issue (fixed in clang 8), but the ccls 0.20181225.* release was also at fault (the "Extend .ccls ..." commit ( broke the clang.extraArgs workaround; -isystem ... in .ccls still works) I've fixed clang.extraArgs and pushed a new release

To make header completion work with clang < 8 on Mac OS X, use a shell script wrapper:

exec /path/to/ccls/Release/ccls -init='{"clang":{"extraArgs":["-isystem", "/Library/Developer/CommandLineTools/usr/include/c++/v1"]}}' "$@"

When clang < 8 (I use clang trunk personally so this configuration gets less testing), the header completion backends is GetSearchDirs leverages clangDriver to get system and user search directories.
On Mac OS X 10.9+, libc++ is the default C++ stdlib implementation. The system libc++ search directory, however, was weirdly computed from -resource-dir in InitHeaderSearch (not run in clangDriver, thus -ccc-install-dir has no use) before rC348365. The results weren't available in clangDriver, thus the missing completion items.

Before rC348365 (will be included in clang 8 but not in clang 7) the libc++ directory (xxx/include/c++/v1) was inferred from -resource-dir.

--- a/lib/Frontend/InitHeaderSearch.cpp
+++ b/lib/Frontend/InitHeaderSearch.cpp
@@ -476,22 +476,6 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang,
   if (Lang.CPlusPlus && !Lang.AsmPreprocessor &&
       HSOpts.UseStandardCXXIncludes && HSOpts.UseStandardSystemIncludes) {
     if (HSOpts.UseLibcxx) {
-      if (triple.isOSDarwin()) {
-        // On Darwin, libc++ may be installed alongside the compiler in
-        // include/c++/v1.
-        if (!HSOpts.ResourceDir.empty()) {
-          // Remove version from foo/lib/clang/version
-          StringRef NoVer = llvm::sys::path::parent_path(HSOpts.ResourceDir);
-          // Remove clang from foo/lib/clang
-          StringRef Lib = llvm::sys::path::parent_path(NoVer);
-          // Remove lib from foo/lib
-          SmallString<128> P = llvm::sys::path::parent_path(Lib);
-          // Get foo/include/c++/v1
-          llvm::sys::path::append(P, "include", "c++", "v1");
-          AddUnmappedPath(P, CXXSystem, false);
-        }
-      }

Thanks to @LeadroyaL for letting me explore his environment. Recorded here for future reference:

  • CMAKE_CXX_COMPILER:FILEPATH=/Library/Developer/CommandLineTools/usr/bin/c++
  • -resource-dir: /Library/Developer/CommandLineTools/usr/lib/clang/10.0.0
  • libc++ search directory: /Library/Developer/CommandLineTools/usr/include/c++/v1
bash-3.2$ grep CMAKE_CXX_COMOMPILER ccls/Release/CMakeCache.txt
bash-3.2$ /Library/Developer/CommandLineTools/usr/bin/c++ -print-resource-dir
# /usr/bin/clang looks like a wrapper
bash-3.2$ /usr/bin/clang -print-resource-dir

## It should also work with a custom clang
bash-3.2$ /Users/leadroyal/pllvm/r/bin/clang -print-resource-dir
# set clang.extraArgs to -isystem /Users/leadroyal/pllvm/r/include/c++/v1

If I understand correctly, the above implies that the workaround -isystem/Library/Developer/CommandLineTools/usr/include/c++/v1 is only needed for clang <v0.8. However, for some reasons, I still need it with clang v11.0 and macOS Catalina. Otherwise, the header files such as stdio.h and string.h would not be found.

cc: @MaskRay

More Issues: