approvals / ApprovalTests.cpp

Native ApprovalTests for C++ on Linux, Mac and Windows
https://approvaltestscpp.readthedocs.io/en/latest/
Apache License 2.0
312 stars 51 forks source link

Help users fix missing symbols during linking after v.10.1.1 release, if misconfigured main #144

Closed claremacrae closed 4 years ago

claremacrae commented 4 years ago

I got this output on Windows in Visual Studio when building against v.10.1.1, and having not updated my main.

This is a change from the old "you have forgotten to set up your main" output...

[100%] Linking CXX executable exercise1.exe
LINK Pass 1: command "C:\PROGRA~2\MICROS~1\2019\COMMUN~1\VC\Tools\MSVC\1426~1.288\bin\Hostx86\x86\link.exe /nologo @CMakeFiles\exercise1.dir\objects1.rsp /out:exercise1.exe /implib:exercise1.lib /pdb:C:\Code\TestingLegacyCodeCourse.cpp\cmake-build-debug\exercises\exercise1\tests\exercise1.pdb /version:0.0 /machine:X86 /debug /INCREMENTAL /subsystem:console ..\code\exercise1_library.lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib /MANIFEST /MANIFESTFILE:CMakeFiles\exercise1.dir/intermediate.manifest CMakeFiles\exercise1.dir/manifest.res" failed (exit code 1120) with the following output:
Test.cpp.obj : error LNK2019: unresolved external symbol "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl ApprovalTests::Scrubbers::doNothing(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)" (?doNothing@Scrubbers@ApprovalTests@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@ABV34@@Z) referenced in function "public: __thiscall ApprovalTests::Options::Options(void)" (??0Options@ApprovalTests@@QAE@XZ)
Test.cpp.obj : error LNK2019: unresolved external symbol "public: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const & __thiscall ApprovalTests::Options::FileOptions::getFileExtension(void)const " (?getFileExtension@FileOptions@Options@ApprovalTests@@QBEABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ) referenced in function "public: static void __cdecl ApprovalTests::TApprovals<struct ApprovalTests::ToStringCompileTimeOptions<class ApprovalTests::StringMaker> >::verify(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class ApprovalTests::Options const &)" (?verify@?$TApprovals@U?$ToStringCompileTimeOptions@VStringMaker@ApprovalTests@@@ApprovalTests@@@ApprovalTests@@SAXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@ABVOptions@2@@Z)
Test.cpp.obj : error LNK2019: unresolved external symbol "private: static class ApprovalTests::Reporter const & __cdecl ApprovalTests::Options::defaultReporter(void)" (?defaultReporter@Options@ApprovalTests@@CAABVReporter@2@XZ) referenced in function "public: __thiscall ApprovalTests::Options::Options(void)" (??0Options@ApprovalTests@@QAE@XZ)
Test.cpp.obj : error LNK2019: unresolved external symbol "public: class ApprovalTests::Options::FileOptions __thiscall ApprovalTests::Options::fileOptions(void)const " (?fileOptions@Options@ApprovalTests@@QBE?AVFileOptions@12@XZ) referenced in function "public: static void __cdecl ApprovalTests::TApprovals<struct ApprovalTests::ToStringCompileTimeOptions<class ApprovalTests::StringMaker> >::verify(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class ApprovalTests::Options const &)" (?verify@?$TApprovals@U?$ToStringCompileTimeOptions@VStringMaker@ApprovalTests@@@ApprovalTests@@@ApprovalTests@@SAXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@ABVOptions@2@@Z)
Test.cpp.obj : error LNK2019: unresolved external symbol "public: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __thiscall ApprovalTests::Options::scrub(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)const " (?scrub@Options@ApprovalTests@@QBE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@ABV34@@Z) referenced in function "public: static void __cdecl ApprovalTests::TApprovals<struct ApprovalTests::ToStringCompileTimeOptions<class ApprovalTests::StringMaker> >::verify(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class ApprovalTests::Options const &)" (?verify@?$TApprovals@U?$ToStringCompileTimeOptions@VStringMaker@ApprovalTests@@@ApprovalTests@@@ApprovalTests@@SAXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@ABVOptions@2@@Z)
Test.cpp.obj : error LNK2019: unresolved external symbol "public: class ApprovalTests::Reporter const & __thiscall ApprovalTests::Options::getReporter(void)const " (?getReporter@Options@ApprovalTests@@QBEABVReporter@2@XZ) referenced in function "public: static void __cdecl ApprovalTests::TApprovals<struct ApprovalTests::ToStringCompileTimeOptions<class ApprovalTests::StringMaker> >::verify(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class ApprovalTests::Options const &)" (?verify@?$TApprovals@U?$ToStringCompileTimeOptions@VStringMaker@ApprovalTests@@@ApprovalTests@@@ApprovalTests@@SAXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@ABVOptions@2@@Z)
Test.cpp.obj : error LNK2019: unresolved external symbol "public: static class std::function<class std::shared_ptr<class ApprovalTests::ApprovalNamer> __cdecl(void)> __cdecl ApprovalTests::DefaultNamerFactory::getDefaultNamer(void)" (?getDefaultNamer@DefaultNamerFactory@ApprovalTests@@SA?AV?$function@$$A6A?AV?$shared_ptr@VApprovalNamer@ApprovalTests@@@std@@XZ@std@@XZ) referenced in function "public: static class std::shared_ptr<class ApprovalTests::ApprovalNamer> __cdecl ApprovalTests::TApprovals<struct ApprovalTests::ToStringCompileTimeOptions<class ApprovalTests::StringMaker> >::getDefaultNamer(void)" (?getDefaultNamer@?$TApprovals@U?$ToStringCompileTimeOptions@VStringMaker@ApprovalTests@@@ApprovalTests@@@ApprovalTests@@SA?AV?$shared_ptr@VApprovalNamer@ApprovalTests@@@std@@XZ)
Test.cpp.obj : error LNK2019: unresolved external symbol "public: __thiscall ApprovalTests::StringWriter::StringWriter(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (??0StringWriter@ApprovalTests@@QAE@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@0@Z) referenced in function "public: static void __cdecl ApprovalTests::TApprovals<struct ApprovalTests::ToStringCompileTimeOptions<class ApprovalTests::StringMaker> >::verify(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class ApprovalTests::Options const &)" (?verify@?$TApprovals@U?$ToStringCompileTimeOptions@VStringMaker@ApprovalTests@@@ApprovalTests@@@ApprovalTests@@SAXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@ABVOptions@2@@Z)
Test.cpp.obj : error LNK2019: unresolved external symbol "public: static void __cdecl ApprovalTests::FileApprover::verify(class ApprovalTests::ApprovalNamer const &,class ApprovalTests::ApprovalWriter const &,class ApprovalTests::Reporter const &)" (?verify@FileApprover@ApprovalTests@@SAXABVApprovalNamer@2@ABVApprovalWriter@2@ABVReporter@2@@Z) referenced in function "public: static void __cdecl ApprovalTests::TApprovals<struct ApprovalTests::ToStringCompileTimeOptions<class ApprovalTests::StringMaker> >::verify(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,class ApprovalTests::Options const &)" (?verify@?$TApprovals@U?$ToStringCompileTimeOptions@VStringMaker@ApprovalTests@@@ApprovalTests@@@ApprovalTests@@SAXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@ABVOptions@2@@Z)
exercise1.exe : fatal error LNK1120: 9 unresolved externals

