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

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.

Related

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

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.

How do I generate and use precompiled headers with Clang++?

The official docs state how precompiled headers are to be used through the -cc1 interface, like so to generate them:
$ clang -cc1 test.h -emit-pch -o test.h.pch
And to use them:
$ clang -cc1 -include-pch test.h.pch test.c -o test.s
The problem is that the -cc1 interface is way too low-level to be used by developers from the CLI. In fact, the regular high-level interface ultimately calls into the low-level -cc1 interface by supplying it with a very large set of arguments that are necessary for its correct operation, for example the include paths appropriate for the compile time system. Without these arguments, the -cc1 interface has no prayer of working:
$ clang++ -cc1 /usr/include/x86_64-linux-gnu/c++/7/bits/stdc++.h -emit-pch -o std.pch
/usr/include/x86_64-linux-gnu/c++/7/bits/stdc++.h:33:10: fatal error: 'cassert' file not found
#include <cassert>
^~~~~~~~~
1 error generated.
Is there a way to use precompiled headers from the high-level interface, such that a developer may conveniently tap into this feature during their daily work?
I don't know why the clang docs do not explain this, but indeed as #selbie surmises, it is possible to use Clang precompiled headers (PCH) without using -cc1.
To generate a PCH file:
$ clang -c -o big-header.hh.pch big-header.hh <other options>
This is the normal compile command, except the input file has the .hh (C++ header) extension. clang will recognize that means to generate a PCH. Alternatively, pass -xc++-header before the header file name if you do not want to use that extension (or another, like .H or .hpp, that is unambiguously C++).
You can tell that big-header.hh.pch is not object code (despite the -c on the command line) because file will say it is "data" (at least my version does) rather than object code. To be extra sure, run strings big-header.hh.pch | head. The first line should be "CPCH" (meaning "Clang PCH").
To use the PCH file:
$ clang -c -include-pch big-header.hh.pch <other compile options>
The addition of -include-pch big-header.hh.pch is the key step that is different compared to gcc. Clang will not automatically pick up PCH files just due their name.
The above was tested with Clang+LLVM-14.0.0 on Linux.
I think the root of your problem is that your filename is test.h and clang thinks you are compiling C code, not C++ code. Hence, when you include <cassert>, clang doesn't know it should be looking at the C++ include path. Try naming your file test.hpp. You only have to name the file you want as the precomp header with .hpp. You can keep all your header files with .h extensions.
In any case, I might be getting this confused with gcc/g++, but Clang follows the same behavior whenever I compile my code on Mac. This is how I make use of precompiled headers. Read on...
If you've got a C++ header file you want to precompile, just compile it as any other .cpp file. Notice that I'm using .hpp as the file extension so the compiler picks it up as a C++ header file.
clang -c precomp.hpp
This will produce precomp.hpp.gch
Now to use the precomp by any other ordinary C++ file, just include the ordinary .hpp file:
// main.cpp
#include "precomp.hpp"
void func1() {...}
void main() {...}
The compiler will automatically use the corresponding .gch file if its present in place of the original .hpp file.

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)

Where in Qt Creator do I pass arguments to a compiler?

Where in Qt Creator do I pass arguments to a compiler?
It isn't really that obvious.
Depending on your build system it's either in your qmake project file(.pro, standard for new projects) or in one of the CMake files (CMakeLists.txt, used by KDE and several other projects).
Using .pro:
QMAKE_CXXFLAGS += -O2
Using CMake:
set( CMAKE_CXX_FLAGS "-g -Wall")
To add compiler flags, open your .pro file and add a line like this:
QMAKE_CXXFLAGS += -std=c++0x
For standard flags like debug vs. release etc. you should try to use the predefined qmake options (see QMake documentation) for the sake of platform and compiler-independency, as QMake will map them to the compiler-specific flags.
If your intention is to precompile some source code you can do like this:
/A/ In your .pro file you can add a line like this:
DEFINES += HOPLA
/B/ In you .cpp or .h file you can use it like this
#ifdef HOPLA
// Do something
#else
// Do something different
#endif
for C projects, add the following line in .pro file
QMAKE_CFLAGS += -std=c99
in the .pro file you can add variables which modify the make behavior for example, if you try to execute the following command:
g++ -Wall -I/usr/include/cppconn -o exe main.cpp -L/usr/lib -lmysqlcppconn
you must add the following lines in the .pro file
INCLUDEPATH += /usr/include/cppconn
LIBS += -L/usr/lib -lmysqlcppconn
Check the image below.
For more information on the available variables that QT IDE uses, you can visit the following link where they explain in more detail each one. Qt Documentation: Variables
As the elected answer points, for CMake based projects, you can edit the CMakeLists.txt and set the flags for the compiler, and for this case, I have a pictorial demonstration on how to add flags on QtCreator/CMake.
I wanted to add the '-pedantic' flag, which warns about extensions, without throwing errors while executing the program, and here's pictorial example of how to enable compiler flags on CMake while using QtCreator:
For more context:
On the example below, I'm setting the size of a Static Array at Runtime, something that is only possible with Variable-length Array feature, which is available at C99, but defined as optional feature starting from C11. Without -pedantic flag being available for the compiler, the warning would't be displayed after compiling the code.

gcc compilation without using system defined header locations

I am attempting to compile a c++ class using gcc. Due to the nature of the build, I need to invoke gcc from a non-standard location and include non-system defined headers, only to add a set from a different location. However, when I do this, I run into an issue where I cannot find some base symbols (suprise suprise). So i am basically running this command to compile my code:
-->(PARENT_DIR)/usr/bin/gcc # invoke compiler
-B$(PARENT_DIR)/usr/lib64/gcc/suselinux-x8664
-B$(PARENT_DIR)/usr/lib64
#C/C++ flags
-fPIC -fvisibility=default -g -c -Wall -m64 -nostdinc
# source files
-I$(SRC_DIR_ONE)/
-I$(SRC_DIR_TWO)
-I../include
# 'Mock' include the system header files
-I$(PARENT_DIR)/usr/include/c++/$(GCC_VERSION)
-I$(PARENT_DIR)/usr/include/c++/$(GCC_VERSION)/backward
-I$(PARENT_DIR)/usr/include/c++/$(GCC_VERSION)/x86_64-suse-linux
-I$(PARENT_DIR)/usr/lib64/x86_64-suse-linux/$(GCC_VERSION)/include
-I$(PARENT_DIR)/usr/lib64/gcc/x86_64-suse-linux/$(GCC_VERSION)/include
-I$(PARENT_DIR)/usr/lib64/gcc/x86_64-suse-linux/$(GCC_VERSION)/include-fixed
-I$(PARENT_DIR)/usr/src/linux/include
-I$(PARENT_DIR)/usr/x86_64-suse-linux/include
-I$(PARENT_DIR)/usr/include/suselinux-x8664
-I$(PARENT_DIR)/usr/suselinux-x8664/include
-I$(PARENT_DIR)/usr/include
-I$(PARENT_DIR)/usr/include/linux
file.cpp
I am getting several errors which indicate that the base headers are not being included: such as:
$(PARENT_DIR)/usr/include/c++/$(GCC_VERSION)/cstddef ::prtdiff_t has not been declared
$(PARENT_DIR)/usr/include/c++/$(GCC_VERSION)/cstddef ::size_t has not bee declared.
Is there something that I am doing wrong when I include the header file directories? Or am I looking in the wrong place?
Perhaps the --sysroot arg would help, see gcc docs.