覆盖单个文件的编译标志

我想使用一组全局标志来编译一个项目,这意味着在我的顶级 CMakeLists.txt 文件中我已经指定:

ADD_DEFINITIONS ( -Wall -Weffc++ -pedantic -std=c++0x )

但是,对于子目录中的特定文件(比方说“ foo.cpp”) ,我希望切换 编译标志不适用-Weffc + + (包括商业库,我不能更改)。为了简化只使用-Wall 的情况,我尝试了:

 SET_SOURCE_FILES_PROPERTIES( foo.cpp PROPERTIES COMPILE_FLAGS -Wall )
ADD_EXECUTABLE( foo foo.cpp )

,这没有工作。 我也试过

SET_PROPERTY( SOURCE foo.cpp PROPERTY COMPILE_FLAGS -Wall )
ADD_EXECUTABLE( foo foo.cpp )

还有

ADD_EXECUTABLE( foo foo.cpp )
SET_TARGET_PROPERTIES( foo PROPERTIES COMPILE_FLAGS -Wall )

两者都不起作用。

最后,我试着去掉这个定义:

REMOVE_DEFINITIONS( -Weffc++ )
ADD_EXECUTABLE( foo foo.cpp )
ADD_DEFINITIONS( -Weffc++ )

,这也没有工作(这意味着,我得到了很多关于商业图书馆的样式警告)。 (* * 注意: 如果在构建可执行文件后不重新包含-Weffc + + 指令,则警告将被取消。)

我还尝试临时删除编译标志: Http://www.cmake.org/pipermail/cmake/2007-june/014614.html 但是没有用。

难道没有一个优雅的解决方案吗?

95572 次浏览

上面的尝试是向文件/目标添加进一步的标志,而不是像您期望的那样覆盖。例如,来自 源文件的属性-COMPILE _ FLAGS的文档:

生成此源文件时,这些标志将添加到编译标志列表中。

通过执行以下操作,您应该能够取消 foo.cpp 的 -Weffc++标志

set_source_files_properties(foo.cpp PROPERTIES COMPILE_FLAGS -Wno-effc++)

这将产生在编译器命令中的 -Weffc++之后添加 -Wno-effc++的效果,后者将获胜。要查看完整命令并检查确实如此,可以这样做

make VERBOSE=1

顺便说一句,GNU C++标准程式库的一位维护者对 这个答案中的 -Weffc++持相当负面的看法。

另一个问题是,在某种意义上,您正在错误地使用 add_definitions,因为您将其用于编译器标志,而不是预期的预处理器定义。

最好使用 add_compile_options

add_compile_options(-Wall -Weffc++ -pedantic -std=c++0x)

或者对于 CMake 版本 < 3.0来说,更像是:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Weffc++ -pedantic -std=c++0x")

作为对下面评论中进一步问题的回应,我认为在单个文件上可靠地使用 拿开标志是不可能的。原因是对于任何给定的源文件,它都应用了目标的 COMPILE_OPTIONSCOMPILE_FLAGS1,但是这两个属性都不会出现在源文件的任何属性中。

您可以从目标的 COMPILE_OPTIONS中剥离问题标志,然后将其分别应用于目标的每个源,根据需要从特定的源文件中省略它。

然而,尽管这在许多场景中都可以工作,但是它存在一些问题。

第一-源文件的属性不包括 COMPILE_OPTIONS,只包括 COMPILE_FLAGS。这是一个问题,因为目标的 COMPILE_OPTIONS可以包含 生成器表达式生成器表达式,但是 COMPILE_FLAGS不支持它们。因此,在搜索标志时,您必须适应生成器表达式,实际上,如果标志包含在一个或多个文件中,您甚至可能需要“解析”生成器表达式,以确定是否应该将其重新应用到剩余的源文件中。

第二,自 CMake v3.0以来,目标可以指定 INTERFACE_COMPILE_OPTIONS。这意味着目标的依赖项可以通过目标的 INTERFACE_COMPILE_OPTIONS添加或覆盖目标的 COMPILE_OPTIONS。因此,您必须进一步递归地遍历所有目标的依赖项(这不是一个特别容易的任务,因为目标的 LINK_LIBRARIES列表也可以包含生成器表达式) ,以找到任何应用问题标志的依赖项,并尝试从这些目标的 INTERFACE_COMPILE_OPTIONS中删除它。

在这个复杂的阶段,我希望向 CMake 提交一个补丁,以提供从源文件中无条件删除特定标志的功能。


1: 注意,与源文件上的 COMPILE_FLAGS属性不同,目标文件上的 COMPILE_FLAGS属性是不推荐的。

只是添加到@Fraser 的正确答案。

如果你想给特定的文件夹添加特殊的标志,你可以这样做:

file(GLOB SPECIAL_SRC_FILES
"path/one/src/*.cpp"
"path/two/src/*.cpp")
set_property(SOURCE ${SPECIAL_SRC_FILES} PROPERTY COMPILE_FLAGS -Wno-effc++)

或者

file(GLOB SPECIAL_SRC_FILES
"path/one/src/*.cpp"
"path/two/src/*.cpp")
set_source_files_properties(${SPECIAL_SRC_FILES} PROPERTIES COMPILE_FLAGS -Wno-effc++)

注意,不建议像讨论的 给你那样使用 GLOB

使用@Fraser 答案,我创建了以下内容来处理 Qt include,因为该变量包含多个由分号分隔的路径。这意味着我必须首先添加一个 foreach()循环并创建包含标志 用手。但是这允许我有一个例外: Foo.cpp(这个文件现在使用 Qt,但是长期来看,我想移除这个依赖,并且我想确保 Qt 不会蔓延到其他任何地方)。

find_package(Qt5Core REQUIRED)
set(QT_INCLUDE_PROPERTIES "")
foreach(DIR ${Qt5Core_INCLUDE_DIRS})
set(QT_INCLUDE_PROPERTIES "${QT_INCLUDE_PROPERTIES} -isystem ${DIR}")
endforeach()
set_source_files_properties(foo.cpp PROPERTIES
COMPILE_FLAGS
${QT_INCLUDE_PROPERTIES}
)

还请注意,我使用 -isystem而不是 -I来避免 Qt 头部生成的一些警告(我已经打开了大量的警告)。

虽然不完全是对 OPs 问题的回答,下面的提示为我解决了一个问题。有些编译器允许在源文件本身中设置或取消设置选项:

#pragma option -Xinteger-divide-fast=0

这将禁用 diab 编译器上的整数除法快速选项,在我的例子中,这会导致它在该特定文件上崩溃。