This is because those functions are now implemented code that is only compiled when the Approved code in main() is activated via the preprocessor...

We just need to update the Troubleshooting doc to describe this.

claremacrae commented 4 years ago

This is much less helpful than the old "You have forgotten to configure your main", unfortunately.

claremacrae commented 4 years ago

The linker output on Mac with clang-9 is:

Undefined symbols for architecture x86_64:
  "ApprovalTests::FileApprover::verify(ApprovalTests::ApprovalNamer const&, ApprovalTests::ApprovalWriter const&, ApprovalTests::Reporter const&)", referenced from:
      ApprovalTests::TApprovals<ApprovalTests::ToStringCompileTimeOptions<ApprovalTests::StringMaker> >::verify(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, ApprovalTests::Options const&) in HelloApprovalsTests.cpp.o
  "ApprovalTests::StringWriter::StringWriter(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >)", referenced from:
      ApprovalTests::TApprovals<ApprovalTests::ToStringCompileTimeOptions<ApprovalTests::StringMaker> >::verify(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, ApprovalTests::Options const&) in HelloApprovalsTests.cpp.o
  "ApprovalTests::DefaultNamerFactory::getDefaultNamer()", referenced from:
      ApprovalTests::TApprovals<ApprovalTests::ToStringCompileTimeOptions<ApprovalTests::StringMaker> >::getDefaultNamer() in HelloApprovalsTests.cpp.o
  "ApprovalTests::Options::defaultReporter()", referenced from:
      ApprovalTests::Options::Options() in HelloApprovalsTests.cpp.o
  "ApprovalTests::Scrubbers::doNothing(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)", referenced from:
      ApprovalTests::Options::Options() in HelloApprovalsTests.cpp.o
  "ApprovalTests::Options::FileOptions::getFileExtension() const", referenced from:
      ApprovalTests::TApprovals<ApprovalTests::ToStringCompileTimeOptions<ApprovalTests::StringMaker> >::verify(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, ApprovalTests::Options const&) in HelloApprovalsTests.cpp.o
  "ApprovalTests::Options::fileOptions() const", referenced from:
      ApprovalTests::TApprovals<ApprovalTests::ToStringCompileTimeOptions<ApprovalTests::StringMaker> >::verify(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, ApprovalTests::Options const&) in HelloApprovalsTests.cpp.o
  "ApprovalTests::Options::getReporter() const", referenced from:
      ApprovalTests::TApprovals<ApprovalTests::ToStringCompileTimeOptions<ApprovalTests::StringMaker> >::verify(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, ApprovalTests::Options const&) in HelloApprovalsTests.cpp.o
  "ApprovalTests::Options::scrub(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) const", referenced from:
      ApprovalTests::TApprovals<ApprovalTests::ToStringCompileTimeOptions<ApprovalTests::StringMaker> >::verify(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, ApprovalTests::Options const&) in HelloApprovalsTests.cpp.o
  "vtable for ApprovalTests::StringWriter", referenced from:
      ApprovalTests::StringWriter::~StringWriter() in HelloApprovalsTests.cpp.o
  NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
claremacrae commented 4 years ago

This is fixed by:

claremacrae commented 4 years ago

(it will be included in the next release)

claremacrae commented 3 years ago

It turns out that builds that link against the ApprovalTests.cpp source tree - such as via CMake's FetchContent - still give the help message if main is not configured.

It's only the builds with the single-header that give missing symbol linker-errors instead.