c++cmakecatch2

catch2 single-include causes "undefined reference" in test


I have seen plenty of examples with the same issue, but they did not apply to my situation.

I have the following file structure:

unit-tests/CMakeLists.txt
unit-tests/FlaAlgoTests/CMakeLists.txt
unit-tests/FlaAlgoTests/catch_test_runner.cpp

In Proj/CMakeLists.txt:

ExternalProject_Add(
        catch
        PREFIX ${CMAKE_BINARY_DIR}/catch2
        GIT_REPOSITORY https://github.com/catchorg/Catch2.git
        TIMEOUT 10
        UPDATE_COMMAND ${GIT_EXECUTABLE} pull
        CONFIGURE_COMMAND ""
        BUILD_COMMAND ""
        INSTALL_COMMAND ""
        LOG_DOWNLOAD ON
)
ExternalProject_Get_Property(catch source_dir)
include_directories(${source_dir}/single_include/catch2)

And in Proj/TestDir1/CMakeLists.txt:

add_executable(
        catch_test_runner
        catch_test_runner.cpp
)

Where catch_test_runner.cpp is:

#include <iostream>
#include "catch.hpp"

#define CATCH_CONFIG_MAIN

TEST_CASE("Yeet", "[beep]"){
    REQUIRE(true);
    REQUIRE(2 == 1);
}

All of this looks perfectly fine and seems to be basically a copy/paste of numerous guides I have found for this. However, I get the following issue:

[100%] Linking CXX executable catch_test_runner.exe
CMakeFiles/catch_test_runner.dir/catch_test_runner.o: In function `::____C_A_T_C_H____T_E_S_T__(void)':
/cygdrive/c/Users/dbak/Projects/firmware/unit-tests/FlaAlgoTests/catch_test_runner.cpp:7: undefined reference to `Catch::StringRef::StringRef(char const*)'
/cygdrive/c/Users/dbak/Projects/firmware/unit-tests/FlaAlgoTests/catch_test_runner.cpp:7:(.text+0x32): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `Catch::StringRef::StringRef(char const*)'
/cygdrive/c/Users/dbak/Projects/firmware/unit-tests/FlaAlgoTests/catch_test_runner.cpp:7: undefined reference to `Catch::AssertionHandler::AssertionHandler(Catch::StringRef const&, Catch::SourceLineInfo const&, Catch::StringRef, Catch::ResultDisposition::Flags)'

So, obviously it's able to link to catch.hpp, otherwise it wouldn't be able to find any of this stuff. And obviously I am using the single_include version of catch, which is the issue all of the examples I found of the same issue had.

What am I doing incorrectly?


Solution

  • The line #define CATCH_CONFIG_MAIN tells catch.hpp header that it should emit Catch implementation too. But for that purpose, this line should come before including of catch.hpp:

    #define CATCH_CONFIG_MAIN // This should come **before** including the 'catch.hpp'.
    #include "catch.hpp"