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

Add meaningful help message inside post v.10.1.1 linker errors for misconfigured main, built with single header. #173

Closed claremacrae closed 3 years ago

claremacrae commented 3 years ago

This would be an improvement over the docs added in #144.

It would mean changing the missing symbol output to look something like:

[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)
+Test.cpp.obj : error LNK2019: unresolved external symbol "public: static void __cdecl ApprovalTests::FileApprover::YOU_HAVE_FORGOTTEN_TO_CONFIGURE_YOUR_MAIN_FOR_APPROVAL_TESTS(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

Llewellyn demoed a fix for this some time ago - it would be great to get it checked in...

From looking at the linker errors, the message needs to be injected at the first non-inlined function call that code will reach, via common calls to:

Those are all templated, so inlined - and they all ultimately call ApprovalTests::FileApprover::verify()

So somehow injecting a symbol called "you_have_forgotten_to_link..." would probably do the trick.

We would have to be careful to avoid illegal symbol names though.

claremacrae commented 3 years ago

Closing, having realised that this is a duplicate of #145