Override compile flags for single files
Your attempts above are adding further flags to your file/target rather than overwriting as you seem to expect. For example, from the docs for Properties on Source Files - COMPILE_FLAGS:
These flags will be added to the list of compile flags when this source file builds.
You should be able to countermand the -Weffc++
flag for foo.cpp by doing
set_source_files_properties(foo.cpp PROPERTIES COMPILE_FLAGS -Wno-effc++)
This should have the effect of adding -Wno-effc++
after -Weffc++
in the compiler command, and the latter setting wins. To see the full command and check that this is indeed the case, you can do
make VERBOSE=1
As an aside, one of the maintainers of the GNU C++ Standard Library presents a pretty negative opinion on -Weffc++
in this answer.
Another point is that you're misusing add_definitions
in the sense that you're using this for compiler flags rather than the intended preprocessor definitions.
It would be preferable to use add_compile_options
add_compile_options(-Wall -Weffc++ -pedantic -std=c++0x)
or for CMake versions < 3.0 to do something more like:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Weffc++ -pedantic -std=c++0x")
In response to further questions in the comments below, I believe it's impossible to reliably remove a flag on a single file. The reason is that for any given source file, it has the COMPILE_OPTIONS
and COMPILE_FLAGS
1 of its target applied, but these don't show up in any of the properties for that source file.
You could look at stripping the problem flag from the target's COMPILE_OPTIONS
, then applying it to each of the target's sources individually, omitting it from the specific source file as required.
However, while this could work in many scenarios, it has a couple of problems.
First - source files' properties don't include COMPILE_OPTIONS
, only COMPILE_FLAGS
. This is a problem because the COMPILE_OPTIONS
of a target can include generator expressions, but COMPILE_FLAGS
doesn't support them. So you'd have to accommodate generator expressions while searching for your flag, and indeed you'd maybe even have to "parse" generator expressions if your flag was contained in one or more to see whether it should be re-applied to the remaining source files.
Second - since CMake v3.0, targets can specify INTERFACE_COMPILE_OPTIONS
. This means that a dependency of your target can add or override your target's COMPILE_OPTIONS
via its INTERFACE_COMPILE_OPTIONS
. So you'd further have to recursively iterate through all your target's dependencies (not a particularly easy task since the list of LINK_LIBRARIES
for the target can also contain generator expressions) to find any which are applying the problem flag, and try and remove it from those targets' INTERFACE_COMPILE_OPTIONS
too.
At this stage of complexity, I'd be looking to submit a patch to CMake to provide the functionality to remove a specific flag unconditionally from a source file.
1: Note that unlike the COMPILE_FLAGS
property on source files, the COMPILE_FLAGS
property on targets is deprecated.
How to compile with different compile options for different files in CMAKE?
AFAIK CMake does not allow to specify compile options per file. The best you can do is to create a target for the files you want to compile with -fno-rtti
, e.g. with add_library
, and add the compile options to this target.
add_definitions
is meant to add preprocessor definitions. You should consider add_compile_options
instead:
add_compile_options(-fno-rtti)
To avoid global pollution and make sure you add your options only to a given target, you may consider using target_compile_options
:
target_compile_options(foo PUBLIC -fno-rtti)
Unrelated, but instead of manually setting flags to enable c++11 with set(CMAKE_CXX_FLAGS "-std=c++11 ...")
, let cmake do a more fine grained job with compile features, or at least with standard selection:
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
EDIT:
Looking more carefully in the documentation, you can set compile flags per source file using set_source_files_properties with COMPILE_FLAGS:
set_source_files_properties(File2.cpp PROPERTIES COMPILE_FLAGS -fno-rtti)
Limit compilation flags usage to certain files only
I don't know about any compiler flags that allow you to apply flags to only some of the files included, so cmake cannot do better for you. Therefore pragmas are the way to go.
Basically what you effectively want in your cpp files is something like this:
#pragma GCC diagnostic push
#pragma GCC diagnostic error "-Wall"
#include "updated_lib/header1.hpp"
#include "updated_lib/header2.hpp"
...
#pragma GCC diagnostic pop
#include "non_updated_lib/header1.hpp"
#include "non_updated_lib/header2.hpp"
Note that this would require this logic to be repeated in multiple translation units which you may want to avoid, if you're updating the headers gradually over time.
As an alternative you could duplicate the header file subdirectories, and make the non-updated versions available via one path and updated headers via another, e.g. for a header foo/bar/baz.hpp
either make the header available via path old/foo/bar/baz.hpp
or new/foo/bar/baz.hpp
and create a new header available via foo/bar/baz.hpp
that looks like this:
#if __has_include("new/foo/bar/baz.hpp")
# pragma GCC diagnostic push
# pragma GCC diagnostic error "-Wall"
# include "new/foo/bar/baz.hpp"
# pragma GCC diagnostic pop
#else
# pragma GCC diagnostic push
# pragma GCC diagnostic warning "-Wall"
# include "old/foo/bar/baz.hpp"
# pragma GCC diagnostic pop
#endif
Note that you'll probably need to write these kind of headers for you. You could even generate the actual includes via cmake during the generation of the project which which would shorten the headers to 3 pragmas plus one include; this would have the additional benefit of working with compiler versions not supporting __has_include
.
function(my_generate_include OUT_LIST DESTINATION_DIR FIRST_HEADER)
set(GENERATED_HEADERS ${${OUT_LIST}})
foreach(HEADER IN ITEMS ${FIRST_HEADER} ${ARGN})
if (HEADER MATCHES "^old/(.*)$")
configure_file(old_include.hpp.in "${DESTINATION_DIR}/${CMAKE_MATCH_1}")
list(APPEND GENERATED_HEADERS "${DESTINATION_DIR}/${CMAKE_MATCH_1}")
elseif (HEADER MATCHES "^new/(.*)$")
configure_file(new_include.hpp.in "${DESTINATION_DIR}/${CMAKE_MATCH_1}")
list(APPEND GENERATED_HEADERS "${DESTINATION_DIR}/${CMAKE_MATCH_1}")
else()
message(FATAL_ERROR "Header '${HEADER}' doesn't start with 'new/' or 'old/'")
endif()
endforeach()
set(${OUT_LIST} ${GENERATED_HEADERS} PARENT_SCOPE)
endfunction()
...
set(HEADERS)
my_generate_include(HEADERS ${CMAKE_CURRENT_BINARY_DIR}/generated_includes
old/a/b/c.hpp
new/d/e/f.hpp
)
Related Topics
What's the Fastest Way to Pack 32 0/1 Values into the Bits of a Single 32-Bit Variable
How to Make Reading from 'Std::Cin' Timeout After a Particular Amount of Time
What's the Precedence of Comma Operator Inside Conditional Operator in C++
Is This Undefined Behavior with Const_Cast
Good Debugger Tutorial for Beginners
Constexpr Initializing Static Member Using Static Function
G++ Does Not Show a 'Unused' Warning
How to Check for Equals? (0 == I) or (I == 0)
How to Pass the Windows Defender Smartscreen Protection
How to Specify Setprecision Rounding
Gcc Linker Can't Find Standard Library
Sending Two or More Chars Using Sendinput
How to Check If the Input Is a Valid Integer Without Any Other Chars
How to Validate Input Using Scanf
Implementing Multiple Interfaces in C++