CMake: set warning flags for my project, but not included headers - c++

I am building a project that includes llvm.
I want to enable warnings for my code, but ignore warnings from code in llvm headers.
I have a source file like:
// main.cpp
#include <llvm/IR/Instructions.h>
void foo() {
// blah blah blah
}
and a CMake file like:
add_executable(prog main.cpp)
target_link_libraries(prog ${llvm_libs})
target_compile_options(prog PRIVATE "-Weverything")
But the -Weverything produces a huge number of warnings in the included llvm files, when I only care about seeing warnings in my own code.
How can I enable warnings for my code, without also seeing warnings for the included llvm headers?

You need to correctly configure include dirs in your CMake file. Something like this should do the trick:
target_include_directories(prog <your project-specific include dirs>)
target_include_directories(prog SYSTEM ${LLVM_INCLUDE_DIRS})
This way compiler will treat LLVM headers as "third-party" and won't emit any warnings for them.

Related

How to use SYSTEM headers with CMake and clang-tidy?

I am trying to use clang-tidy in my CMake (3.17.1) project however it crashes on the Catch2 test library header. Setting the Catch2 as a system header does not seem to help. The command invoked for clang-tidy contains the path to Catch2 as a system include directory yet the diagnostics is still printed for it. When trying to isolate it I have discovered that this does not actually work with clang-tidy:
clang-tidy src.cpp -- -Isystem/Path/to/header
It results in the header not being found at all. What I have learned somewhere (cannot find it now) was to make it actually two --extra-arg parameters of the clang-tidy instead:
clang-tidy --extra-arg=-Isystem --extra-arg=/Path/to/header src.cpp
This however does not work everywhere. On Windows I was able to make it work but on Linux it never worked in any form (together, separate, after --). How does one use the -isystem headers with clang-tidy on Linux? It is very confusing and inconsistent. Furthermore how to do it with CMake?
I have this:
cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_CLANG_TIDY clang-tidy)
add_library(Catch2 STATIC Catch2/Catch2.cpp Catch2/include/Catch2/catch.hpp)
target_include_directories(Catch2 SYSTEM PUBLIC Catch2/include)
add_executable(SomeTest SomeTest/test.cpp)
target_link_libraries(Catch2)
The generated command line is rather convoluted (wrapping is mine for readability):
cmake
-E __run_co_compile
--tidy="clang-tidy-10;--extra-arg-before=--driver-mode=g++"
--source=../Sometest/test.cpp
--
/usr/bin/clang++-10
-isystem ../Catch2/include
-g
-std=gnu++17
-MD
-MT CMakeFiles/SomeTest.dir/projects/SomeTest/test.cpp.o
-MF CMakeFiles/SomeTest.dir/projects/SomeTest/FileTest.cpp.o.d
-o CMakeFiles/SomeTest.dir/projects/SomeTest/test.cpp.o
-c
../projects/SomeTest/test.cpp
In the output there are warnings from the Catch2 so the system in the include is just ignored seemingly. I have tried to force the --extra-arg via the CMAKE_CXX_CLANG_TIDY property:
set(CMAKE_CXX_CLANG_TIDY clang-tidy --extra-arg=-isystem --extra-arg=../Catch2/include)
but that does not seem to do the trick either.
I am following your repro as posted on LLVM bugtracker.
You are doing everything correctly: that is, marking Catch2 as system include with SYSTEM. clang-tidy is also behaving correctly: it only checks your source file test.cpp and doesn't fully check catch.hpp, only the macro expansion.
The problem is the outdated version of Catch2. hicpp-vararg warning has been silenced as of Catch2 2.12.2, so you need to update to at least that version. Moreover, apparently the core issue that hicpp-vararg reported upon has been fixed and this change is expected to be present in clang-tidy 11 release.

CMAKE - How to set different compiler options for a single file

I have a CMAKE file with the following compilation flags
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} \
-fPIC -Wall -pedantic -Wextra -Werror \
-Wno-missing-braces -Wno-unused-variable \
-Wno-ignored-qualifiers -fdiagnostics-color")
I want to omit the -Wextra option for a single header file; /externals/include/foo.hpp (this is a third-party header-only library and gives error: [-Werror=unused-parameter] when compiled).
I have tried set_source_files_properties like this
set_source_files_properties(${EXTERNALS_SOURCE_DIR}/foo.hpp PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS_DEBUG} -Wno-extra")
but couldn't get rid of the compilation error.
Is there a way to do that either in CMAKE or using #pragmas in the header file itself?
Thanks.
SOLUTION
Here is how I got rid of the error:
Create a file foo_wrapper.hpp.
Add _pragma to ignore the trouble maker compilation flag
Use the wrapper header everywhere in the project instead of the actual header.
` // In file foo_wrapper.hpp:
_Pragma("GCC diagnostic push")
_Pragma("GCC diagnostic ignored \"-Wunused-parameter\"")
#include "foo.hpp"
_Pragma("GCC diagnostic pop")
`
On current compilers, it is not possible to do this through build options.
This is because of how the build model works: The compiler will get invoked once for every source file and all the header files included by that source file will invariably use the same build options as the source file itself.
So CMake will not be able to help you here.
Some compilers allow switching off certain warnings through #pragmas. For example, MSVC or gcc. Check your compiler's manual for what they offer in this regard. Unfortunately, this will always be non-portable, so if you have a code base supporting lots of compilers, the #pragmas can get lengthy. I would recommend writing a wrapper header that only includes the third party header giving you trouble and takes care of all the warning disabling. In your project you then always include the wrapper instead of the original third party header.

