Как я могу позволить CMake проверить, являются ли мои заголовки самодостаточными?

Настроить

У меня есть проект, который прекрасно работает и работает с 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 build, cd build, cmake .., make, а также ./main правильно печатает «Hello World!» без предупреждений.

проблема

Вышеуказанная настройка верна. Но предположим <iostream> не был включен в x.hpp но в main.cpp вместо. Тогда программа все равно была бы построена правильно, но x.hpp не будет автономным заголовком. Поэтому я хотел бы проверить самодостаточность моих заголовков, т.е. для каждого заголовка я хотел бы собрать небольшую тестовую программу

#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() не работает. Что мне нужно сделать, чтобы сделать эту работу? Только когда правильные заголовки считаются правильными, я могу продолжить и проверить неправильные заголовки.

НОТА Если это не
абсолютно необходимо, меня не интересуют сценарии оболочки или разработка CMake для циклов, которые напрямую вызывают TRY_COMPILE или что-то типа того. AFAICS, вот что CheckIncludeFiles Модуль для, и я хотел бы знать, как правильно настроить это, если это вообще возможно.

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 Как писать проверки платформ.

5

Другие решения

После просмотра CMakeFiles/CMakeError.log вывод, кажется, есть два фундаментальных ограничения check_include_files() это не может быть преодолено с помощью разрешенных параметров конфигурации (кажется, некоторое подтверждение из этих пунктов):

  1. Компилятор Си всегда вызывается, а не компилятор C ++. Это означает, что -std=C++11 не является допустимым параметром командной строки для передачи.
  2. стандартная система включает пути (/usr/include так далее.) игнорируются даже при добавлении вручную с set(CMAKE_REQUIRED_INCLUDES ${CMAKE_SOURCE_DIR}/include "/usr/include"), #include <iostream> внутри x.hpp поэтому не правильно найден.

Журнал ошибок имеет этот фрагмент:

/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. Похоже, мне придется искать альтернативы сценария оболочки, например тот на этом ТАК вопрос.

ОБНОВИТЬ: благодаря обновленному ответу @Fraser мой вопрос теперь решается с помощью check_include_file_cxx с флагами компилятора и предварительно заданными путями.

1

По вопросам рекламы [email protected]