There are various posts about this - but I can't seem to find a definitive answer. Some people are saying it works and others not, and yet others saying its tools / IDEs that are the issue.
So I made as small an example as I could. Here are the two files I have:
[
{
"arguments": [ "gcc", "test.cpp" ],
"directory": "/home/user/development/sandbox/comp_commands",
"file": "test.cpp"
}
]
bool is_it()
{
// no return value - give clang warning
}
Now if I run the command clang-tidy test.cpp
in the same directory as the files I get:
[user] comp_commands$ clang-tidy test.cpp
1 warning generated.
test.cpp:4:1: warning: non-void function does not return a value [clang-diagnostic-return-type]
}
... as expected. However if I change the line in the compile_commands.json directory to:
"directory": ".",
Then I get the output:
[user] comp_commands$ clang-tidy test.cpp
Skipping /home/user/development/sandbox/comp_commands/test.cpp. Compile command not found.
here "MaskRay"s answer suggests this is fine/works. Since I am using no IDE, just clang-tidy directly- it can't be the IDE...
Is it possible to use relative paths in the compile_commands.json file? - I am generating this file via a script and can use either, but I specifically want it to be relative paths.
No, the directory
in compile_commands.json
cannot be relative. It must be absolute to work with clang-tidy
.
The specification
for compile_commands.json
says:
- directory: The working directory of the compilation. All paths specified in the command or file fields must be either absolute or relative to this directory.
That is not very explicit, but as it acknowledges the possibility of
relative paths in other attributes, while saying nothing about a
relative directory
, this is weak evidence that the path must be
absolute.
The code that prints Compile command not found.
is in
ClangTool
::run
:
std::vector<CompileCommand> CompileCommandsForFile =
Compilations.getCompileCommands(File);
if (CompileCommandsForFile.empty()) {
llvm::errs() << "Skipping " << File << ". Compile command not found.\n";
FileSkipped = true;
continue;
}
This is calling JSONCompilationDatabase
::getCompileCommands
,
which consults the MatchTrie
member, which is built in
JSONCompilationDatabase::parse
, and includes these key lines:
if (!Directory) {
ErrorMessage = "Missing key: \"directory\".";
return false;
}
SmallString<8> FileStorage;
StringRef FileName = File->getValue(FileStorage);
SmallString<128> NativeFilePath;
if (llvm::sys::path::is_relative(FileName)) {
SmallString<8> DirectoryStorage;
SmallString<128> AbsolutePath( // (1)
Directory->getValue(DirectoryStorage));
llvm::sys::path::append(AbsolutePath, FileName); // (2)
llvm::sys::path::native(AbsolutePath, NativeFilePath);
} else {
llvm::sys::path::native(FileName, NativeFilePath);
}
Although this code is willing to handle a relative FileName
, the
Directory
value is simply assumed to be absolute at (1), as its value
(as a YAML string) is concatenated with FileName
at (2) and the result
treated as absolute from then on.
When the input file name test.cpp
is passed on the command line,
the tooling infrastructure turns that into the absolute path
/home/user/development/sandbox/comp_commands/test.cpp
, then
compares it as a string (via MatchTrie
) to the path built by the above code,
which will be ./test.cpp
and hence not match.
ccls is a separate project that
happens to also consume the compile_commands.json
format, but with an
extension to allow relative directory
attributes.
That extension is not present in clang-tidy
.