如何让CMake检查我的标题是否自给自足?

时间:2013-05-07 22:08:49

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

设置

我有一个使用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!”没有警告。

问题

以上设置是正确的。但是假设<iostream>中没有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()也不起作用。 我需要做些什么才能使其正常工作?只有当正确的标题被认为是正确的时候,我才能继续测试不正确的标题。

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

2 个答案:

答案 0 :(得分:5)

对于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的更多信息。

答案 1 :(得分:1)

浏览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")手动添加也是如此。因此无法正确找到#include <iostream>内的x.hpp
  3. 错误日志包含以下片段:

    /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并包含事先设置的路径来解决我的问题。