Неразрешенные ошибки внешнего символа при использовании Catch2

Я пытаюсь выполнить модульное тестирование Catch2 в Visual Studio. Я создал небольшой тестовый проект для практики. Когда я пытаюсь скомпилировать этот тестовый проект, я получаю ошибку компоновщика. Сейчас я пытаюсь диагностировать эту ошибку компоновщика, но заголовочный файл Catch2.hpp содержит тысячи строк кода. Я надеюсь, что кто-то, кто лучше знаком с Catch2 или модульным тестированием в целом, сможет диагностировать проблему.

Я опишу процесс создания этого проекта. Я создал новый проект в новом решении. У меня есть 4 файла, все в одном каталоге, перечисленные ниже.

Класс, который я хочу протестировать:

//a.h

#pragma once

class A {
    friend int A_Tester_Func1(A a);
public:
    A(int num) : my_num_(num) {
    }
private:
    int my_num_;
};

Тест:

//atester.cpp

#pragma once

#include "catch.hpp"
#include "a.h"

int A_Tester_Func1(A a) {
    return a.my_num_;
}

TEST_CASE("a contains a positive integer", "[a]") {
    //...
    A a(3);
    REQUIRE(A_Tester_Func1(a) == 3);

}

Основная функция, которая запускает тесты:

//tester.cpp

#define CATCH_CONFIG_MAIN
#include "catch.hpp" // this should create the main function

Платформа тестирования Catch2:

// catch.hpp

/*
 *  Catch v2.13.2
 *  Generated: 2020-10-07 11:32:53.302017
*/

//~17-18k lines of code that from Catch2

#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED

Когда я пытаюсь скомпилировать этот код в Visual Studio с помощью кнопки локального отладчика Windows, я получаю кучу ошибок компоновщика Unresolved External Symbol. Кажется, я где-то читал, что Catch2 частично скомпилирован. Может быть, это как-то связано с этим, но я не знаю. Следуя этому руководству (StackOverflow: рекомендации по модульному тестированию с Catch2 в Visual Studio) сработал, но я пытаюсь понять, почему приведенный выше небольшой пример не связывается успешно.

Я включил ошибки компоновщика ниже для полноты, хотя я чувствую, что они, вероятно, не понадобятся для вопроса.

