llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.15k stars 12.03k forks source link

Add a way for clang-tidy to generate depfile #58577

Open kiwixz opened 2 years ago

kiwixz commented 2 years ago

Hello, I'm trying to integrate clang-tidy in my CMake with custom commands to have more control over whats going on.

I wanted to use the depfile feature of CMake for add_custom_command, but after a lot of head-scratching realized that clang-tidy is purposely filtering out any "dependency" flag (starting with M) !

See here for the relevant function.

I think we should add a way to force clang-tidy to honor those flags, or just always allow them because the compile-commands doesn't have those anyway (at least with CMake) ?

NOTE: There is an ugly workaround, --write-dependencies (alias of -MD) is not filtered. So you can make clang-tidy generate a dependency file, but there is no way to specify the output directory nor the main target.

llvmbot commented 2 years ago

@llvm/issue-subscribers-clang-tidy

whisperity commented 2 years ago

Why do you need Clang-Tidy to generate a dependency file? It's not the purpose of the tool, at all. There is clang-scan-deps for such a purpose that is also a "top-level tool" with its own main() and invocation.

have more control over whats going on

Could you please tell us what is the workflow you are trying to achieve? That way, we could suggest the right tools. Are you trying to do an incremental analysis? (So run Clang-Tidy only for files that had changed?)

kiwixz commented 2 years ago

I'm trying to add a target tidy that would run clang-tidy on all changed files akin to a compiler really (incremental analysis like you described). I don't want to use CMake's built-in *_CLANG_TIDY because I want it to be a separate step from compilation.

My current solution is to add a custom_command with a depfile that's generated with clang-tidy. It's pretty simple and I like it, except I have to do some post-processing to change file output (-MF) and target name (-MT).

Running another command beforehand would work for me, even though I don't see the point because I'm really trying to use those flags the way there were meant too, except with clang-tidy as my "compiler". It would also duplicate the preprocessing work (I assume clang-tidy has to do it anyway).

I didn't know about clang-scan-deps, it's interesting because it can generate the depfile with a compile_commands.json. I couldn't find a way to generate only the depfile for one file though, and I am pretty sure that's what CMake expects.

So, I totally agree that generating a depfile is not the purpose of clang-tidy. But it would be very convenient to add the possibility to generate it as a byproduct of the real checking, like it's generated as a byproduct of clang's compilation. The plumbing is already there, we just need to allow it, or maybe add unfiltered long-version aliases to -MF and -MT like we currently have for -MD ?

whisperity commented 2 years ago

Hmm... Okay. It's a bit of an arcane area for me, but I have a hunch that LibTooling (not just Clang-Tidy, but all of LibTooling!) strips out the dep-file related flags because running a tool that would write the dep-file would invalidate the build because the build system then will think that the dependencies changes, simply because you ran a tool.

I still do not see how having dep-files would help your case in figuring out what files are modified and execute Clang-Tidy only for them. This seems like a much higher-level problem that might generally not be supported by CMake in the first place, and might worth a feature request for them.

Until then, however, there are some options. intercept-build and CodeChecker are both tools commonly used for the Clang Static Analyzer (and CodeChecker for Clang-Tidy) for driving the analysis. Both of them are running in a way that they intercept the execution of the compiler and obtain the build command from there (as opposed to using the existing compilation database!), and execute the analysis only for files which were built in one go.

While it looks wonky, you could use CodeChecker check --build "cmake --build . -- -j", which will run CMake which will run some build targets, and these compilations are intercepted and scheduled by CodeChecker, which will drive the Clang-Tidy (and perhaps even CSA) analysis.

As long as you are running multiple binaries, you will run multiple times the preprocessor too. Yes, Clang-Tidy starts with building an AST (so it does semantic analysis, instantiates templates, etc., not just running the preprocessor) but instead of creating a binary from it, it runs the analysis routines.

kiwixz commented 2 years ago

Interesting, I think those would be fairly similar to CMake's built-in clang-tidy support (but with more fancy stuff!). Unfortunately it would not solve my problem: I want to have the test phase separate and independent from the compile phase.

It is indeed an higher level problem, and it's too bad CMake/Ninja do not have a builtin way to work with those dependencies _(anymore, kind of)_. The thing is, dependencies can change and you don't want to have to reconfigure CMake every time, so CMake makes the compiler always regenerate them when compiling a file.

I don't understand why clang-tidy should depend on the presence of a compiler for having an up-to-date depfile when it's very well capable of generating one itself. Also, regenerating one should not trigger a rebuild ? You'd need the actual dependencies inside to change for this.

PiotrZSL commented 1 year ago

This do not work because: appendArgumentsAdjuster(getClangStripDependencyFileAdjuster()); in ClangTool constructor. All Clang-tidy tests pass without this line, to be honest I don't see a reason why this exist, without that you can use clang-tidy directly with "make".