GCC, CMake, precompiled headers and maintaining dependencies - c++

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.

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.

How to eliminate certain (non system) headers from dependency files(.d)?

We link in a library(TAO) which is composed of many header files.
Every time I run the pre-processor command on a cpp file( g++ -MM $< $# ), these library files are automatically included in every .d file generated.
These are obviously not system files and almost never change as far as we're concerned, so I would like to eliminate them from my .d files.
Short of filtering out these header files using sed, is there any built in way to accomplish this?
You may instruct gcc to consider some path as system headers with -isystem; and g++ -MM ignore system-headers.

c++ automake precompiled header support on centos

The background about this question is: my project(C++ language) contains too many files, which including boost, thrift, zookeeper, etc. Now the compilation duration takes too long.
As you know, Visual Studio supports precompiled headers, so as GCC. Because I use automake to manager the Make procedure, so What I want to ask for is whether automake supports precompiled headers? How can I write automake files if so?
Waiting and thranks for your answers.
The whole thing is not about automake, but rather about writing makefiles.
Actually, you can try the .gch, but there're restrictons:
write one common header to include everything (like stdafx.h)
It should be the 1st include in all your sources
use same CFLAGS to compile all your sources
It's a new functionality. You'd want to detect it in your configure.ac
Write a rule in your Makefile.am, name it like stdafx.gch:. Make it empty, if gch is not supported:
stdafx.gch: stdafx.h
$(OPTIONAL_COMPILE_GCH)
.PHONY: $(OPTIONAL_STDAFX_GCH)
Make your _OBJECTS depend on stdafx.gch:
$(foo_SOURCES:.cpp=.$(OBJEXT)): stdafx.gch
# or (is it documented var?)
$(foo_OBJECTS)): stdafx.gch
Youc can use the documented CXXCOMPILE command to be sure that all CXXFLAGS are the same.
Detect in your configure.ac:
if ...; then
[OPTIONAL_COMPILE_GCH='$(CXXCOMPILE) -c -o $# $<']
[OPTIONAL_STDAFX_GCH=]
else
[OPTIONAL_COMPILE_GCH=]
[OPTIONAL_STDAFX_GCH='stdafx.gch']
fi
AC_SUBST(OPTIONAL_COMPILE_GCH)
AC_SUBST(OPTIONAL_STDAFX_GCH)
Update
You want your .gch to be recompiled, when any header file indirectly used by stdafx.h is modified.
Then you could add stdafx.cpp that does nothing, but includes stdagx.h and make .gch depend on stdafx.o. This way the dependency tracking would be managed by automake, but there's a problem:
stdafx.o itself could make use of .gch to compile faster, but if we add such dependency, it would be circular. It's not easy for me to find a solution.
Here's an example that uses status files to solve this: https://gist.github.com/basinilya/e00ea0055f74092b4790
Ideally, we would override the compilation command for stdafx.o, so it first creates .gch and then runs the standard automake compilation, but automake does not use $(CXXCOMPILE) as is. It creates a complex recipe from it (and it depends on automake version):
Update 2
Another solution is to use gcc dependency tracking directly:
stdafx.h.gch: stdafx.h
g++ -MT stdafx.h.gch -MD -MP -MF .deps/stdafx.Tpo -c -o stdafx.h.gch stdafx.h
mv .deps/stdafx.Tpo .deps/stdafx.Po
-include .deps/stdafx.Po
By default, if precompiled header is used, gcc -MD will not put the list of header files into the generated dependencies file, just .gch. There's an option to fix this : -fpch-deps (see bug), but perhaps the default behavior is not that bad: if only the .gch depends on the headers, make will have less work to do.

Adding a library to a makefile

I just installed RtMidi for a project and compiled it. The examples in the tests folder work and so does my code if I put it in the folder and include it in the Makefile that compiles all the examples. How can I use RtMidi in a project with #include <RtMidi.h> instead of having my code in the tests folder? More specifically, what should I put in my Makefile? I've read a bit about dynamic and static libraries but I have no idea what I should be looking for. I've tried adding -llibrtmidi and /usr/local/lib/librtmidi.a without success.
In a standard Makefile, the CXXFLAGS macro defines flags for the C++ compiler. You will need to add -I<path to header directory> to this macro for the compiler to find the RtMidi header files.
Then you will need to add -L<path to lib directory> to the link step of the Makefile so that -lrtmidi will find the library file. (Note that you omit the lib prefix for the -l command)
Based on your description of your environment, you may require something like
CPPFLAGS += -I/usr/local/include
LDFLAGS += -L/usr/local/lib
LDLIBS += -lrtmidi
in your Makefile. make uses a lot of these implicit variables.