I'm having a hard time compiling a C/C++ dll on Visual Studio. It seems to be linked to CRT library.
A simple VS c++ dll project. Just removed recompiled header, and added /NOENTRY. Exporting methods is working, but a simple class (not intended to be exported) raises a lot of linking error with CRT library:
Test.h:
class ITest
{
public:
virtual void foo() = 0;
}
class Test final : public ITest
{
public:
Test();
~Test();
void foo();
};
// extern "C" __declspec(dllexport) ITest* __cdecl CreateTest();
Test.cpp
#include "Test.h"
Test::Test() {}
Test::~Test() {}
Test::foo() {}
// extern "C" __declspec(dllexport) ITest* __cdecl CreateTest() { return new Test; }
errors:
Test.obj : error LNK2001: unresolved external symbol _purecall
msvcrt.lib(delete_scalar.obj) : error LNK2019: unresolved external symbol free referenced in function "void __cdecl operator delete(void *)" (??3#YAXPEAX#Z)
Uncommenting the export raises more msvcrt.lib link errors and changing the runtime library for MDd, MT, MTd changes only the library referenced.
Thanks you for any help :)
The problem comes from /NOENTRY option in Project Properties->Linker->Advanced->No Entry Point. Removing it solved the problem
/NOENTRY is for creating dlls which don't have any code at all and only contiain bitmaps etc: https://learn.microsoft.com/en-us/cpp/build/creating-a-resource-only-dll?view=vs-2017
As the dll (should) have no code visual studio doesn't link in the runtime library either, but as there is code it generates requirements for the runtime library symbols which are unresolved.
Related
Similar to LNK2005 Error in CLR Windows Form, yet this answer cannot explain what I've met.
My question is at the end of the description, thanks for the patience.
The project structure is as below (I simplify the situation to demonstrate the problem I met, which does not make any sense in real development):
Environment: Visual Studio 2019
Configuration: Debug/x86
OpenCV 420: I compile it to a dynamic library (.lib+.dll) myself because the x86 version is not provided officially.
Project2: pure C++, output type: lib
// ClassB.h
#pragma once
#include <opencv2/opencv.hpp>
class ClassB
{
public:
void FuncB();
};
// ClassB.cpp
#include "ClassB.h"
void ClassB::FuncB() {
cv::Mat mat;
}
Project3: C++ with /clr on, output type: dll for .NET Framework v4.6.1
// ClassC.h
#pragma once
#include <iostream>
#include <opencv2/opencv.hpp>
class __declspec(dllexport) ClassC
{
};
// ClassC.cpp
#include "ClassC.h"
Link against (the input libs order matters, will explain later)
opencv_world420d.lib (it's just an import library, at runtime use opencv_world420d.dll)
Project2.lib
And the compiler throws errors:
LNK2005 "public: __thiscall cv::MatSize::MatSize(int *)" (??0MatSize#cv##QAE#PAH#Z) already defined in opencv_world420d.lib(opencv_world420d.dll) Project3 (ClassB.obj) 1
LNK2005 "public: __thiscall cv::MatStep::MatStep(unsigned int)" (??0MatStep#cv##QAE#I#Z) already defined in opencv_world420d.lib(opencv_world420d.dll) Project3 (ClassB.obj) 1
After some digging, I suppose it is because there're some inline functions in mat.inl.hpp header file which is needed by class Mat and included byopencv.hpp(indirectly though), as below:
inline
MatStep::MatStep(size_t s)
{
p = buf; p[0] = s; p[1] = 0;
}
Maybe the compiler decided not to inline the functions, but indexed them into Project2.lib, to assure, I dump the two libs:
// Project2.lib
8B6 00000000 SECT109 notype () External | ??0MatSize#cv##QAE#PAH#Z (public: __thiscall cv::MatSize::MatSize(int *))
// opencv_world420d.lib
??0MatSize#cv##QAE#PAH#Z (public: __thiscall cv::MatSize::MatSize(int *))
As far as I know, SECT109 and External do mean that Project2.lib has complete definition of cv::MatSize::MatSize(int *), so do opencv_420world420d.lib
However, I explore 3 separate ways out to pass the compilation
Solution 1
swap the linking order to:
Project2.lib
opencv_world420d.lib
Solution 2
Turn the Project3 /clr off, make it a pure C++ project
Solution 3
MakeClassB::FuncBinline:
// ClassB.h
#pragma once
#include <opencv2/opencv.hpp>
class ClassB
{
public:
void FuncB() {
cv::Mat mat(100, 200, CV_8U);
}
};
// ClassB.cpp
#include "ClassB.h"
For solution1/2, I don't even touch Project2, so obviously ??0MatSize#cv##QAE#PAH#Z still exists in Project2.lib (so I don't understand how the compilation succeed).
For solution3, ??0MatSize#cv##QAE#PAH#Z disappears in Project2.lib (again I dumped the lib file and search the function name), so this does make sense to me.
In conclusion, my questions are:
Why solution 1 works, by just swapping the input libs order?
Why solution 2 works, by just switching off /clr for Project3 whose output target is dll?
OpenCV puts inline implementation in their hpp file, I wonder if it is a safe and good way to do so?
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.
I normally work in c# and am out of my wits for this one . I used Walkthrough: Creating and Using a Dynamic Link Library (C++) to create a Dynamic Link Library.
I have defined two methods as shown below
DeveloperConsoleManager.h
#pragma once
#include "atlstr.h"
#ifdef DEVCONSOLEMANAGER_EXPORTS
#define DEVCONSOLEMANAGER_API __declspec(dllexport)
#else
#define DEVCONSOLEMANAGER_API __declspec(dllimport)
#endif
namespace DeveloperConsoleManager
{
class DeveloperConsoleLogic
{
public:
// Returns a + b
static DEVCONSOLEMANAGER_API double Add(double a, double b);
static DEVCONSOLEMANAGER_API bool CheckforValidFile(CString fileName);
};
}
DeveloperConsoleManager.cpp
// DeveloperConsoleManager.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "DeveloperConsoleManager.h"
namespace DeveloperConsoleManager
{
double DeveloperConsoleLogic::Add(double a, double b)
{
return a + b;
}
bool DeveloperConsoleLogic :: CheckforValidFile(CString fileName)
{
return false;
}
}
I use these methods in a .cpp file in a different project (type: Application (.exe)). When I Build the solution, there are following linker errors
Warning 1 warning C4273: 'DeveloperConsoleManager::DeveloperConsoleLogic::Add' : inconsistent dll linkage e:\md_69\developerconsolemanager\developerconsolemanager.cpp 10
Warning 2 warning C4273: 'DeveloperConsoleManager::DeveloperConsoleLogic::CheckforValidFile' : inconsistent dll linkage e:\md_69\developerconsolemanager\developerconsolemanager.cpp 16
Error 3 error LNK2028: unresolved token (0A0004F1) "public: static bool __cdecl DeveloperConsoleManager::DeveloperConsoleLogic::CheckforValidFile(class ATL::CStringT > >)" (?CheckforValidFile#DeveloperConsoleLogic#DeveloperConsoleManager##$$FSA_NV?$CStringT#_WV?$StrTraitMFC_DLL#_WV?$ChTraitsCRT#_W#ATL#####ATL###Z) referenced in function "public: void __thiscall CSaSsiConsoleUi::UploadSsiCheck(void)" (?UploadSsiCheck#CSaSsiConsoleUi##$$FQAEXXZ) E:\MD_69\DeveloperConsoleUI\SaSsiConsoleUI.obj
Error 4 error LNK2019: unresolved external symbol "public: static bool __cdecl DeveloperConsoleManager::DeveloperConsoleLogic::CheckforValidFile(class ATL::CStringT > >)" (?CheckforValidFile#DeveloperConsoleLogic#DeveloperConsoleManager##$$FSA_NV?$CStringT#_WV?$StrTraitMFC_DLL#_WV?$ChTraitsCRT#_W#ATL#####ATL###Z) referenced in function "public: void __thiscall CSaSsiConsoleUi::UploadSsiCheck(void)" (?UploadSsiCheck#CSaSsiConsoleUi##$$FQAEXXZ) E:\MD_69\DeveloperConsoleUI\SaSsiConsoleUI.obj
Error 5 error LNK1120: 2 unresolved externals E:\MD_69\Debug\DeveloperConsoleUi.exe
There is no linker error for the "Add" method.
I have already included "DeveloperConsoleManager.lib" in Linker -> Input -> Additional Dependencies. Please help me find out what exactly am I doing wrong.
I would be glad to add any additional information needed.
Thanks to #Igor Tandetnik and the awesome thing that is internet, I figured it out. I am adding it as an answer so that some one else might benefit.
The problem was with CString. The project in which the function was defined was a dynamic link library (dll) and the call was being made from an MFC application. Now, the issue was that, MFC uses for CString while the non-MFC dll uses .
CString in is defined as:
typedef ATL::CStringT< TCHAR, StrTraitMFC_DLL< TCHAR > > CString;
while in is defined as:
typedef CStringT< TCHAR, StrTraitATL< TCHAR > > CString;
This, as you can clearly see is different. The workaround I used was using CAtlString instead of CString . However, please feel free to suggest any better way if you come across.
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
I'm trying to wrap a unmanaged C++ DLL with managed C++ and I keep getting linking errors.
even though I include my library.lib in the project and include the correct header file.
This is the managed class:
#pragma once
#include "..\Terminal\Terminal.h"
public ref class ManagedTerminal
{
private:
Terminal * m_unTerminal;
public:
ManagedTerminal(void)
{
m_unTerminal = new Terminal();
}
};
and this is the unmanaged class:
#include "..\Core1.h"
#include "..\Core2.h"
__declspec(dllexport) class Terminal
{
private:
CoreObj m_core;
public:
Terminal();
void Init(char* path, char* filename);
void Start();
void Stop();
void Run();
Array<Report> GetSnapshot();
~Terminal(void);
};
and the errors I get are:
Error 5 error LNK2028: unresolved token (0A0000B3) "public: __thiscall Terminal::Terminal(void)" (??0Terminal##$$FQAE#XZ) referenced in function "public: __clrcall ManagedTerminal::ManagedTerminal(void)" (??0ManagedTerminal##$$FQ$AAM#XZ) ManagedTerminal.obj TerminalWrapper
Error 6 error LNK2019: unresolved external symbol "public: __thiscall Terminal::Terminal(void)" (??0Terminal##$$FQAE#XZ) referenced in function "public: __clrcall ManagedTerminal::ManagedTerminal(void)" (??0ManagedTerminal##$$FQ$AAM#XZ) ManagedTerminal.obj TerminalWrapper
can anybody tell me what's wrong?
thanks :)
You have to match all of the build settings -- specifically the calling conventions (CDECL vs. STDCALL) -- in order to have a successful link.
Since .NET 2.0, you have also had to link to the c-runtime dynamically, so make sure that both the .dll and the managed C++ project do this.
Basically, go into the properties dialog for both projects and make sure that things that affect the call are the same.