0

I am using CMake as my build system generator. I want to use spdlog and clang-tidy. I add spdlog to my project_packages like this:

find_package("spdlog" REQUIRED)
target_link_libraries("project_packages" INTERFACE "spdlog::spdlog")

I set up clang-tidy like this:

option("ENABLE_CLANG_TIDY" "Enable static analysis with clang-tidy" ON)

if(ENABLE_CLANG_TIDY)
    find_program("CLANGTIDY" "clang-tidy")
    if(CLANGTIDY)
        set("CMAKE_CXX_CLANG_TIDY" "${CLANGTIDY}")
    else()
        message(SEND_ERROR "clang-tidy requested but executable not found")
    endif()
endif()

I install spdlog with my system package manager sudo pacman -Syu spdlog and can use spdlog in my code. But, when clang-tidy is enabled I get the error:

/usr/include/spdlog/tweakme.h:81:9: error: 'SPDLOG_FMT_EXTERNAL' macro redefined [clang-diagnostic-macro-redefined,-warnings-as-errors]
#define SPDLOG_FMT_EXTERNAL
        ^
note: previous definition is here
101500 warnings generated.
Suppressed 101499 warnings (101499 in non-user code).
Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
1 warning treated as error

I can disable checking for redefinitions or commenting out line 81 in /usr/include/spdlog/tweakme.h, but this is obviously a hack. I want the macro defined and warnings, I just don't care that it is being redefined multiple times by upstream. tweakme.h is where the system config for the library is located.

It appears that the correct way of suppressing a system library warnings generated by clang-tidy using cmake is to be declaring it to be a SYSTEM library.

https://cmake.org/cmake/help/latest/command/target_include_directories.html

If SYSTEM is specified, the compiler will be told the directories are meant as system include directories on some platforms. This may have effects such as suppressing warnings or skipping the contained headers in dependency calculations (see compiler documentation).

clang-tidy does not emit warnings for files when SYSTEM is specified. But I am using target_link_libraries which does not support the SYSTEM keyword. I have not been able to get target_include_directories to work even though it appears to do almost what I want.

Inline way to disable clang-tidy checks only explains how to disable errors for one line, so disabling clang-tidy before including the header and re-enabling clang-tidy after the include doesn't appear possible.

So I need to find a way to tell cmake that the library I am trying to link is a SYSTEM library so clang-tidy will suppress the error. Is this possible to do, or is their another solution that will let my get my program to compile when upstream is triggering warnings.

Here is a minimal example of what I've got so far: https://hastebin.com/share/oxefeworup

starball
  • 20,030
  • 7
  • 43
  • 238
Brandon
  • 456
  • 2
  • 6
  • 19
  • See [ask] for why your [mre] should be in the post itself instead of a link to something like a pastebin. – starball Mar 16 '23 at 19:40
  • what happens if you `target_link_libraries` to `spdlog::spdlog` directly instead of through the `project_packages` interface target? – starball Mar 17 '23 at 17:57
  • @user, `target_link_libraries("app" LINK_PUBLIC "project_core" "spdlog::spdlog")` gives the same result as linking through `project_packages`. Using the Conan package manager I am able to get the library to play nice with clang-tidy. I will likely end up using this method as it also doesn't require the library installed on the system. It would still be nice to know what CMake is doing – Brandon Mar 17 '23 at 18:59

1 Answers1

2

I don't think you need to do anything for targets added by find_package, which are/should be specified as IMPORTED. IMPORTED targets are SYSTEM by default.

For non-imported targets if your project's cmake_minimum_required(VERSION ...) is v3.25, use the SYSTEM target property (set_property(TARGET spdlog PROPERTY SYSTEM TRUE)) (and for FetchContent and add_subdirectory dependencies in particular, see Is there a way to get -isystem for FetchContent targets? (TL;DR use the SYSTEM argument). For CMake 2.34 and below, use a workaround to move the target's INTERFACE_INCLUDE_DIRECTORIES to its INTERFACE_SYSTEM_INCLUDE_DIRECTORIES described the previous linked Q&A.

starball
  • 20,030
  • 7
  • 43
  • 238
  • I tried wrapping the library in a new library target, then setting the SYSTEM property: https://hastebin.com/share/muhipuwebe it did not work, but the documentation reads like it is possible to make libraries installed on the system marked as SYSTEM. – Brandon Mar 16 '23 at 20:19
  • I wounder why clang-tidy is checking the file, it doesn't check other system libraries I include – Brandon Mar 17 '23 at 09:38
  • Following this answer: https://stackoverflow.com/a/64139281/1356754 I came up with the following code which solves the problem: `find_package("spdlog" REQUIRED)`↲ `add_library("abc" INTERFACE)`↲ `get_target_property("xyz_IID" "spdlog::spdlog" INTERFACE_INCLUDE_DIRECTORIES)`↲ `set_target_properties("abc" PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${xyz_IID}")`↲ `target_link_libraries("project_packages" INTERFACE "abc")` – Brandon Mar 17 '23 at 19:34
  • @Brandon If you want, feel free to edit the specific solution you found into this answer post. – starball Mar 17 '23 at 19:38