【问题标题】:How can I let CMake check whether my headers are self-sufficient?如何让 CMake 检查我的标头是否自给自足?
【发布时间】:2013-05-07 22:08:49
【问题描述】:

设置

我有一个使用 CMake 构建和运行良好的项目。我的项目设置是这样的:

├── CMakeLists.txt
|
├── include/
│   └── standalone/
│       └── x.hpp
|
├── src/
    └── standalone/
        └── main.cpp

我的头文件内容是这样的:

// ------x.hpp--------
#pragma once
#include <iostream>

class X
{
public:
  void hello()
  {
    std::cout << "Hello World!\n"; // needs <iostream>
  }
};

// -------main.cpp-------
#include <standalone/x.hpp>

int main()
{
  X x;
  x.hello();
}

我用下面CMakeLists.txt

cmake_minimum_required(VERSION 2.8)
project(standalone)

###############################################################
# Compiler settings
###############################################################

# use C++11 features
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

# set warning level
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -pedantic -pedantic-errors -Wall -Wextra")

###############################################################
# header dependencies
###############################################################

# compile against project headers
include_directories(${PROJECT_SOURCE_DIR}/include)

# the header files
file(GLOB_RECURSE header_files FOLLOW_SYMLINKS "include/*.hpp")

# the source files
file(GLOB_RECURSE source_files FOLLOW_SYMLINKS "src/*.cpp")

###############################################################
# build target
###############################################################

# the program depends on the header files and the source files
add_executable(main ${header_files} ${source_files})

mkdir buildcd buildcmake ..make./main 的命令序列正确打印“Hello World!”没有警告。

问题

上面的设置是正确的。但是假设&lt;iostream&gt; 不包含在x.hpp 中,而是包含在main.cpp 中。然后程序仍然可以正确构建,但x.hpp 不会是独立的标头。所以我想测试self-sufficiency of my headers,即对于每个头我想编译一个小测试程序

#include "some_header.hpp"
int main() {}

但是,如果我将以下部分添加到 CMakeList.txt

###############################################################
# header self-sufficiency
###############################################################

set(CMAKE_REQUIRED_FLAGS ${CMAKE_CXX_FLAGS})
message("REQUIRED_FLAGS=${CMAKE_REQUIRED_FLAGS}")
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_SOURCE_DIR}/include)
message("REQUIRED_INCLUDES=${CMAKE_REQUIRED_INCLUDES}")
include(CheckIncludeFiles)
check_include_files("${header_files}" IS_STANDALONE)

${header_files} 正确扩展为标题x.hpp,但check_include_files() 命令没有正确编译它

REQUIRED_FLAGS= -std=c++11 -Werror -pedantic -pedantic-errors -Wall -Wextra
REQUIRED_INCLUDES=/home/rein/projects/standalone/include
-- Looking for include file /home/rein/projects/standalone/include/standalone/x.hpp
-- Looking for include file /home/rein/projects/standalone/include/standalone/x.hpp - not found.

问题

显然我缺少一些配置变量,让 CMake 在正确的位置进行搜索。即使对于正确的标题,check_include_files() 也不起作用。 我需要做些什么来完成这项工作?只有当正确的标题被认为是正确的,我才能继续测试不正确的标题。

注意除非是 绝对必要,我对直接调用TRY_COMPILE 的shell 脚本或精心制作的CMake 循环不感兴趣或类似的东西。 AFAICS,这就是 CheckIncludeFiles 模块的用途,如果可能的话,我想知道如何正确配置它。

【问题讨论】:

  • 这个answer 到关于Self-sufficient headers in C/C++ 的问题有一个脚本chkhdr,可用于测试标头的自包含性。
  • @JonathanLeffler 谢谢,是的,我知道您的脚本,并将检查它(同时我找到了另一个脚本,请参阅我的答案)。令人失望的是,CMake 并不简单(我试图保持与 Windows 兼容)。
  • 我没有将它作为答案发布的一个原因是我不确定如何将它集成到 CMake 中。抱歉,我帮不上忙。
  • @JonathanLeffler 没问题,本周早些时候我已经对你的优秀剧本投了赞成票 :-)

