Heres my compile_commands.json :
{ "directory": "/data/data/com.termux/files/home/cpulator", "file": "allocator.cc", "output": "allocator.o", "arguments": ["/data/data/com.termux/files/usr/bin/clang-16", "-xc++", "--sysroot=/data/data/com.termux/files", "events.cc", "-o", "events.o", "--target=arm-altera-eabi", "-nostdlib", "-Wall", "-Wextra", "-Wpedantic", "-c", "-O0", "-gdwarf-4", "-fno-exceptions", "-fno-rtti", "-fno-inline", "--target=armv4t-altera-unknown-eabi"]}
When I run clang-tidy allocator.cc
, it acts as if it cant detect the compile_commands.json file.
Error message:
Error while trying to load a compilation database:
Could not auto-detect compilation database from directory "/data/data/com.termux/files/home/cpulator"
No compilation database found in /data/data/com.termux/files/home/cpulator or any parent directory
fixed-compilation-database: Error while opening fixed database: No such file or directory
json-compilation-database: Expected array.
How do I fix this?
The error message:
json-compilation-database: Expected array.
comes from JSONCompilationDatabase.cpp
:
bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
llvm::yaml::document_iterator I = YAMLStream.begin();
if (I == YAMLStream.end()) {
ErrorMessage = "Error while parsing YAML.";
return false;
}
llvm::yaml::Node *Root = I->getRoot();
if (!Root) {
ErrorMessage = "Error while parsing YAML.";
return false;
}
auto *Array = dyn_cast<llvm::yaml::SequenceNode>(Root);
if (!Array) {
ErrorMessage = "Expected array."; // <-------------------
return false;
}
It means the compilation_database.json
file was found, but did not begin with the required square bracket character [
.
compile_commands.json
The documentation of the compile_commands.json
format explains (emphasis mine):
A compilation database is a JSON file, which consist of an array of “command objects” ...
To fix your compile_commands.json
file, simply insert [
at the start and ]
at the end.
-MJ
?One possible reason you have a compile_commands.json
without brackets is you used the clang -MJ
option:
-MJ<arg>
Write a compilation database entry per input
Notice it says "entry"; that means the output is just one element of the array that compile_commands.json
is supposed to contain. It is therefore incorrect to use it to directly create that file:
$ clang -MJcompile_commands.json ... # WRONG!
What you have to do instead is write each file's entry to its own file, then put them all together afterward. For example, in one of my Makefile
s I have something like (this is an untested simplified fragment):
%.o: %.cc
$(CXX) -c -o $@ $< -MJ$@.json
which creates foo.o.json
(and foo.o
) for every foo.cc
file compiled. Then I have another rule (this one is tested):
compile_commands.json:
(echo "["; cat *.o.json; echo "]") > $@
that I just run manually when needed.
This isn't a particularly good solution due to requiring manual invocation of a rule, it's just meant to illustrate the requirement to assemble a properly-formed compile_commands.json
from the fragments produced by -MJ
.
cmake
cmake
3.5 or later has the CMAKE_EXPORT_COMPILE_COMMANDS
variable that will take care of assembling a properly-formatted file without additional intervention.
(It is not my intention to recommend cmake
here, I'm just noting that, for this task, cmake
has a good solution.)