Unresolved external symbols with git submodules - c++

I have a solution with 2 projects:
A static library (Almond)
A project that uses that static library (Sandbox)
I'm watching and following The Cherno's Game Engine Series except that I'm using C++20 modules. He added spdlog through git submodule add. I did the same thing. Then I added the $(SolutionDir)Almond\vendor\spdlog\include to Additional Include Directories in the Almond project.
The library builds fine (with a bunch of macro redefinition warnings from sal.h). When I try to build Sandbox I don't get any warnings just these errors:
Severity Code Description Project File Line Suppression State
Error LNK1120 4 unresolved externals Sandbox C:\source\Almond\bin\Debug-x64\Sandbox\Sandbox.exe 1
Error LNK2019 unresolved external symbol __imp_MapViewOfFileNuma2 referenced in function MapViewOfFile2 Sandbox C:\source\Almond\Sandbox\Almond.lib(stdout_color_sinks.h_D07BG2BYL2KQ67JA.obj) 1
Error LNK2001 unresolved external symbol __imp_MapViewOfFileNuma2 Sandbox C:\source\Almond\Sandbox\Almond.lib(spdlog.h_UEKL7NPFP4GR8605.obj) 1
Error LNK2001 unresolved external symbol "private: static class std::shared_ptr<class spdlog::logger> Almond::Log::s_CoreLogger" (?s_CoreLogger#Log#Almond##0V?$shared_ptr#Vlogger#spdlog###std##A::<!Log>) Sandbox C:\source\Almond\Sandbox\Almond.lib(Log.ixx.obj) 1
Error LNK2001 unresolved external symbol "private: static class std::shared_ptr<class spdlog::logger> Almond::Log::s_ClientLogger" (?s_ClientLogger#Log#Almond##0V?$shared_ptr#Vlogger#spdlog###std##A::<!Log>) Sandbox C:\source\Almond\Sandbox\Almond.lib(Log.ixx.obj) 1
Error LNK2001 unresolved external symbol "char const * const spdlog::details::os::default_eol" (?default_eol#os#details#spdlog##3QEBDEB) Sandbox C:\source\Almond\Sandbox\Almond.lib(Log.ixx.obj) 1
Relevant Code
Log.ixx (Almond):
export module Log;
import <memory>;
import <spdlog/spdlog.h>;
import <spdlog/sinks/stdout_color_sinks.h>;
export namespace Almond {
class Log {
private:
static std::shared_ptr<spdlog::logger> s_CoreLogger;
static std::shared_ptr<spdlog::logger> s_ClientLogger;
public:
static void Init() {
spdlog::set_pattern("%^[%T] %n: %v%$");
// Create multithreaded loggers
s_CoreLogger = spdlog::stdout_color_mt("ALMOND", spdlog::color_mode::always);
s_CoreLogger->set_level(spdlog::level::trace);
s_ClientLogger = spdlog::stdout_color_mt("APP", spdlog::color_mode::always);
s_ClientLogger->set_level(spdlog::level::trace);
}
inline static std::shared_ptr<spdlog::logger>& GetCoreLogger() { return s_CoreLogger; }
inline static std::shared_ptr<spdlog::logger>& GetClientLogger() { return s_ClientLogger; }
};
}
EntryPoint.ixx (Almond):
export module EntryPoint;
import Application;
import Log;
#ifdef ALMOND_PLATFORM_WINDOWS
export int main(int argc, char** argv) {
Almond::Log::Init();
auto app = Almond::CreateApplication();
app->Run();
delete app;
}
#endif
Main.cpp (Sandbox):
import Almond;
class Sandbox : public Almond::Application {
public:
Sandbox() {}
~Sandbox() {}
};
Almond::Application* Almond::CreateApplication() {
return new Sandbox();
}

A project that uses that static library
Is this project compiled as a shared (DLL) or static (.lib) library?
I assume you link your executable with the "A project that uses that static library". If so, you need to enable symbol visibility from that project.
I don't use VS, but CMake can handle that quite elegantly with GenerateExportHeader. You need to include __decl(dllexport) and __decl(dllimport) to your classes or make all symbol visibility public.
Windows makes all symbols private by default, while UNIX variants make them public by default.

Related

Static variable link error in MSVC even though it is created in the cpp file

I am working on a cross-platform (Linux & Windows) library. One of my class has a static member defined in the header. And I created it in a CPP file like
namespace raisim {
std::function<void()> RaiSimMsg::fatalCallback_ = []() { exit(1); };
}
The header file
#ifndef RAISIM_MESSAGE_LOGGER_HPP
#define RAISIM_MESSAGE_LOGGER_HPP
#include <chrono>
...
namespace raisim {
class RaiSimMsg {
public:
...
void stream(const char *file, const int line, std::stringstream &msg, int severity) {
if (severity == RSEVERITY_FATAL)
fatalCallback_();
}
private:
static std::function<void()> fatalCallback_;
};
}
#endif //RAISIM_MESSAGE_LOGGER_HPP
This works perfectly with GCC and Clang in Linux. But MSVC is giving a link error. Does MSVC have its own rules for static members??
Full error log
1>anymal.obj : error LNK2001: unresolved external symbol "private: static class std::function<void __cdecl(void)> raisim::RaiSimMsg::fatalCallback_" (?fatalCallback_#RaiSimMsg#raisim##0V?$function#$$A6AXXZ#std##A)
1>C:\Users\ultrafrog\source\repos\raisim\build\benchmark\Debug\speed_test_anymal.exe : fatal error LNK1120: 1 unresolved externals
1>Done building project "speed_test_anymal.vcxproj" -- FAILED.
Jack Dingler's answer here
https://www.codeproject.com/Questions/585271/Aplusstaticplusmemberplusvariableplusexportpluserr
worked. So the issue is that the Windows linker needs to know that if it has to import or export the symbol. So we have to declare __declspec(dllexport) when we export (when we build the library) and __declspec(dllimport) for using it. We can switch that using a compilation flag. I am not sure why they designed the linker like this but anyway it works now.

C++ DLL: unresolved external symbol

I seem to have some issues with creating new files for my project.
The issue is that in my sk_error.h file it seems to complain about unresolved external symbols (full error report below). When I place my OutOfRange class in my sk_interface.h file no one complains but when I put the class in the errors file it has issues with it.
If I was to comment out OutOfRange it works perfectly fine so I dont think that it is an issue with the DLL setup.
sk_error.h
#include <sk_platform.h>
#include <sk_interface.h>
namespace sky {
class SK_API OutOfRange : IError {
public:
OutOfRange() {
m_message = " Out Of Range";
m_value = (0 << 1);
}
std::string getMessage() override {
return m_message;
}
};
}
sk_platform.h
#if defined (SK_NONCLIENT_BUILD)
#ifndef SK_API
#define SK_API __declspec(dllexport)
#endif
#else
#ifndef SK_API
#define SK_API __declspec(dllimport)
#endif
#endif
sk_interface.h
#include <sk_platform.h>
#include <string>
namespace sky {
...
class SK_API IError {
public:
virtual std::string getMessage() = 0;
protected:
uint32_t m_value = 0;
std::string m_message = "Error not initialized";
};
}
The Client Project using the DLL
#include <sk_logmanager.h>
#include <sk_error.h>
#include <iostream>
int main() {
sky::g_LogManager.startup();
sky::OutOfRange err;
std::cout << err.getMessage() << "\n";
sky::g_LogManager.shutdown();
while (1) {}
}
Error Output
1>------ Build started: Project: SkyTest, Configuration: Debug Win32 ------
1>main.cpp
1>main.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: __thiscall sky::OutOfRange::OutOfRange(void)" (__imp_??0OutOfRange#sky##QAE#XZ) referenced in function _main
1>main.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: virtual class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __thiscall sky::OutOfRange::getMessage(void)" (__imp_?getMessage#OutOfRange#sky##UAE?AV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##XZ) referenced in function _main
1>main.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: __thiscall sky::OutOfRange::~OutOfRange(void)" (__imp_??1OutOfRange#sky##QAE#XZ) referenced in function _main
1>C:\Users\Matt\Documents\Game Development\DevEnv\SkyTest\Debug\SkyTest.exe : fatal error LNK1120: 3 unresolved externals
1>Done building project "SkyTest.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Edit:
I am using Visual Studio 2017 (could be the source of the error). The Client Project is using the .lib file.
An unresolved external is always a link error. It even has it in its name: LNK2019.
It is telling you it cannot find the implementation for sky::OutOfRange::OutOfRange()
You have it in a header somewhere and you've called it, but you have not linked to the library that implements it.
We have no way of telling you what library implements it or where it lives on your hard drive. You will have to consult the documentation for OutOfRange, the author of it, or yourself.
I can tell you that you will want to check:
right click the executable project->
properties->linker->general->additional library directories
properties->linker->input->additional dependencies
and make sure the path to the library that defines OutOfRange is in the former and the library name is in the latter.
EDIT: If the library itself has a header that imports it, as it appears from the code you posted, you just need to set up the additional directories part.
In the end, you have to consult the documentation for whatever library you are using or hit up their forums.
I am not sure but this may be related to your solution configuration and solution platform. It wasn't working for me, when I set my solution configuration to "Debug" and platform to "x64"; it started working after setting it to Release - x86

included header for static library giving dllimport error

I have the code presented later using Xerces-c, which can be built as a static or dynamic library. Failing to include of course results in a compiler error, however when I add #include <xercesc/util/PlatformUtils.hpp> visual studio 2012 gives me a linker errors saying:
1>main.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: static void __cdecl xercesc_3_1::XMLPlatformUtils::Initialize(char const * const,char const * const,class xercesc_3_1::PanicHandler * const,class xercesc_3_1::MemoryManager * const)" (__imp_?Initialize#XMLPlatformUtils#xercesc_3_1##SAXQBD0QAVPanicHandler#2#QAVMemoryManager#2##Z) referenced in function _main
1>main.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: static void __cdecl xercesc_3_1::XMLPlatformUtils::Terminate(void)" (__imp_?Terminate#XMLPlatformUtils#xercesc_3_1##SAXXZ) referenced in function __catch$_main$0
1>main.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) public: static char const * const xercesc_3_1::XMLUni::fgXercescDefaultLocale" (__imp_?fgXercescDefaultLocale#XMLUni#xercesc_3_1##2QBDB)
Based on the dllimport part of the error it seems that it's failing to find a dll. This is confirmed by that when I build Xerces-c as a dynamic library and link to it the error goes away. However if I build Xerces-c as a static library and link to it the same error remains. So my question is why am I getting an error asking for a dll when I'm including and linking to a static library?
using namespace xercesc;
int main(int argc, char* argv[])
{
std::ifstream inputFile(argv[1]);
char c = inputFile.get();
while (inputFile.good()) {
std::cout << c;
c = inputFile.get();
}
try {
XMLPlatformUtils::Initialize();
}
catch (const XMLException& toCatch) {
// Do your failure processing here
return 1;
}
// Do your actual work with Xerces-C++ here.
//XercesDOMParser parser;
//parser.useScanner(XMLUni::fgDGXMLScanner);
XMLPlatformUtils::Terminate();
// Other terminations and cleanup.
return 0;
}
You need to compile your application with XERCES_STATIC_LIBRARY preprocessor macro to disable DLL import/export for Xerces library.
Also check that you link against static version of .lib files.

Create & Using Dll's On MFC Application

I just created dll project in Visual Studio 2013:New Project->MFC DLL->Next->Check "MFC Extention DLL" and finish.Now, I add new class:
class CMyTest
{
public:
CMyTest();
~CMyTest();
int Test(){ return 1; }
};
Next, I compiled the project and got .lib,.dll files.
In the another project (who using the dll's) I just add the include,lib directory and copy the .dll file to the .exe file location and add the .lib file to Additional Dependency on Linker->Input.
Now, i just create some object from CMyTest class on my OnInitDialog() Method:
CMyTest x;
And when I tried to compiled the project I got Link error:
Error 3 error LNK2019: unresolved external symbol "public: __cdecl CMyTest::CMyTest(void)" (??0CMyTest##QEAA#XZ) referenced in function "protected: virtual int __cdecl CUsingDllProjectDlg::OnInitDialog(void)" (?OnInitDialog#CUsingDllProjectDlg##MEAAHXZ) C:\Users\user\documents\visual studio 2013\Projects\UsingDllProject\UsingDllProject\UsingDllProjectDlg.obj UsingDllProject
Error 4 error LNK2019: unresolved external symbol "public: __cdecl CMyTest::~CMyTest(void)" (??1CMyTest##QEAA#XZ) referenced in function "protected: virtual int __cdecl CUsingDllProjectDlg::OnInitDialog(void)" (?OnInitDialog#CUsingDllProjectDlg##MEAAHXZ) C:\Users\user\documents\visual studio 2013\Projects\UsingDllProject\UsingDllProject\UsingDllProjectDlg.obj UsingDllProject
Where is the problem?
You need to declare the Test method like that (and also the ctr,dctr):
__declspec(dllexport) int Test(){ return 1; }
__declspec(dllexport), instruct the linker to export a symbol to a DLL.you can read about that here: https://msdn.microsoft.com/en-us/library/dabb5z75(VS.80).aspx

error LNK2019: unresolved external symbol error

I'm getting these error messages
2>main.obj : error LNK2019: unresolved external symbol "public: __thiscall CEngine::CEngine(void)" (??0CEngine##QAE#XZ) referenced in function _WinMain#16
2>main.obj : error LNK2019: unresolved external symbol "public: void __thiscall CEngine::SetWindowSize(int,int,char const *,int)" (?SetWindowSize#CEngine##QAEXHHPBDH#Z) referenced in function _WinMain#16
2>main.obj : error LNK2019: unresolved external symbol "public: void __thiscall CEngine::Begin(void)" (?Begin#CEngine##QAEXXZ) referenced in function _WinMain#16
2>main.obj : error LNK2019: unresolved external symbol "public: int __thiscall CEngine::GetDisplayWidth(void)" (?GetDisplayWidth#CEngine##QAEHXZ) referenced in function _WinMain#16
2>main.obj : error LNK2019: unresolved external symbol "public: int __thiscall CEngine::GetDisplayHeight(void)" (?GetDisplayHeight#CEngine##QAEHXZ) referenced in function _WinMain#16
2>C:\Users\ethan\Desktop\C++ Projects\delveenginetest\Debug\delveenginetest.exe : fatal error LNK1120: 5 unresolved externals
This is my solution:
Solution 'delveenginetest' (2 projects)
DelveEngine
Include
delve.h
Engine.h
SetupSDL.h
stdafx.h
Engine.cpp
Main.cpp
SetupSDL.cpp
This is the code for Engine.h
#pragma once
#include "SetupSDL.h"
class CEngine
{
public:
CEngine(void);
~CEngine(void);
void SetWindowSize(int winW, int winH, const char* GameName, int windowMode);
void Begin(void);
int GetDisplayWidth(void);
int GetDisplayHeight(void);
private:
int deskW;
int deskH;
bool playing;
CSetupSDL* sdl_setup;
};
Code for Engine.cpp
#include "Include/stdafx.h"
#include "Include/Engine.h"
CEngine::CEngine(void)
{
playing = true;
deskW = GetSystemMetrics(SM_CXSCREEN);
deskH = GetSystemMetrics(SM_CYSCREEN);
}
CEngine::~CEngine(void)
{
}
void CEngine::SetWindowSize(int winW, int winH, const char* GameName, int windowMode)
{
// set up SDL for use
sdl_setup = new CSetupSDL(winW, winH, GameName, windowMode);
}
void CEngine::Begin(void)
{
while (playing && sdl_setup->GetMainEvent()->type != SDL_QUIT)
{
sdl_setup->Begin();
sdl_setup->End();
}
playing = false;
}
int CEngine::GetDisplayWidth(void){ return deskW; }
int CEngine::GetDisplayHeight(void){ return deskH; }
The DelveEngine project builds successfully, whereas the delveenginetest project fails.
What's wrong? I've looked everywhere for a reason, can't find one that suits me.
Despite the fact you're not providing all the sufficient information for a correct diagnosis of your problems, I'll try to share what I could imagine that might be the reasons for the linker errors:
I suppose the project delveenginetest you mention is meant to set up unit tests for the classes from the DelveEngine project.
Since you have a Main.cpp in your DelveEngine project, I'd guess it's simply build as an executable (successfully).
Your delveenginetest needs to link to the classes provided from the DelveEngine project, but that's actually not possible, since the .exe from DelveEngine can't be used for linking, you'll need a library to import it to another executable (the unit testing framework).
I'd recommend to separate out your classes/source files from DelveEngine project to make up a static or shared library, that can be linked from an application and the test framework simultaneously from within a single VS solution:
Solution 'DelveEngine' (3 projects)
DelveEngineLib (project [.lib/.dll])
Include
delve.h
Engine.h
SetupSDL.h
Engine.cpp
SetupSDL.cpp
DelveEngine (project [.exe])
Main.cpp
delveenginetest (project [.exe])
Main.cpp (TestFramework main definition)
Since I'm not very versed with it I don't know actually, if VS 2013 supports to setup projects consuming virtual resources (think of links to sources in the actual build environment), but this could be an alternative how to setup application and unit tests without need of an extra library.