1>atester.obj : error LNK2019: unresolved external symbol "public: __thiscall Catch::StringRef::StringRef(char const *)" (??0StringRef@Catch@@QAE@PBD@Z) referenced in function "public: class Catch::BinaryExpr<int const &,int const &> const __thiscall Catch::ExprLhs<int const &>::operator==<int>(int const &)" (??$?8H@?$ExprLhs@ABH@Catch@@QAE?BV?$BinaryExpr@ABHABH@1@ABH@Z)
1>atester.obj : error LNK2019: unresolved external symbol "struct Catch::ITestInvoker * __cdecl Catch::makeTestInvoker(void (__cdecl*)(void))" (?makeTestInvoker@Catch@@YAPAUITestInvoker@1@P6AXXZ@Z) referenced in function "void __cdecl `anonymous namespace'::`dynamic initializer for 'autoRegistrar1''(void)" (??__EautoRegistrar1@?A0xf9ca9c7d@@YAXXZ)
1>atester.obj : error LNK2019: unresolved external symbol "public: __thiscall Catch::NameAndTags::NameAndTags(class Catch::StringRef const &,class Catch::StringRef const &)" (??0NameAndTags@Catch@@QAE@ABVStringRef@1@0@Z) referenced in function "void __cdecl `anonymous namespace'::`dynamic initializer for 'autoRegistrar1''(void)" (??__EautoRegistrar1@?A0xf9ca9c7d@@YAXXZ)
1>atester.obj : error LNK2019: unresolved external symbol "public: __thiscall Catch::AutoReg::AutoReg(struct Catch::ITestInvoker *,struct Catch::SourceLineInfo const &,class Catch::StringRef const &,struct Catch::NameAndTags const &)" (??0AutoReg@Catch@@QAE@PAUITestInvoker@1@ABUSourceLineInfo@1@ABVStringRef@1@ABUNameAndTags@1@@Z) referenced in function "void __cdecl `anonymous namespace'::`dynamic initializer for 'autoRegistrar1''(void)" (??__EautoRegistrar1@?A0xf9ca9c7d@@YAXXZ)
1>atester.obj : error LNK2019: unresolved external symbol "public: virtual __thiscall Catch::AutoReg::~AutoReg(void)" (??1AutoReg@Catch@@UAE@XZ) referenced in function "void __cdecl `anonymous namespace'::`dynamic atexit destructor for 'autoRegistrar1''(void)" (??__FautoRegistrar1@?A0xf9ca9c7d@@YAXXZ)
1>atester.obj : error LNK2019: unresolved external symbol "public: static class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl Catch::StringMaker<int,void>::convert(int)" (?convert@?$StringMaker@HX@Catch@@SA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@H@Z) referenced in function "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl Catch::Detail::stringify<int>(int const &)" (??$stringify@H@Detail@Catch@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@ABH@Z)
1>atester.obj : error LNK2019: unresolved external symbol "public: virtual __thiscall Catch::ITransientExpression::~ITransientExpression(void)" (??1ITransientExpression@Catch@@UAE@XZ) referenced in function "public: virtual __thiscall Catch::BinaryExpr<int const &,int const &>::~BinaryExpr<int const &,int const &>(void)" (??1?$BinaryExpr@ABHABH@Catch@@UAE@XZ)
1>atester.obj : error LNK2019: unresolved external symbol "void __cdecl Catch::formatReconstructedExpression(class std::basic_ostream<char,struct std::char_traits<char> > &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class Catch::StringRef,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)" (?formatReconstructedExpression@Catch@@YAXAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@3@VStringRef@1@1@Z) referenced in function "private: virtual void __thiscall Catch::BinaryExpr<int const &,int const &>::streamReconstructedExpression(class std::basic_ostream<char,struct std::char_traits<char> > &)const " (?streamReconstructedExpression@?$BinaryExpr@ABHABH@Catch@@EBEXAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@@Z)
1>atester.obj : error LNK2019: unresolved external symbol "public: __thiscall Catch::AssertionHandler::AssertionHandler(class Catch::StringRef const &,struct Catch::SourceLineInfo const &,class Catch::StringRef,enum Catch::ResultDisposition::Flags)" (??0AssertionHandler@Catch@@QAE@ABVStringRef@1@ABUSourceLineInfo@1@V21@W4Flags@ResultDisposition@1@@Z) referenced in function "void __cdecl ____C_A_T_C_H____T_E_S_T____0(void)" (?____C_A_T_C_H____T_E_S_T____0@@YAXXZ)
1>atester.obj : error LNK2019: unresolved external symbol "public: void __thiscall Catch::AssertionHandler::handleExpr(struct Catch::ITransientExpression const &)" (?handleExpr@AssertionHandler@Catch@@QAEXABUITransientExpression@2@@Z) referenced in function "void __cdecl ____C_A_T_C_H____T_E_S_T____0(void)" (?____C_A_T_C_H____T_E_S_T____0@@YAXXZ)
1>atester.obj : error LNK2019: unresolved external symbol "public: void __thiscall Catch::AssertionHandler::handleUnexpectedInflightException(void)" (?handleUnexpectedInflightException@AssertionHandler@Catch@@QAEXXZ) referenced in function __catch$?____C_A_T_C_H____T_E_S_T____0@@YAXXZ$0
1>atester.obj : error LNK2019: unresolved external symbol "public: void __thiscall Catch::AssertionHandler::complete(void)" (?complete@AssertionHandler@Catch@@QAEXXZ) referenced in function __catch$?____C_A_T_C_H____T_E_S_T____0@@YAXXZ$0
1>MSVCRTD.lib(exe_main.obj) : error LNK2019: unresolved external symbol _main referenced in function "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ)

Что вызывает эти ошибки? Как исправить эти ошибки, оставив catch.hpp в том же проекте, что и мои исходные файлы?


person mana    schedule 21.10.2020    source источник


Ответы (2)


В файле .cpp добавьте это, чтобы сделать проект запускателем тестов Catch2:

#define CATCH_CONFIG_RUNNER
#include "catch.hpp"

Подробнее читайте на странице Поставка main() самостоятельно

person Scott Hutchinson    schedule 23.11.2020
comment
Это не отвечает на вопрос. - person mana; 24.11.2020
comment
Ах, извините, теперь я вижу, что у вас уже есть #define CATCH_CONFIG_MAIN. Если бы этого не было, то, я думаю, это вызвало бы точно такие же ошибки. Возможно, #define CATCH_CONFIG_MAIN находится не в одном месте или не в том месте в вашем проекте. - person Scott Hutchinson; 25.11.2020
comment
мое решение состояло в том, чтобы перенести тесты catch2 в отдельный проект и скомпилировать мой основной проект как статическую библиотеку. Я не уверен, что это необходимо (о чем вопрос), но это сработало. - person mana; 25.11.2020
comment
У нас есть все наши тесты Catch2 в исполняемом проекте нашего приложения. Так что я знаю, что это может работать нормально. Хотя не уверен, что это лучшая практика. Я думаю, что я бы предпочел иметь их в отдельном проекте, но тогда вам, возможно, придется предоставить API только для тестирования. - person Scott Hutchinson; 26.11.2020

  1. atester.cpp не должно иметь директивы #pragma once. Это для файлов заголовков, и хотя это может не быть вашим источником проблем, оно просто не принадлежит вам. Поскольку вы не предоставляете достаточно подробностей (а именно: где находится свернутый файл проекта?), я должен быть консервативен здесь.

  2. Кажется, что tester.cpp не является частью проекта, который вы создаете. Тот факт, что этот файл существует на диске, не означает, что он автоматически подхватывается. Вы должны вручную добавить его в проект MSVC. Вот и все. Я постоянно использую Catch2 с MSVS, и этого достаточно, чтобы заставить его работать.

person Kuba hasn't forgotten Monica    schedule 26.07.2021