-
Notifications
You must be signed in to change notification settings - Fork 259
Project Setup
ccls typically indexes an entire project. In order for this to work properly,
ccls
needs to be able to obtain the source file list and their compilation
command lines.
There are two main ways this happens:
- Provide
compile_commands.json
at the project root - Provide
.ccls
. It is a line-based text file describing compiler flags. Recursively listed source files (headers excluded) will be indexed.
If neither exists, then when ccls starts it will not index anything: instead it will wait for LSP clients to open files and index only those files.
Guillaume Papin(@Sarcasm) has a thorough article about compilation databases.
Generally this file is not checked into source control, but rather is
generated by the build system. This means it's best to generate it in a new
project before starting the ccls
server in that project.
Because this file is auto-generated it's not easy to customize. As a result
it's possible to provide both compile_commands.json
and .ccls
in the
same project and have the .ccls
configuration enhance the options from
compile_commands.json
.
If your compile_commands.json
is not kept in the project root, set the
initialization option compilationDatabaseDirectory
to an alternative
directory containing compile_commands.json
.
% cmake -H. -BDebug -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=YES
% ln -s Debug/compile_commands.json
Caveat on Windows: CMake dumps Windows shell command line directly into command
, depends on how ccls was built, it may confuse this field as command line from a POSIX shell, in which Windows path separator '\' is a escape character. You can use jq to convert such entries to use arguments
which does not have this issue:
jq '[.[] | {directory: .directory, file: .file, arguments: .command | split(" ") | map(select(length > 0)) | map(sub("\\\\\""; "\""; "g"))}]' < compile_commands.json
Bear is a tool that generates a compilation database for clang tooling. It can be used for any project based on Makefile
.
bear make
# generates compile_commands.json
scan-build is a python package that can generate a compilation database for clang tooling (uses Bear as a backend). This too can be used for any project based on a Makefile
.
intercept-build make all # generates compile_commands.json from the `make all` ruleset
# Format: ninja -t compdb rule_names... > compile_commands.json
ninja -C out/Release -t compdb cxx cc > compile_commands.json
Load the clang_compilation_database
tool in your wscript:
def configure(conf):
conf.load('clang_compilation_database')
./waf configure build
ln -s build/compile_commands.json
buck build :helloworld#compilation-database
ln -s $(buck targets --show-output :helloworld#compilation-database | cut -d ' ' -f 2)
You may use the initialization option "compilationDatabaseCommand"
to provide the JSON compilation database. ccls will read its stdout rather than read compile_commands.json
. This may be useful when ccls cannot parse the compile_commands.json
correctly (e.g. MSVC cl.exe, Intel C++ Compiler options)
# extra command line option
'--init={"compilationDatabaseCommand":"mycompdb"}'
(setq ccls-initialization-options '(:compilationDatabaseCommand "mycompdb"))
Suppose the project is at /tmp/c
, mycompdb /tmp/c
will be executed with stdin=initializationOptions and the stdout should be a JSON compilation database.
You may use this shell script as a starting point:
#!/bin/zsh
# mycompdb /tmp/c
cat >> /tmp/initialization-options
cat <<e
[ { "arguments": [ "c++", "a.o", "a.cc" ],
"directory": "/tmp/c", "file": "a.cc" } ]
e
An example to scrub Intel C++ Compiler options (or, even easier, check out clang.excludeArgs
in the Initialization options):
#!/usr/bin/env python3
import json
import os
import sys
with open(os.path.join(sys.argv[1], 'compile_commands.json')) as f:
db = json.load(f)
for entry in db:
args = entry['arguments']
try:
# Intel C++ Compiler option that is unknown to clang
args.remove('-xHost')
except ValueError:
pass
json.dump(db, sys.stdout)
.ccls
is a line-based text file at the project root. It's main function is
to specify compiler flags needed to properly index your code: -I
-D
etc.
Each line consists of one argument. No whitespace splitting is performed on the
argument, thus -I foo
cannot be used (use -Ifoo
or -I\nfoo
).
Subdirectories of the project can also contain .ccls
files, if needed, to
specify compiler flags specific to those directories.
A line may start with zero or more %
directives.
Available directives include:
By default .ccls
specify compiler flags of files not listed in
compile_commands.json
. If this directive appears first in .ccls
then after
compile_commands.json
is parsed, the rest lines of .ccls
will be appended
to the compiler flags.
This argument should be added only when parsing C (%c
), C++ (%cpp
),
Objective-C (%objective-c
), or Objective-C++ (%objective-c++
) files.
This argument should be added only when indexing C header files (%h
: *.h
) or C++
header files (%hpp
: *.hh
*.hpp
). Note, *.h
files are considered as C, not C++.
You may add a line %h -x c++-header
to make every *.h
parsed as C++.
Note, if your project has both C and C++ files, a.h
's flags may be inferred from a C file and thus parsed as C.
You may run into parsing errors like unknown type name 'class'
.
The compiler driver (the first line unless %compile_commands.json
is used) can usually just be clang
.
clang++
is usually unnecessary, and incorrect if some files are C.
Note that clang a.cc
and clang++ a.cc
are different, but the difference is only related to linking (what default runtime libraries are passed) and is not relevant for the frontend actions ccls performs.
clang
%c -std=c11
%cpp -std=c++2a
%h %hpp --include=Global.h
-Iinc
-DMACRO
*.h *.hh *.hpp
files will be parsed with extra --include=Global.h
%compile_commands.json
%c -std=c11
%cpp -std=c++14
%c %cpp -pthread
%h %hpp --include=Global.h
-Iinc
It appends flags so clang
should not be used.
See https://github.com/MaskRay/ccls/issues/107.
If the compiler driver is a GCC cross-compiler, --target=
may be required. Suppose arm-linux-gnueabi-gcc -march=armv7a
is used, add a --target=
:
%compile_commands.json
--target=armv7a-linux-gnueabi
Otherwise clang will error: unknown target CPU 'armv7a'
.
wget 'https://git.archlinux.org/svntogit/packages.git/plain/trunk/config?h=packages/linux' -O .config
yes '' | make config
bear make -j bzImage modules
ccls -index ~/Dev/Linux -init='{"clang":{"excludeArgs":[
"-falign-jumps=1","-falign-loops=1","-fconserve-stack","-fmerge-constants","-fno-code-hoisting","-fno-schedule-insns","-fno-sched-pressure","-fno-var-tracking-assignments","-fsched-pressure",
"-mhard-float","-mindirect-branch-register","-mindirect-branch=thunk-inline","-mpreferred-stack-boundary=2","-mpreferred-stack-boundary=3","-mpreferred-stack-boundary=4","-mrecord-mcount","-mindirect-branch=thunk-extern","-mno-fp-ret-in-387","-mskip-rax-setup",
"--param=allow-store-data-races=0","-Wa,arch/x86/kernel/macros.s","-Wa,-"
], "extraArgs":["--gcc-toolchain=/usr"]}}'
mkdir Debug; cd Debug
../configure --enable-optimize=no --enable-debug --prefix=~/.local/stow/musl
bear make -j
cd ..; ln -s Debug/compile_commands.json