Why is clang reporting warnings on my header despite the use of -isystem, while gcc reports none?

Slightly related to this question but not the same.
Using clang 7.0.1 on Arch Linux. I like clean code, so I want to enable all warnings and treat them as errors.
The problem is that I have some autogenerated files in my build that are not free of warnings, e.g.:
generated/foo.h
inline void foo(int unused) { // warning: unused parameter 'unused'
}
generated/foo.cc
#include "foo.h"
// There is actual code here, but it doesn't matter.
Since these files are generated by a third-party tool, I cannot easily modify them, so I use -isystem to suppress all warnings from the generated directory.
I also have a main file that depends on the generated ones:
main.cc
#include "foo.h"
int main() {
foo(42);
}
With gcc, I can compile this just fine, even with all warnings enabled.
$ g++ -Wall -Wextra -pedantic -Werror -isystem generated -omain main.cc generated/foo.cc
With clang, however, it fails to compile generated/foo.cc:
$ clang++ -Wall -Wextra -pedantic -Werror -isystem generated -omain main.cc generated/foo.cc
In file included from generated/foo.cc:1:
generated/foo.h:1:21: error: unused parameter 'unused'
[-Werror,-Wunused-parameter]
inline void foo(int unused) {
^
1 error generated.
Adding --system-header-prefix does not help:
$ clang++ -Wall -Wextra -pedantic -Werror -isystem generated --system-header-prefix=generated/ -omain main.cc generated/foo.cc
In file included from generated/foo.cc:1:
generated/foo.h:1:21: error: unused parameter 'unused'
[-Werror,-Wunused-parameter]
inline void foo(int unused) {
^
1 error generated.
What does help is to replace #include "foo.h" by #include <foo.h> in the generated ("DO NOT MODIFY") code. This is hardly a proper fix, but it provides a clue: I suspect that clang is somehow finding foo.h in the current directory . instead of scanning the include path, and of course . is not marked as a system include directory.
This is actually almost documented:
A #include directive which finds a file relative to the current directory is treated as including a system header if the including file is treated as a system header.
However, it doesn't say what happens if the including file is not a header at all.
Workarounds that I can think of, none of which are great:
Postprocess the generated files before compiling them. E.g. by adding #pragma clang system_header. Ugly, and tricky to do in a very portable way.
Fiddle with the build system, CMake, to not enable warnings when compiling the generated .cc files. But this probably means I'll have to add a separate target for them, which means either duplicating lots of flags and configuration, or a DRY but more complex CMakeLists.txt.
I'd rather just set the right flags, like with gcc. Is this possible?
I underestimated CMake; this works without adding a lot of clutter:
set_source_files_properties(generated/foo.cc PROPERTIES COMPILE_FLAGS -w)

GCC, CMake, precompiled headers and maintaining dependencies

I'm trying to figure out how to maintain dependencies of my precompiled headers. It includes STL headers, some third-parties like boost and some of our rarely changing infrastructure headers.
I came out with something like this
SET(PCH_DIR ${CMAKE_CURRENT_BINARY_DIR})
SET(PCH_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/../include/server/server.h)
SET(PCH_DST server.h.gch)
ADD_CUSTOM_TARGET(serverPCH DEPENDS ${PCH_DST})
ADD_CUSTOM_COMMAND(OUTPUT ${PCH_DST} ${PCH_DEP}
COMMAND ${CMAKE_CXX_COMPILER} -x c++-header ${COMMON_CXXFLAGS} ${COMPILER_DEFINITIONS} -std=gnu++1z -c ${PCH_HEADER} -o ${PCH_DST} -I${CMAKE_SOURCE_DIR}/lib/include/server -I${CMAKE_SOURCE_DIR}/lib/include
MAIN_DEPENDENCY ${PCH_HEADER}
WORKING_DIRECTORY ${PCH_DIR}
COMMENT "Building precompiled header"
VERBATIM)
Looks like its doing its job and it gets recompiled once the header is edited. However, PCH recompilation is not triggered when one of files included in server.h is changed. Is there a way to trigger re-compilation if any of headers included in server.h is changed?
Well, 2 years later. CMake now supports precompiled headers and unity builds.

cmake generate assembly file then compile it into executable

I'm using cmake, and let's say I have a .cpp file.
Is it possible in cmake to compile this cpp file into assembly code first, then do some other operation and after that create executable from the generated assembly?
Update:
So basically I want to compile Hello.cpp to Hello.s (later modify it, and then create the object file). However I can't generate the asm file with that code (It just creates a Hello.a static library):
add_library(Tutorial Hello.cpp)
set_target_properties(Tutorial PROPERTIES COMPILE_FLAGS "-S")
install (TARGETS Tutorial DESTINATION bin)
CMake does always generate "assembly file rules" for you. So let's say you have:
file(WRITE main.cpp "int main() { return 0; }")
add_executable(MyMain main.cpp)
You can call make for targets main.s or main.cpp.s like:
> make main.cpp.s
Compiling CXX source to assembly CMakeFiles/MyMain.dir/main.cpp.s
But if you want to automate everything, see my answer at your other question:
Call shell command after asm file generation in cmake
You can tell GCC to only generate assembly with the -S option.
You can also tell GCC to keep intermediate files with -save-temps.