Using clang-tidy with cross compilation

This may be a really silly issue but I’m struggling to get clang-tidy working while cross compiling.

I’m using the RSIC-V GCC toolchain to generate the binaries for a small embedded project I have and as part of the build I want to enable certain static analysis tools such as clang-tidy. I enable the clang-tidy checks using

set(CMAKE_CXX_CLANG_TIDY clang-tidy;-checks=-*,readability-*,performance-*,portability-*)

in my top level CMakeLists.txt. I then run CMake and I get the error from clang-tidy:
error: x86-64 'interrupt' attribute only applies to functions that have only a pointer parameter optionally followed by an integer parameter [clang-diagnostic-error]
for the following code snippet:

__attribute__((interrupt)) void handler() {}

The specifics for this error is that the function signature for x86 differs from that of RISC-V but this just shows that clang-tidy is doing the compilation for my host machine rather than the target architecture.

Have I done anything wrong when setting up clang-tidy to run? Is there a way to get CMake to change the clang compiler target when running clang-tidy?

First you have to use the --target= CLI parameter for clang-tidy.

But that may not be sufficient as the header files are also for your host. You also have to define the include directories. Luckily, CMake already knows these as CMAKE_${lang}_IMPLICIT_INCLUDE_DIRECTORIES.
Before those, somehow clang then also needs its own include directory else I got strange errors (${CLANG_ROOT_DIR}/lib/clang/${CLANG_TIDY_VERSION_STRING}/include). To know CLANG_TIDY_VERSION_STRING, you have to parse clang-tidy --version.

Include directories for clang-tidy can be added using

list ( APPEND CMAKE_${lang}_CLANG_TIDY --extra-arg=-isystem "--extra-arg=${some_include_path}" )

for each directory.

And do yourself a favor and omit the “-checks” CLI parameter. Use a .clang-tidy file instead.

Advantage:

  • clang-tidy integration separated from clang-tidy usage setup
  • per-directory configuration possible
  • IDEs also read that file for use of integrated clang-tidy displaying (e.g. QtCreator, VS 2019)
  • you can actually configure the parameters of those checks
1 Like

Thanks! I managed to get the include paths in a similar way to here using

if(CMAKE_EXPORT_COMPILE_COMMANDS)
    set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
endif()

But I really don’t think this is the best way to do it. I can’t see why CMake wouldn’t be able to pass the include directories for us but maybe there’s some detail I’m missing. Even if it’s not automatic it seems like there’s a cleaner solution than this

The clang-tidy support is pretty ignorant of behaviors of clang-tidy itself AFAIK. Flag manipulation like this needs to be done manually as CMake doesn’t really know how well clang-tidy actually understands the compiler in use (and getting it to understand means that as clang-tidy improves, CMake has to chase it with whatever table is used to track that information).

Yes, there’s also the problem of clang-tidy compatibility between several vs2019/cmake/llvm version combinations which may not be relevant at all for most developers.

Same for this problem of making clang-tidy compatible to a certain gcc-based SDK.

And then there’s also the problem that the code itself needs to be clang-compilable :wink:

Could you please expand on this a little? At least the official distribution of Clang-Tidy v15 doesn’t have the target parameter.

EDIT 2: Oh I think you mean passing it to the clang frontend invoked by clang-tidy via --extra-arg. That worked for me (initially it didn’t because I invoke clang-tidy via execvp and I forgot that the first argument is supposed to be the path to the executable itself).