Setup

I have a project that builds and runs fine with CMake. My project setup is like this:

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

The contents of my headers is like this:

// ------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();
}

I use the following 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})

The sequence of commands mkdir build, cd build, cmake .., make, and ./main correctly prints "Hello World!" without warnings.

Problem

The above setup is correct. But suppose <iostream> was not included in x.hpp but in main.cpp instead. Then the program would still have built correctly, but the x.hpp would not be a standalone header. So I would like to test for self-sufficiency of my headers, i.e. for every header I would like to compile a small test program

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

However, if I add the following section to the 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)

The macro ${header_files} correctly expands to the header x.hpp, but the check_include_files() command does not correctly compile it

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.

Question

Apparantly I am missing some configuration variable that lets CMake search in the right place. Even for correct headers, check_include_files() does not work. What do I need to do to make this work? Only when correct headers are deemed correct, can I go on and test incorrect headers.

NOTE Unless it's absolutey necessary, I am not interested in shell scripts or elaborate CMake for loops that directly call TRY_COMPILE or something like that. AFAICS, that's what the CheckIncludeFiles module is for, and I'd like to know how to correctly configure that, if at all possible.

有帮助吗?

解决方案

For C++ headers rather than C headers, you need to use CheckIncludeFileCXX. This module also differs from CheckIncludeFiles in that you can only pass a single file at a time to this macro.

It could well also be that you need to set CMAKE_REQUIRED_INCLUDES, or one of the other variables listed in the docs.

For example, if some of your headers refer to eachother (as in #include "h1.hpp"), then you'll need:

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()

There's a little more info in the CMake wiki article How To Write Platform Checks.

其他提示

After browsing the CMakeFiles/CMakeError.log output, it appeara there are two fundamental limitations to check_include_files() that cannot be overcome with the allowed configuration options (there appears to be some confirmation of these points):

  1. the C compiler is always called, not the C++ compiler. This means that -std=C++11 is not a valid command line option to pass.
  2. the standard system include paths (/usr/include etc.) are ignored even when added manually with set(CMAKE_REQUIRED_INCLUDES ${CMAKE_SOURCE_DIR}/include "/usr/include"). The #include <iostream> inside x.hpp is therefore not correctly found.

The error log has this fragment:

/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.

This essentially limits the idea of checking for self-sufficiency to system C headers. It appears I will have to seek out shell script alternatives, e.g. the one on this SO question.

UPDATE: thanks to @Fraser 's updated answer, my question is now resolved by doing check_include_file_cxx with the compiler flags and include paths set beforehand.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top