将编译标志的使用限制在某些文件中

Limit compilation flags usage to certain files only

我正在尝试将 -Werror 标志引入相当大的遗留项目。正如预期的那样,它完全破坏了编译。因此,我决定逐步介绍它,首先是针对新代码。我最初的方法是将新功能编译为单独的静态目标,并将它们link 编译到项目中,这在项目结构和可读性方面都很好。一直纠结的问题包括pre-existing。基本上,即使在修复了新代码中的所有警告之后,我仍然留下了引入新警告的包含链。有没有办法严格限制给定源文件的警告标志使用? 我确实明白 include 基本上意味着 copy/pasting headers 进入 cpps,因此仅使用 cmake 设置似乎是不可能的。然后 pragma,也许?

您可以在您需要的文件上使用 set_source_files_properties command to set the COMPILE_OPTIONS 属性。

像这样:

set_source_files_properties(bad.cpp PROPERTIES COMPILE_OPTIONS -Werror)

我不知道是否有任何编译器标志允许您仅将标志应用于所包含的部分文件,因此 cmake 无法为您做得更好。因此,pragmas 是必经之路。

基本上你想要的 cpp 文件是这样的:

#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"

请注意,如果您随着时间的推移逐渐更新 headers,这将需要在多个翻译单元中重复此逻辑,您可能希望避免这种情况。

作为替代方案,您可以复制 header 文件子目录,并通过一个路径使 non-updated 版本可用,并通过另一个路径更新 headers,例如对于 header foo/bar/baz.hpp 可以通过路径 old/foo/bar/baz.hppnew/foo/bar/baz.hpp 使 header 可用,并通过 foo/bar/baz.hpp 创建一个新的 header 可用看起来像这样:

#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

请注意,您可能需要为自己编写此类 header。您甚至可以在项目生成期间通过 cmake 生成实际包含,这会将 headers 缩短为 3 个编译指示加一个包含;使用不支持 __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
)