Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to suppress Clang warnings in third-party library header file in CMakeLists.txt file?

I'm currently trying to setup a project that will make use of multiple compilers (including Clang, MSVC, and GCC) using Visual Studio 2019's new CMake functionalities (notably using Clang and Ninja in conjunction with CMake and VS2019).

I'm using CMake to configure the project to be "compiler-agnostic", so that I don't need to edit the code itself to handle different compilers via pre-processor instructions or #pragma instructions.

This project needs to be configured to have a high warning level (/W4 for MSVC, -Wall, -Wextra, and -Wpedantic for Clang), and must treat warnings as errors.

I don't have any issues when it comes to configuring the MSVC portion of the project. A lot of these settings have "sane" defaults that "just work" as I'd expect them to. When it comes to Clang, however, I've encountered a problem:

I can't seem to disable warnings for third-party library header files. I'm currently using the Dear Imgui and SFML libraries. Since Dear Imgui isn't pre-compiled, I simply do the following in my CMakeLists.txt file to include it:

include_directories(
    ${CMAKE_CURRENT_SOURCE_DIR}/libs/imgui
)

I use the statically linked version of SFML, so I do the following to include it:

# Find SFML and link statically to it.
# Note: We need to set the SFML_DIR variable manually.
set(SFML_STATIC_LIBRARIES TRUE)
set(SFML_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libs/SFML-2.5.1/lib/cmake/SFML")
find_package(SFML 2.5.1 COMPONENTS system audio window graphics REQUIRED)

target_link_libraries(${PROJECT_NAME}
    PRIVATE
        sfml-system
        sfml-audio
        sfml-window
        sfml-graphics
)

Sadly, SFML doesn't currently follow the current CMake standard way of adding libraries, so it's kind of weird to work with or configure it via CMake.

Now, the above works just fine when it comes to including the libraries in my project (but it might be something I need to change, so I've included it in the post). The problems come when I try to impose the warnings and warnings-as-errors configurations to them when using Clang.

Here are the parts of my CMakeLists.txt file which handle Clang and my C++ configurations:

# Set project to use C++ 17 standard.
set_target_properties(
    ${PROJECT_NAME}
    PROPERTIES
    CXX_STANDARD 17
    CXX_STANDARD_REQUIRED ON
)


target_compile_options(${PROJECT_NAME} PRIVATE
    # All warnings, warnings as errors, be pedantic.
    -Wall
    -Wextra
    -Werror
    -Wpedantic

    # Disable warnings about C++98 incompatibility. We're using C++17 features...
    -Wno-c++98-compat
    -Wno-c++98-compat-pedantic
)

Using the above configuration results in hundreds of warnings/errors in Dear Imgui's source files (due to the usage of "old-school" C++/C-style code), as well as a whole bunch of them in SFML's own source files and header files.

I've been looking for ways to get around this for nearly a week, before settling on the following solution (which doesn't entirely work, more on that later):

set(LIBS_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/libs")
set(IMGUI_FOLDER "${LIBS_FOLDER}/imgui")
set(SFML_FOLDER "${LIBS_FOLDER}/SFML-2.5.1/include/SFML")

file(GLOB LIBRARY_FILES
    # Dear-imgui
    "${IMGUI_FOLDER}/*.cpp"
    "${IMGUI_FOLDER}/misc/freetype/*.cpp"
    "${IMGUI_FOLDER}/misc/fonts/*.cpp"
    "${IMGUI_FOLDER}/misc/cpp/*.cpp"

    # SFML
    "${SFML_FOLDER}/Audio/*.cpp"
    "${SFML_FOLDER}/Graphics/*.cpp"
    "${SFML_FOLDER}/Network/*.cpp"
    "${SFML_FOLDER}/System/*.cpp"
    "${SFML_FOLDER}/Window/*.cpp"
)

set_source_files_properties(
    ${LIBRARY_FILES}
    PROPERTIES
    COMPILE_FLAGS
    "-Wno-everything"
)

I begin by GLOB-ing my library source files (NOTE: I know GLOB is usually looked down upon, but I felt like using it with third-party library files was fine since they're not supposed to change anyway). I then pass them to the set_source_files_properties function to apply the -Wno-everything flag, which seems to properly suppress all errors and warnings from those files.

Everything seems to work just fine, except for one warning which I can't seem to disable without using a #pragma instruction in my code (which I want to avoid). When compiling an empty main function that includes SFML headers, I get warnings about their .hpp files (which can't be passed to the set_source_files_properties function).

This:

#include <SFML/Graphics.hpp>

int main()
{
}

Results in the following warnings/errors:

zero as null pointer constant [-Werror,-Wzero-as-null-pointer-constant]
declaration is marked with '\deprecated' command but does not have a deprecation attribute [-Werror,-Wdocumentation-deprecated-sync]
declaration is marked with '\deprecated' command but does not have a deprecation attribute [-Werror,-Wdocumentation-deprecated-sync]
declaration is marked with '\deprecated' command but does not have a deprecation attribute [-Werror,-Wdocumentation-deprecated-sync]

In these respective SFML files:

ThreadLocal.hpp (57)
Keyboard.hpp (161)
Event.hpp (105)
PrimitiveType.hpp (52)

Other things I've tried that didn't work:

  • Putting the .h/.hpp files in the set_source_files_properties CMake function (alongside the .cpp files). Works for Dear Imgui, but all its errors were in .cpp files, not its headers. Doesn't work for SFML's headers.
  • (Not for SFML, but for Dear Imgui) Including the directories as SYSTEM includes to suppress the warnings. Doesn't appear to work on Windows. Can't really do this with SFML, since I'm using CMake's find_package function instead of doing everything manually.
  • Using #pragma instructions. While this worked, every SFML file has dozens of different errors, and I want to avoid using #pragmas everywhere (or wrapping SFML's headers in my own headers that just wrap the #include instruction in #pragmas).

Is it even possible to suppress these warnings for my library headers without #pragmas? I've never really used Clang before, so apologies if this seems like a simple question, but searching online hasn't really given me anything that would work:

  • Outside of a commandline (I'm using Visual Studio with CMake).
  • On Windows (the system flag doesn't seem to work with this setup).
  • That would work with CMake specifically.
like image 230
micka190 Avatar asked Jun 21 '19 16:06

micka190


People also ask

How do I ignore a warning on Cmake?

Use -Wno-dev to suppress it. You can disable the warning like this when you are configuring your build.

How do I turn off warnings in GCC?

To suppress this warning use the unused attribute (see Variable Attributes). This warning is also enabled by -Wunused , which is enabled by -Wall . Warn whenever a static function is declared but not defined or a non-inline static function is unused.


1 Answers

You can mark the include paths as SYSTEM. Most compilers will not report warnings in system headers. In your case that might look something like this:

include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/libs/imgui)

set_target_properties(sfml-system PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:sfml-system,INTERFACE_INCLUDE_DIRECTORIES>)
set_target_properties(sfml-audio PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:sfml-audio,INTERFACE_INCLUDE_DIRECTORIES>)
set_target_properties(sfml-window PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:sfml-window,INTERFACE_INCLUDE_DIRECTORIES>)
set_target_properties(sfml-graphics PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:sfml-graphics,INTERFACE_INCLUDE_DIRECTORIES>)

For example, this dummy project:

project(example)
cmake_minimum_required(VERSION 3.18)

add_library(dep INTERFACE)
target_include_directories(dep INTERFACE include)
file(WRITE include/header.h "static int a;")

add_library(lib STATIC lib.c)
target_link_libraries(lib PRIVATE dep)
target_compile_options(lib PRIVATE -Wunused -Werror)
file(WRITE lib.c "#include <header.h>")

Fails with:

$ cmake . && make
include/header.h:1:12: error: ‘a’ defined but not used [-Werror=unused-variable]

But after adding this line:

set_target_properties(dep PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:dep,INTERFACE_INCLUDE_DIRECTORIES>)

It builds with no errors.

like image 183
Etienne Laurin Avatar answered Nov 09 '22 06:11

Etienne Laurin