标签: c++ cmake header-files buildconfiguration build-dependencies


【解决方案1】:

对于 C++ 头文件而不是 C 头文件,您需要使用 CheckIncludeFileCXX。此模块与CheckIncludeFiles 的不同之处还在于,您一次只能将一个文件传递给此宏。

您也可能需要设置CMAKE_REQUIRED_INCLUDES,或文档中列出的其他变量之一。

例如,如果您的某些标题相互引用(如#include "h1.hpp"),那么您需要:

set(CMAKE_REQUIRED_FLAGS ${CMAKE_CXX_FLAGS})
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_SOURCE_DIR}/include)
include(CheckIncludeFileCXX)
foreach(project_header ${project_headers})
  get_filename_component(header_name ${project_header} NAME_WE)
  check_include_file_cxx("${project_header}" ${header_name}_IS_STANDALONE)
endforeach()

CMake wiki 文章 How To Write Platform Checks 中有更多信息。

【讨论】:

  • 感谢您的回答。我将我的问题修改为一个自给自足的例子。但是,您的建议不起作用。我是否需要在所有标题上写一个循环并写check_include_file()(单数,而不是复数!)才能做到这一点?
  • 您不应该这样做,但这样做会更好。我认为更多的是该功能的设计方式,它将为您提供更细粒度的结果。刚才,如果您将 4 个标头传递给命令并且任何一个标头失败,则整个命令将失败(这就是您所看到的)。因此,您的一个标题实际上可能不是自给自足的。另外,在您的示例中,我看到您使用的是 set(CMAKE_REQUIRED_INCLUDE ...) 而不是 set(CMAKE_REQUIRED_INCLUDES ...) - 我猜可能是转录错误?
  • 你是对的,我在我的问题上打错了(不是在我的代码中!):CMAKE_REQUIRED_INCLUDES 中应该有一个最后的 S。请注意,我将问题修改为由单个头文件和单个源文件组成的示例。
  • 查看我自己的答案,了解为什么我认为这无法正常工作。或者你的答案是否真的适用于我的设置?
  • @rhalbersma 我已经更新了我的答案,希望现在应该是一个可行的解决方案。抱歉,我之前从未发现过 C 与 C++ 的问题!
【解决方案2】:

浏览CMakeFiles/CMakeError.log 输出后,check_include_files() 似乎有两个基本限制无法通过允许的配置选项克服(这些点中似乎有some confirmation):

  1. 总是调用 C 编译器,而不是 C++ 编译器。这意味着 -std=C++11 不是要传递的有效命令行选项。
  2. 标准系统包括路径(/usr/include 等)被忽略,即使使用 set(CMAKE_REQUIRED_INCLUDES ${CMAKE_SOURCE_DIR}/include "/usr/include") 手动添加也是如此。因此无法正确找到 x.hpp 中的 #include &lt;iostream&gt;

错误日志有这个片段:

/usr/bin/gcc   -I/home/rein/projects/standalone/include    -o CMakeFiles/cmTryCompileExec4052324189.dir/CheckIncludeFiles.c.o   -c /home/rein/projects/standalone/build/CMakeFiles/CMakeTmp/CheckIncludeFiles.c
In file included from /home/rein/projects/standalone/build/CMakeFiles/CMakeTmp/CheckIncludeFiles.c:2:0:
/home/rein/projects/standalone/include/standalone/x.hpp:2:20: fatal error: iostream: No such file or directory
compilation terminated.

这本质上将检查自给自足的想法限制在系统 C 头文件中。看来我将不得不寻找shell script alternatives,例如这个SO question上的那个。

更新:感谢@Fraser 的更新答案,我的问题现在通过使用编译器标志执行check_include_file_cxx 得到解决,并包含预先设置的路径。

【讨论】:

    猜你喜欢
    • 2015-04-23
    • 2021-09-14
    • 1970-01-01
    • 1970-01-01
    • 2019-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多