【问题标题】:Override compile flags for single files覆盖单个文件的编译标志
【发布时间】:2012-11-18 06:31:29
【问题描述】:

我想使用一组全局标志来编译项目,这意味着在我的顶级 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 ,但这没有帮助。

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

【问题讨论】:

标签: c++ cmake compiler-warnings


【解决方案1】:

您在上面的尝试正在向您的文件/目标添加更多标志,而不是像您预期的那样覆盖。例如,来自Properties on Source Files - COMPILE_FLAGS 的文档:

这些标志将在此源文件构建时添加到编译标志列表中。

您应该可以通过这样做来取消 foo.cpp 的 -Weffc++ 标志

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

这应该有在编译命令中-Weffc++后面加上-Wno-effc++的效果,后面的设置胜出。要查看完整的命令并检查是否确实如此,您可以这样做

make VERBOSE=1

顺便说一句,GNU C++ 标准库的维护者之一在this answer 中对-Weffc++ 提出了相当负面的看法。

另一点是,您误用了add_definitions,因为您将它用于编译器标志而不是预期的预处理器定义。

最好使用add_compile_options

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

或者对于 CMake 版本

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

为了回答下面 cmets 中的进一步问题,我认为不可能可靠地删除单个文件上的标志。原因是对于任何给定的源文件,它应用了其目标的COMPILE_OPTIONSCOMPILE_FLAGS1,但是这些不会显示在该源文件的任何属性中。

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

然而,虽然这可以在许多情况下工作,但它有几个问题。

首先 - source files' properties 不包括 COMPILE_OPTIONS,仅包括 COMPILE_FLAGS。这是一个问题,因为目标的COMPILE_OPTIONS 可以包含generator expressions,但COMPILE_FLAGS 不支持它们。所以你必须在搜索你的标志时适应生成器表达式,事实上,如果你的标志包含在一个或多个中,你甚至可能不得不“解析”生成器表达式,以查看它是否应该重新应用于剩余的源文件。

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

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


1:请注意,与源文件上的COMPILE_FLAGS 属性不同,目标上的COMPILE_FLAGS 属性已被弃用。

【讨论】:

  • 但是如何在不附加文件的情​​况下单独设置文件的编译标志。例如,我想对生成的目标使用与文件不同的编译标志,但由于它们是附加的,我必须手动删除它们。是否没有不附加但实际上仅为指定文件/目标设置它们的属性?
  • 当 -fno-flag 不可用(并且 -fflag 已设置)时我们该怎么办?
  • @Baradé 你不能——不是源文件。
  • @gnzlbg 再次,我们几乎被困住了。我已经更新了我的答案以提供更多信息(以及可能适用于一些场景的可能解决方法)。
  • 单文件编译选项设置真的没有解决办法吗?我必须为一些崩溃 gcov 的文件禁用 gcc 覆盖生成。
【解决方案2】:

只是添加到@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++)

请注意,不建议使用here所讨论的 GLOB

【讨论】:

    【解决方案3】:

    使用@Fraser 答案,我创建了以下内容来处理 Qt 包含,因为该变量包含由分号分隔的多个路径。这意味着我必须首先添加一个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 标头生成的一些警告(我打开了大量警告)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-26
      • 2010-12-08
      • 1970-01-01
      • 2015-04-26
      • 2011-10-19
      • 1970-01-01
      相关资源
      最近更新 更多