Unit testing Inconsistent dll linkage leads to compilation error - c++

New to c++ and trying to test a dll but keep getting
warning C4273: 'CRootFinder::SquareRoot' : inconsistent dll linkage
RootFinder.h
#ifdef MY_EXPORTS
#define API _declspec(dllexport)
#else
#define API _declspec(dllimport)
#endif
class API CRootFinder {
public:
CRootFinder(void);
double SquareRoot(double v);
};
RootFinder.cpp
#include "stdafx.h"
#include "RootFinder.h"
double CRootFinder::SquareRoot(double v)
{
return 0.0;
}
Builds but gets warning above.
Added reference to dll to unit test project
unittest1.cpp
#include "stdafx.h"
#include "CppUnitTest.h"
#include "../c source/RootFinder.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace Tests
{
TEST_CLASS(UnitTest1)
{
public:
TEST_METHOD(TestMethod1)
{
CRootFinder rooter;
Assert::AreEqual(
// Expected value:
0.0,
// Actual value:
rooter.SquareRoot(0.0),
// Tolerance:
0.01,
// Message:
L"Basic test failed",
// Line number - used if there is no PDB file:
LINE_INFO());
}
};
}
Won't build
Error 2 error LNK2019: unresolved external symbol "__declspec(dllimport) public: __thiscall
CRootFinder::CRootFinder(void)" (__imp_??0CRootFinder##QAE#XZ)
referenced in function "public: void __thiscall
Tests::UnitTest1::TestMethod1(void)"
(?TestMethod1#UnitTest1#Tests##QAEXXZ)

Compile dll with MY_EXPORTS preprocessor marco. Add use it in test without MY_EXPORTS definition macro.
In Visual Studio you can do that: Project right click->Propertis->C/C++->Preprocessor->Preprocessor Definitions, just add MY_EXPORTS to the list for dll project, and leave that list without MY_EXPORTS for test project.
And you need define constructor CRootFinder() in RootFinder.cpp.

Related

C++ Unit Test in Visual Studio 2019

I am having a problem with Visual Studio 2019 CPPUnitTestFramework. I follow the instructions, but every time I get an error. I have looked for tutorials, but anything I get is for Visual Studio 2017 and it does not solve my problem.
I am writing a program that uses OOP in C++ and I want to make unit tests, since it is going to be a considerably long project. The problem that I am having is that the program is not compiling in the test module.
Consider that I have the code such that I have the header file:
//A.h
#pragma once
class A
{
private:
// One parameter.
int a;
public:
// Add function.
int add(int, int);
// Subtract function.
int subtract(int, int);
A();
};
with the proper source file:
// A.cpp
#include "A.h"
int a;
int A::add(int alpha, int beta)
{
return alpha + beta;
}
int A::subtract(int alpha, int beta)
{
return alpha - beta;
}
A::A()
{
a = 4;
}
The structure of the program looks something like this:
To make my Unit Test, I right click on the "Solution 'TestTestUnit'" label and choose new project, look for the unit test, add the unit test and attach the reference, such that I get a file structure such as the one below:
To perform the unit test I write the code:
// TestUnitForTestTestUnit.cpp
#include "pch.h"
#include "CppUnitTest.h"
#include "../TestTestUnit/A.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace TestUnitForTestTestUnit
{
TEST_CLASS(TestUnitForTestTestUnit)
{
public:
TEST_METHOD(TestMethod1)
{
A first;
Assert::AreEqual(first.add(3, 2), 5);
}
};
}
When I try to run a test, the Test Explorer does nothing and throws the message: Aborting test run due to build failures. Please see the build for more details.
I cannot find the mistake here. The program runs perfect, but when instantiating a new "A" object the test fails. I am stuck here, are there any suggestions? What am I doing wrong (besides developing in Windows)?
UPDATE:
I have followed the suggestion to remove the namespace, as suggested by #ChrisMM, so that the test file now reads:
// TestUnitForTestTestUnit.cpp
#include "pch.h"
#include "CppUnitTest.h"
#include "../TestTestUnit/A.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
TEST_CLASS(TestUnitForTestTestUnit)
{
public:
TEST_METHOD(TestMethod1)
{
A first;
Assert::AreEqual(first.add(3, 2), 5);
}
};
such that when I run the Test Explorer gives the same message:
with error message:
1>------ Build started: Project: TestUnitForTestTestUnit, Configuration: Debug Win32 ------
1> Creating library C:\Users\<user>\Desktop\CPlusPlus\TestTestUnit\Debug\TestUnitForTestTestUnit.lib and object C:\Users\<user>\Desktop\CPlusPlus\TestTestUnit\Debug\TestUnitForTestTestUnit.exp
1>TestUnitForTestTestUnit.obj : error LNK2019: unresolved external symbol "public: int __thiscall A::add(int,int)" (?add#A##QAEHHH#Z) referenced in function "public: void __thiscall TestUnitForTestTestUnit::TestMethod1(void)" (?TestMethod1#TestUnitForTestTestUnit##QAEXXZ)
1>TestUnitForTestTestUnit.obj : error LNK2019: unresolved external symbol "public: __thiscall A::A(void)" (??0A##QAE#XZ) referenced in function "public: void __thiscall TestUnitForTestTestUnit::TestMethod1(void)" (?TestMethod1#TestUnitForTestTestUnit##QAEXXZ)
1>C:\Users\<user>\Desktop\CPlusPlus\TestTestUnit\Debug\TestUnitForTestTestUnit.dll : fatal error LNK1120: 2 unresolved externals
1>Done building project "TestUnitForTestTestUnit.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 1 up-to-date, 0 skipped ==========
Help would be appreciated.
You cannot put a test class inside a namespace. From the documentation
TEST_CLASS must be declared at namespace scope.
I suggest you to check if TestUnitForTestTestUnit has added Additional Dependencies. When I didn’t add it, the same problem as you occurred. After I added it, the program worked fine.
Right click TestUnitForTestTestUnit->Properties->C/C++->Linker->Input->Additional Dependencies-> add ..\TestTestUnit\Debug\*.obj

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.

Link error when referencing managed dll to native c++

I am trying to create a rather simple project in native c++ that calls a a managed dll.
this how my native c++ code looks:
// MyCppStud.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "MyStudWrapper\MyStudentWrapperWrapper.h"
int _tmain(int argc, _TCHAR* argv[])
{
char * path = "C:/Users/rami.schreiber/documents/visual studio 2013/Projects/TestProj/test.xml";
MyStudentWrapperWrapper* student = new MyStudentWrapperWrapper();
// student->GetStudent(path);
return 0;
}
and here are the .h and .cpp files for the managed dll (compiled with /clr)
//MyStudentWrapperWrapper.h
#pragma once
//#ifdef THISDLL_EXPORTS
#define THISDLL_API __declspec(dllexport)
/*#else
#define THISDLL_API __declspec(dllimport)
#endif*/
class MyStudentWrapper;
class THISDLL_API MyStudentWrapperWrapper
{
private:
MyStudentWrapper* _Impl;
public:
MyStudentWrapperWrapper();
MyStudentWrapperWrapper(MyStudentWrapper* student);
~MyStudentWrapperWrapper();
MyStudentWrapperWrapper* GetStudent(const char* path);
void SaveStudent(MyStudentWrapperWrapper* student, const char* path);
};
// MyStudentWrapperWrapper.cpp
#pragma once
#include "stdafx.h"
#include "MyStudWrapper.h"
#include "MyStudentWrapperWrapper.h"
MyStudentWrapperWrapper::MyStudentWrapperWrapper()
{
_Impl = new MyStudentWrapper;
}
when i build the solution i get a link error
1>MyCppStud.obj : error LNK2019: unresolved external symbol "public: __thiscall MyStudentWrapperWrapper::MyStudentWrapperWrapper(void)" (??0MyStudentWrapperWrapper##QAE#XZ) referenced in function _main
1>c:\users\...\documents\visual studio 2013\Projects\MyStudentProj\Debug\MyCppStud.exe : fatal error LNK1120: 1 unresolved externals
From what I understand I am not referencing the the .lib file correctly and therefor the linker does not recognize the c'tor for my wrapper class.
can someone please explain how to correctly reference the dll to my c++ project.
thank you very much!

unresolved external symbol visual studio 2010 error

i've implemented with visual studio 2010 professional a solution containing 2 projects; the first called OptDll consist of a dynamic library with a method i want to export, while the second is a exe project, called prova, in order to try the dll.
I've included the correct references and all work fine until i decided to insert in OptDll project a new class (GlobalOutput) in order to create the output parameters i want. When i build the project OptDll no error occurs but when i build the whole solution i get these errors in the prova project:
Error 59 error LNK2019: unresolved external symbol "public: __thiscall GlobalOutput::~GlobalOutput(void)" (??1GlobalOutput##QAE#XZ) referenced in function _main C:\Users\ANTONIO\Desktop\optDll\prova\prova.obj
Error 60 error LNK2019: unresolved external symbol "public: __thiscall GlobalOutput::GlobalOutput(void)" (??0GlobalOutput##QAE#XZ) referenced in function _main C:\Users\ANTONIO\Desktop\optDll\prova\prova.obj
Error 61 error LNK1120: 2 unresolved externals C:\Users\ANTONIO\Desktop\optDll\Debug\prova.exe 1
I read it could be a problem with the class constructor/destructor but i don't fix it.
Below the code of interest.
OptFunDll.h
#ifdef OPTFUNDLL_EXPORTS
#define OPTFUNDLL_API __declspec(dllexport)
#else
#define OPTFUNDLL_API __declspec(dllimport)
#endif
//#include "tool_library.h"
#include "GlobalOutput.h"
namespace optFun
{
// This class is exported from the optFunDll.dll
class myoptFun
{
public:
// funzione che implementa il modulo di ottimizzazione
class OPTFUNDLL_API GlobalOutput;
static OPTFUNDLL_API void scheduling(const char*,const char*,const char*,const char*,GlobalOutput&);
};
}
OptFunDll.cpp
#include "stdafx.h"
#include "optFunDll.h"
#include <stdexcept>
using namespace std;
::Random Particle::_rnd;
::Random ParticleSwarm::_rnd;
namespace optFun
{
void myoptFun::scheduling(const char *pRicette,const char *pWarehouse,const char *pFarmacia,const char *pShaker,GlobalOutput& total){
//here some code...
//class definition
total.CreateDataPrescription(final_list);
total.time=time_output;
GlobalOutput.h
#include <afxwin.h> // MFC core and standard components
#include <afxext.h> // MFC extensions
#include <afxadv.h>
#include <afxdisp.h> // MFC Automation classes
#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h> // MFC support for Windows Common Controls
#endif // _AFX_NO_AFXCMN_SUPPORT
#include "GlobalInfo.h"
#include "tool_library.h"
struct DataPrescription{
EDrug NameDrug;
double Dosage;
EContainerType DestType;
ELiquid IdDest;
double CapacityDest;
double Priority;
bool ScaricoShaker;
DataPrescription(){
NameDrug=EDrug_NoDrug;
Dosage=0.0;
DestType= EContainerType_Tot;
IdDest=ELiquid_NoLiquid;
CapacityDest=0.0;
Priority=0.0;
ScaricoShaker=true;
}
DataPrescription(EDrug name,double dos,EContainerType dest,ELiquid ID,double cap_dest,double p,bool _ScaricoShaker){
NameDrug=name;
Dosage=dos;
DestType=dest;
IdDest=ID;
CapacityDest=cap_dest;
Priority=p;
ScaricoShaker=_ScaricoShaker;
}
};
class GlobalOutput{
public:
CArray<DataPrescription> OptList;
time_info time;
GlobalOutput();
~GlobalOutput();
void CreateDataPrescription(vector<ricetta>&);
};
#endif
GlobalOutput.cpp
#include "stdafx.h"
#include "GlobalOutput.h"
GlobalOutput::GlobalOutput(){
time.total_makespan=0;
}
GlobalOutput::~GlobalOutput(){
}
void GlobalOutput::CreateDataPrescription(vector<ricetta>& list){
//DataPrescription tmp;
for(unsigned int i=0;i<list.size();i++){
DataPrescription tmp(list[i].getID(),list[i].getdosage(),list[i].get_destination(),list[i].get_DestType(),list[i].get_CapacityDest(),list[i].getPriority(),list[i].processing_info.scarico_shaker);
this->OptList.Add(tmp);
}
}
and Finally the main of prova project:
#include "stdafx.h"
#include "optFunDll.h"
#include <iostream>
//#include "C:\Users\ANTONIO\Desktop\optDll\optDll\tool_library.h"
using namespace std;
int main()
{
const char *pRicette;
pRicette=new char(NULL);
const char *pWarehouse;
pWarehouse=new char(NULL);
const char *pFarmacia;
pFarmacia=new char(NULL);
const char *pShaker;
pShaker=new char(NULL);
optFun::myoptFun::GlobalOutput total;
optFun::myoptFun::scheduling(pRicette,pWarehouse,pFarmacia,pShaker,total);
return 0;
}
Thanks for your help.
Please let me know if you want more info.
if I comment the code lines under class definition in OptDll.cpp i get these errors:
Error 5 error C2079: 'total' uses undefined class 'optFun::myoptFun::GlobalOutput' c:\users\antonio\desktop\optdll\prova\prova.cpp 23
Error 6 error C2664: 'optFun::myoptFun::scheduling' : cannot convert parameter 5 from 'int' to 'optFun::myoptFun::GlobalOutput &' c:\users\antonio\desktop\optdll\prova\prova.cpp 24
instead if i uncomment the definition of total i obtain also:
9 IntelliSense: incomplete type is not allowed c:\users\antonio\desktop\optdll\optdll\optfundll.cpp 131
Thanks for you availability, I'm new on c++ programming.
You are not actually exporting your class GlobalOutput.
You need to have:
class OPTFUNDLL_API GlobalOutput

unresolved external symbol in C++ DLL project

can I just start by saying I appreciate you taking your time to go through my question and attempting to help. However I have already attempted the solution suggested on here and on here and they haven't worked for me.
This is my problem:
I am attempting to create a serial port class as a VS12 DLL project. I have a header file "SerialDll.h" which is included in my c++ source file "SerialDll.cpp". When I try to build the solution in visual studio 2012, i get the errors below:
Error 11 error LNK1120: 1 unresolved externals C:\Sprint 7\SerialDll\Debug\SerialDll.dll 1 1 SerialDll
Error 10 error LNK2001: unresolved external symbol "__declspec(dllimport) private: static void * MySerial::MySerialPort::serial_port_handle" (__imp_?serial_port_handle#MySerialPort#MySerial##0PAXA) C:\Sprint 7\SerialDll\SerialDll\SerialDll.obj SerialDll
When I try implementing John Zwinck's Solution, this is the error i get:
Error 2 error C2491: 'MySerial::MySerialPort::serial_port_handle' : definition of dllimport static data member not allowed c:\sprint 7\serialdll\serialdll\serialdll.cpp 16 1 SerialDll
This is the code in my header file:
#include <Windows.h>
#ifdef SERIAL_DLL_EXPORTS
#define SERIAL_DLL_API __declspec(dllexport)
#else
#define SERIAL_DLL_API __declspec(dllimport)
#endif
namespace MySerial
{
class MySerialPort
{
private:
static SERIAL_DLL_API HANDLE serial_port_handle;
public:
SERIAL_DLL_API MySerialPort();
SERIAL_DLL_API ~MySerialPort();
};
}
This is the code in my c++ source file, with John Zwinck's solution:
#include "stdafx.h"
#include "SerialDll.h"
#include <stdexcept>
#include <iostream>
using namespace std;
namespace MySerial
{
HANDLE MySerialPort::serial_port_handle;
MySerialPort::MySerialPort()
{
serial_port_handle = INVALID_HANDLE_VALUE;
}
MySerialPort::~MySerialPort()
{
if(serial_port_handle != INVALID_HANDLE_VALUE)
{
CloseHandle(serial_port_handle);
}
serial_port_handle = INVALID_HANDLE_VALUE;
}
}
Hope you guys can help me with a solution or at least refer me to a link with a working solution.
Cheers!
The answer is exactly the same as this answer to the previous question you linked:
https://stackoverflow.com/a/17902142/4323
That is, you have only declared, but not allocated storage for, your static member. You need to add this to your implementation file:
namespace MySerial
{
HANDLE MySerialPort::serial_port_handle;
}
If you are looking to export the class outside the DLL, then you need to use __declspec for the class, and not for each member function/variable. (See http://msdn.microsoft.com/en-us//library/a90k134d.aspx )
Your header file needs to look like :
namespace MySerial
{
class SERIAL_DLL_API MySerialPort
{
private:
static HANDLE serial_port_handle;
public:
MySerialPort();
~MySerialPort();
};
}