Как использовать CMake с Catch2?

Из примера Catch2 я попытался запустить этот пример с cmake где структура моего проекта такая:

/factorial
    +-- CMakeLists.txt
    +-- /bin
    +-- /include
    |     +-- catch.hpp
    |     +-- fact.hpp 
    +-- /src
    |     +-- CMakeLists.txt
    |    +-- fact.cpp
    +-- /test
         +-- CMakeLists.txt
         +-- test_fact.cpp

fact.cpp:

unsigned int factorial( unsigned int number ) {
    return number <= 1 ? number : factorial(number-1)*number;
}

fact.hpp:

#ifndef FACT_H
#define FACT_H

unsigned int factorial(unsigned int);

#endif

test_fact.cpp:

#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include "fact.hpp"

TEST_CASE( "factorials are computed", "[factorial]" ) {
    REQUIRE( factorial(1) == 1 );
    REQUIRE( factorial(2) == 2 );
    REQUIRE( factorial(3) == 6 );
    REQUIRE( factorial(10) == 3628800 );
}

Я уже пробовал несколько способов построить этот проект с cmake но это не удалось. Иногда я получаю ошибку:

cpp:X:XX: fatal error: 'fact.hpp' file not found
...

и иногда я получаю:

Undefined symbols for architecture x86_64:
  "_main", referenced from:
...

когда я бегу make,

Что я должен иметь в factorial/CMakeLists.txt,factorial/src/CMakeLists.txt а также factorial/test/CMakeLists.txt, если я хочу, чтобы мои файлы выполнения в factorial/bin?

Дополнительно: это мой CMakeLists.txts (я думаю, что они совершенно не правы).

factorial/CMakeLists.txt:

project(factorial)
cmake_minimum_required(VERSION 2.8.12)

add_definitions("-std=c++11")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)

add_subdirectory(src)
add_subdirectory(test)

factorial/src/CMakeLists.txt:

project(factorial)
cmake_minimum_required(VERSION 2.8.12)

add_executable(fact fact.cpp)

factorial/test/CMakeLists.txt:

project(factorial)
cmake_minimum_required(VERSION 2.8.12)

add_executable(test_fact test_fact.cpp)
target_include_directories(test_fact PRIVATE ${CMAKE_SOURCE_DIR}/include)

2 ответа

Решение

Здесь много проблем:

add_executable(fact fact.cpp)

Вызов должен использовать add_library (Вы также можете указать STATIC или же SHARED), поскольку вы определяете только факториальную функцию, а не исполняемый файл с main функция

add_executable(fact fact.cpp)

Файл должен быть test_fact.cpp, Кроме того, ваш fact.cpp не включает fact.hpp, Не в последнюю очередь, вместо того, чтобы делать target_include_directories, просто напишите следующее на вашем верхнем уровне CMakeLists.txt:

include_directories(include)

Теперь все подкаталоги должны иметь доступ к заголовочным файлам. Помните, что это удаляет контроль над областью заголовочных файлов (PRIVATE против PUBLIC против INTERFACE) и позволяет всем подкаталогам получать доступ к файлам заголовков. Если вы хотите ограничить это поведение, используйте target_include_direcories для всех целей (Ваша библиотека и исполняемый файл теста). В этом примере, так как все должно иметь доступ к файлам заголовка, с заявлением выше проблем нет.

Больше проблем:

project(factorial)
cmake_minimum_required(VERSION 2.8.12)

Либо поменяйте порядок этих утверждений, либо удалите оба. (Они нужны только в вашем файле CMake верхнего уровня)

Если вы посмотрите на документацию CMake, то PROJECT_SOURCE_DIR переменная определяется так:

Исходный каталог верхнего уровня для текущего проекта.

Это исходный каталог самой последней команды project().

Так как ты звонил project много раз, эта переменная будет постоянно меняться. Я бы предложил вам удалить директиву проекта или использовать CMAKE_SOURCE_DIR, которые всегда указывают на исходный каталог всего проекта.


В качестве примечания, я предлагаю использовать set(CMAKE_CXX_STANDARD 11) вместо add_definition

Другие вопросы по тегам