Linker error while unit testing with Visual Studio C++ - c++

I want to unit test my C++ project with Visual Studio. After adding the folders from my project as include path to my test project, I get linker errors when trying to compile the tests:
Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol "public: __thiscall Piece::Piece(enum Color)" (??0Piece##QAE#W4Color###Z) referenced in function "public: __thiscall Bishop::Bishop(enum Color)" (??0Bishop##QAE#W4Color###Z) ChessPlusPlus-Tests D:\Documents\Projects\ChessPlusPlus\ChessPlusPlus-Tests\BishopTests.obj 1
Error LNK2019 unresolved external symbol "public: __thiscall Board::~Board(void)" (??1Board##QAE#XZ) referenced in function "public: void __thiscall ChessPlusPlusTests::BishopTests::ValidMovesTest(void)" (?ValidMovesTest#BishopTests#ChessPlusPlusTests##QAEXXZ) ChessPlusPlus-Tests D:\Documents\Projects\ChessPlusPlus\ChessPlusPlus-Tests\BishopTests.obj 1
Error LNK2019 unresolved external symbol "public: void __thiscall Board::placePieceAt(class Piece * const,struct Position)" (?placePieceAt#Board##QAEXQAVPiece##UPosition###Z) referenced in function "public: void __thiscall ChessPlusPlusTests::BishopTests::ValidMovesTest(void)" (?ValidMovesTest#BishopTests#ChessPlusPlusTests##QAEXXZ) ChessPlusPlus-Tests D:\Documents\Projects\ChessPlusPlus\ChessPlusPlus-Tests\BishopTests.obj 1
Error LNK2001 unresolved external symbol "public: virtual class std::vector<struct Position,class std::allocator<struct Position> > __thiscall Bishop::getMovesFor(struct Position,class Board &)" (?getMovesFor#Bishop##UAE?AV?$vector#UPosition##V?$allocator#UPosition###std###std##UPosition##AAVBoard###Z) ChessPlusPlus-Tests D:\Documents\Projects\ChessPlusPlus\ChessPlusPlus-Tests\BishopTests.obj 1
Error LNK2001 unresolved external symbol "public: virtual class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __thiscall Bishop::toString(void)" (?toString#Bishop##UAE?AV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##XZ) ChessPlusPlus-Tests D:\Documents\Projects\ChessPlusPlus\ChessPlusPlus-Tests\BishopTests.obj 1
Error LNK2001 unresolved external symbol "public: virtual class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __thiscall Bishop::toShortString(void)" (?toShortString#Bishop##UAE?AV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##XZ) ChessPlusPlus-Tests D:\Documents\Projects\ChessPlusPlus\ChessPlusPlus-Tests\BishopTests.obj 1
My test source code:
#include "stdafx.h"
#include "CppUnitTest.h"
#include "Bishop.h"
#include "Board.h"
#include "TestUtils.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace ChessPlusPlusTests
{
TEST_CLASS(BishopTests)
{
public:
TEST_METHOD(ValidMovesTest)
{
// Arrange
Board board{};
Bishop *piece = new Bishop{ Color::WHITE };
Position pos{ 3,3 };
board.placePieceAt(piece, pos);
// Act
auto validPositions = piece->getMovesFor(pos, board);
// Assert
TestUtils::AssertPositions(validPositions, {
0,0,0,0,0,0,0,1,
1,0,0,0,0,0,1,0,
0,1,0,0,0,1,0,0,
0,0,1,0,1,0,0,0,
0,0,0,0,0,0,0,0,
0,0,1,0,1,0,0,0,
0,1,0,0,0,1,0,0,
1,0,0,0,0,0,1,0,
});
}
};
}
Without adding the include path's the test project doesn't compile, since the header file includes in the main project rely on the include paths.
The main project compiles just fine.
Can someone help me to understand whats going wrong?
Thanks!

I believe the chosen answer is not correct. Tests typically should be run in their environment; therefore, they should not access the implementation (.cpp)
When you create a separate Test Project on Visual Studio (VS 2017) you need to create a reference to the project you want to test (right-click test project -> Add -> Reference -> tick projects):
Add a reference
If you see some linker errors, right-click from the Unit test project: Project->Linker->Input->Additional Dependencies->Edit
then add the path to your .obj files.
You could try something like "$(SolutionDir)ConsoleApplication1\$(IntDir)*.obj" where ConsoleApplication1 is the target project name.
Path to .obj
Initially, I only wanted to put a comment on Cornelis' post, but I couldn't.

https://www.codeproject.com/Tips/1085171/How-To-Do-Unit-Testing-with-Cplusplus-in-Visual-St
I found there that you have to add your .h and .cpp files as existing files also to the test project. That is left out on the official documentation or I missed it.
Now it works!

I just ran into the same problem and solved it differently, following this piece of Microsoft documentation: https://learn.microsoft.com/nl-nl/visualstudio/test/unit-testing-existing-cpp-applications-with-test-explorer?view=vs-2015&redirectedfrom=MSDN#objectRef
This solution is a bit cleaner, I think, as you don't end up with all the header files from your projects under test also showing up in your test project.
Lines from the documentation in italics, bold lines are my additions:
If the code under test does not export the functions that you want to test, you can add the output .obj or .lib file to the dependencies of the test project.
Create a C++ test project.
On the File menu, choose New, Project, Visual C++, Test, C++ Unit Test Project.
Make sure to add the projects that you want to test as References. If you forgot, you can also add these references later, in the Solution Explorer window.
In Solution Explorer, on the shortcut menu of the test project, choose Properties. The project properties window opens.
Choose Configuration Properties, Linker, Input, Additional Dependencies.
Choose Edit, and add the names of the .obj or .lib files. Do not use the full path names.
For me, there were only .obj files. I found them in the Intermediates folder, of which there are multiple versions, one for each combination of Solution Platform (x86 or x64) and Solution Configuration (Debug or Release). If you have a lot of .obj (or .lib) files, I found it convenient to open a terminal and run ls (or dir) to get the filenames, edit out the .log, .txt and .pdb filenames that I didn't need, and copy paste the list of .obj filenames into Visual Studio. For convenient editing, note that you can click on the dropdown arrow on the right hand side of the Additional Dependencies entry field and click on edit.
Choose Configuration Properties, Linker, General, Additional Library Directories.
Choose Edit, and add the directory path of the .obj or .lib files. The path is typically within the build folder of the project under test.
For me, I only had .obj files. I found them in the Intermediates folder, of which there are multiple versions, one for each combination of Solution Platform (x86 or x64) and Solution Configuration (Debug or Release). A convenient macro for setting this path for all 4 combinations is this: $(SolutionDir)bin\$(PlatformTarget)\$(IntermediateOutputPath)Intermediates. You might have to take out the bin\ part, as I have also seen the output folders set up directly in the Solution Directory, instead of in a separate binary folder.
Choose Configuration Properties, VC++ Directories, Include Directories.
Choose Edit, and then add the header directory of the project under test.
For this directory, it's okay to point directly to folders that are part of the project under test. There is no need to copy the header files over to the test project. It's also okay if this directory contains more than just the headers. For example, my source folder contains both the .h files and the .cpp files.
After following these steps, I was able to include the header files in my test code by simply writing:
#include "SomeHeaderName.h"
So, without any need to specify the folders that the header files are in.
Make sure to clean and rebuild your entire solution. Then, your tests should be able to access the functionality of the projects that you are testing.

Related

Problems with linking MATLAB and Visual Studios

In my on my header file (pages.h), I've done:
#include "mat.h".
In my cpp, all I'm trying to do is a simple:
MATFile *pmat.
However, whenever I try to build my code, I get an error that says:
1>pages.obj : error LNK2019: unresolved external symbol _matOpen referenced in function "public: void __thiscall DataPage::LoadDBIData(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (?LoadDBIData#DataPage##QAEXV?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std###Z)
and
1>C:\Users\celes\source\repos\bci2000-svn\tools\P300Classifier_electrode_selection\P300Classifier_electrode_selection.exe : fatal error LNK1120: 1 unresolved externals
I've tried going into Properties->C/C++->General->Additional Include Directories and adding a file path of C:\Program Files (x86)\MATLAB\R2015b\extern\include", but I am still receiving the same error. Without this included path, I only received the second error, not the first one.
I am using Visual Studio 2010 (it's for an old research lab) and R2015b for MATLAB.
Any sort of help would be appreciated!
The error message indicates that the compiler has trouble resolving the symbol. Apparently, you didn't set up the project correctly. Besides the "Additional Include Directories" option, you also need to set the library directory in the Linker-> Additional Library Directories for using an external library.
Because you are running a project in VS C++, you will need to have $(MATLABPATH)\extern\lib\<arch>\microsoft in that option, where $(MATLABPATH) is "C:\Program Files (x86)\MATLAB\R2015b" and the <arch> might be Win64 or Win32 depending on your target machine flag in your VS project (i.e. 32- or 64-bit).
Firstly, you could check if you add C:\Program Files (x86)\MATLAB\R2015b\extern\include in Porperties->VC++ Directories-> Include Directories, C:\Program Files (x86)\MATLAB\R2015b\extern\lib\winXX\microsoft in Porperties->VC++ Directories->Library Directories.
Secondly, you could check if you add libmat.lib;ibeng.lib;libmx.lib in Porperties->Linker->Input->Additional Dependencies.
Finally, you could refer to Microsoft Docs about LNK2019 and LNK1120.

Unresolved externals with google test

I have a project I am trying to add google-test unit testing to. It is structured like so:
VM (project)
some source files
BytecodePrograms.h
VMTest (project, made by add project -> google test -> link dynamically, test VM)
pch.h
test.cpp
I added my VM project as an include directory in VMTest properties -> c/c++ -> general -> additional include directories
contents of test.cpp are:
#include "pch.h"
#include "BytecodePrograms.h"
TEST(TestCaseName, TestName) {
EXPECT_EQ(8, VMFibonacciImp(6));
EXPECT_TRUE(true);
}
If I build, I get the following errors
Error LNK2019 unresolved external symbol "public: __thiscall WVM::WVM(void)" (??0WVM##QAE#XZ) referenced in function "int __cdecl VMFibonacciImp(int)" (?VMFibonacciImp##YAHH#Z) WVMTest C:\Users\WadeMcCall\source\repos\Virtual Machine Visual Scripting\WVMTest\test.obj 1
Error LNK2019 unresolved external symbol "public: __thiscall WVM::~WVM(void)" (??1WVM##QAE#XZ) referenced in function "int __cdecl VMFibonacciImp(int)" (?VMFibonacciImp##YAHH#Z) WVMTest C:\Users\WadeMcCall\source\repos\Virtual Machine Visual Scripting\WVMTest\test.obj 1
Error LNK2019 unresolved external symbol "public: int __thiscall WVM::interpret(class std::vector<int,class std::allocator<int> >)" (?interpret#WVM##QAEHV?$vector#HV?$allocator#H#std###std###Z) referenced in function "int __cdecl VMFibonacciImp(int)" (?VMFibonacciImp##YAHH#Z) WVMTest C:\Users\WadeMcCall\source\repos\Virtual Machine Visual Scripting\WVMTest\test.obj 1
However, my VM project defines my WVM class and uses it and can build and run and BytecodePrograms.h includes VM.h which has the declaration for this class.
I feel like this must just be a problem with the set up of my projects in Visual Studio somehow, but I have no idea. I have been googling for 2 days straight and have found other people with similar problems but their solution never seems to work for me.
Any ideas? Thanks.
I found a solution here: https://stackoverflow.com/a/19709712/8488701
Similar to what Steve suggested, except instead of creating a whole new project, I use a post-build event to build my project to a library and then link google test to that. The advantage of this over Steve's solution is that you don't have to modify your main project at all and you can still build a unit testing project on top of it.
This is a link error indicating that it found the .h file but couldn't find the actual implementation found in the .cpp. If you have a LIB project then visual studio may take the cpp code compiled into the LIB project and add it to your EXE project.
To incorporate the code into the test project, you have two options.
You can add the .cpp files in your VM Project to your Test project as well, but this is not usually done.
Instead, if your VM project is now an EXE I would recommend creating a new project called VMLib as a LIB project and then adding that project to both the test project and the VM EXE project.

LNK2019 : unresolved external symbol, searched for in a non-existing *.obj file

Good morning,
I have just inherited an application from a collegue who has left, and I'm already in trouble: the last thing we have done is porting the solution from Visual Studio 2010 to 2013.
Now while building one of the projects in the solution, I get following error message:
1>usharedmemory.obj : error LNK2019: unresolved external symbol "public: __cdecl C_NamedSemaphore::C_NamedSemaphore(char const *,unsigned int)" (??0C_NamedSemaphore##QEAA#PEBDI#Z) referenced in function "public: __cdecl C_RecursiveNamedSemaphore::C_RecursiveNamedSemaphore(char const *,unsigned int)" (??0C_RecursiveNamedSemaphore##QEAA#PEBDI#Z)
This error seems to be caused within the file "Y:\Ucam5\ucm\x\rip_mlfdpf\usharedmemory.obj" (within the project's directory), but after having a quick look, it seems that this *.obj file does not even exist.
Hence the next question: what can I do in order to be sure that the *.obj file gets created? I have already verified that the "usharedmemory.cpp" file is present in the directory of the main project (the corresponding *.h files is located in the "External Dependencies" chapter, which makes me believe that the *.obj file will be created during the build of the main project.
You see my problem: my project refers to a file which the project needs to create, but as the project does not create the file, he obviously can't refer to it, you see the circle I'm running in :-)
(for your information, I have no idea on how to generate an "*.obj" file)
Can anybody help me?
Thanks
Object files (*.obj) are created directly from source files (*.cpp) by the compiler at compilation time, for each source file in your project.
The error you are receiving is not caused by usharedmemory.obj not existing; it should be created in the Debug or Release folders.
The error you are getting is because usharedmemory.cpp uses the C_NamedSemaphore(char const *,unsigned int)-constructor of C_NamedSemaphore and the definition of the constructor can not be found in any of the source files. This constructor is used in the C_RecursiveNamedSemaphore(char const *,unsigned int)-constructor defined in usharedmemory.cpp. This is what the error message reads.
To solve this, you need to find out where the constructor of C_NamedSemaphore is defined (which source file) and ensure that this source file is included in your project. Or, if it is in a library file (static or dynamic), verify that this library file is included as an Additional Dependency (under project Properties -> Linker -> Input -> Additional Dependencies; ensure you set this for all builds, not just the currently active one).
Good morning,
I have finally solved my issue. As a good citizen, I will describe how I have done it :-), but as a less good programmer, I need to admit that I don't understand how my actions solve the problem ;-(
I have done a file comparison of both *.vcxproj Visual Project files (the old one from VC2010 and the new VC2013 one). In that way I have seen that the "umultiproc.cpp" entry was missing in the VC2013 one:
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
...
<ItemGroup>
...
<ClCompile Include="..\..\mp\umultiproc.cpp" /> <!-- missing -->
Summary: In the error message, there was an unresolved symbol (C_Semaphore constructor), which was defined in *.cpp/*.h source/header file. In order to solve the error, I have added a reference to the *.cpp source file into the VC2013 project file.

Can't get rid of LNK 2019 error in Dll

I keep getting link 2019 errors on this ctor,ctor-copy ctor-assignment code that works in other projects with no errors. I am trying to include it in a plain DLL generated with the MFC support option checked. I'm in VS2010.
#include "stdafx.h"
#include "Name.h"
CNameBase::CNameBase()
{
IsGlobal = false;
UseShortName = true;
m_ShortName = NO_NAME_ID ;
m_Description = "";
pMe = this;
}
CNameBase::CNameBase( const CNameBase& ref )
{
m_Description = ref.m_Description;
IsGlobal = ref.IsGlobal;
m_LongName = ref.m_LongName;
m_ShortName = ref.m_ShortName;
UseShortName = ref.UseShortName;
pMe = ref.pMe;
}
CNameBase& CNameBase::operator=( const CNameBase& ref )
{
m_Description = ref.m_Description;
IsGlobal = ref.IsGlobal;
m_LongName = ref.m_LongName;
m_ShortName = ref.m_ShortName;
UseShortName = ref.UseShortName;
pMe = ref.pMe;
return *this;
}
The link errors are:
error LNK2019: unresolved external symbol "public: __thiscall CNameBase::CNameBase(void)" (??0CNameBase##QAE#XZ) referenced in function "public: __thiscall CName::CName(void)" (??0CName##QAE#XZ)
1>clayer.obj : error LNK2019: unresolved external symbol "public: __thiscall CNameBase::CNameBase(class CNameBase const &)" (??0CNameBase##QAE#ABV0##Z) referenced in function "public: __thiscall CName::CName(class CName const &)" (??0CName##QAE#ABV0##Z)
1>clayer.obj : error LNK2019: unresolved external symbol "public: class CNameBase & __thiscall CNameBase::operator=(class CNameBase const &)" (??4CNameBase##QAEAAV0#ABV0##Z) referenced in function "public: class CName & __thiscall CName::operator=(class CName const &)" (??4CName##QAEAAV0#ABV0##Z)
1>C:\devt\hftappb\Debug\CLayer.dll : fatal error LNK1120: 3 unresolved externals
The funny thing is this code works and has worked. The Ctors do what they're supporsed to do and have been in other solution. I stick the class in this file and suddenly get these errors that I am having dififculty resolving. I've compared project settings between this project and projects I know this code works in. What else could be causing this?
The cpp file that holds the implementation of the 3 functions doesn't compile/link into the exe/dll.
If you're using C++ namespaces, you need to make sure that both header and cpp use it. The namespace is part of the class name.
Thank you all for responding to my question. The question took the better part of a day to resolve but I wanted to share the answer with others since it can happen to anyone. The solution to the problem wasn't any code, it was a configuration issue. In VS2010, apparently, ALL files that your project references must be in the list of files that appear with the project in the Solution Explorer. I am not privy to the underlying architecture so I can't answer why this is required. On the surface, there's NO reason for it. If there are files #included into a project either explicity or implicitly through the Project paths and whose functions I reference from files that are included in the Project's list of files in Solution Explorer, functions in those files should be able to reference functions in files that aren't included in the project filelist in Sol Exp.
The rules for #include and other rules are convoluted enough in C++ without MSFT adding their layers of confusion. These types of errors would be easily prevented with better error reporting and/or UI management.
The rules I've learned are this
1. Never make more than 1 copy of the same file in the entire solution. Multiple copies of the same file are hard to keep symchronized and lead to confusion as to which one is being used.
2. All files being used in a project must be listed in that project but rule 1 should be respected.
Steps (approximate)
1. Create a project
2. Create a .h and .cpp with global functions (or in a class doesn't matter)
3. In the same parent directory as project 1, create project 2 There should be two project directories underneath one parent
4. In project 2 in File Explorer, create a subfolder called Common
5. Create a .h and .cpp in that folder and create a simple function that returns a value
6. Add those files to project 2 in Solution Explorer
7. In Project 1, in the .cpp, create a function that #includes the file for project 2 and calls that function in that file.
8. The compiler generates a 2019 and 2001 unresolved external link error. What it should do is report that those files are required to be in your project's file list.

Qt Link Issue with MyClass::metaobject VS2005

Just quickly before I start, I have searched SO and Google for a length of time trying to solve this and have been unsuccessful.
I am trying to compile my project, which used to use a certain library for providing GUI functionality based on Windows Forms. Now my company has started to move to Qt, and I decided I would start to convert my small application to support Qt also.
At first it would not compile at all, due to missing headers. Now that is sorted, I am stuck with my final .exe not being able to link due to the following errors.
Creating library Bin\VS_V8\Win32\Debug\Disp.lib and object Bin\VS_V8\Win32\Debug\Disp.exp
QtMainMenu.obj : error LNK2001: unresolved external symbol "public: virtual struct QMetaObject const * __thiscall QtMainMenu::metaObject(void)const " (?metaObject#QtMainMenu##UBEPBUQMetaObject##XZ)
QtMainMenu.obj : error LNK2001: unresolved external symbol "public: virtual void * __thiscall QtMainMenu::qt_metacast(char const *)" (?qt_metacast#QtMainMenu##UAEPAXPBD#Z)
QtMainMenu.obj : error LNK2001: unresolved external symbol "public: virtual int __thiscall QtMainMenu::qt_metacall(enum QMetaObject::Call,int,void * *)" (?qt_metacall#QtMainMenu##UAEHW4Call#QMetaObject##HPAPAX#Z)
Bin\VS_V8\Win32\Debug\Disp.exe : fatal error LNK1120: 3 unresolved externals
Our company has a small "Qt Test App" that was written to play around with, which is where I have based my import from. I can compile and link that fine. From what I have gathered, the following properties must be met with Qt files:
Make sure QTDir is included
Add to the UI Files the UIC Compiler
Add to the Resoruce Files the Resource Compiler
Add to the created Header Files the MOC compiler.
I noticed I was missing the MOC Build Tool commands, so I have added them to my UI File's header. However this didnt change the linking problem. I read that I should delete all built files and do a clean to solve it. This didnt work either.
I have checked, and Q_OBJECT is defined in the class.
I am using VS2005 with the Qt Addin. I did not start a new project for Qt however, I am just using the old Visual Studio Solution / VCProj.
Any ideas where to go next?
#Cameron Stubber you need moc object .. You need to modify Custom Build Step.
You can find Custom Build Step in header file (which has Q_OBJECT) Properties by right click. Then type this commands ;
Command Line = $(QTDIR)\bin\moc.exe -I"$(QTDIR)\include\QtCore" -I"$(QTDIR)\include\QtGui" -I"$(QTDIR)\include" -I"$(QTDIR)\mkspecs\$(QMAKESPEC)" finddialog.h -o debug\moc_finddialog.cpp
Description = MOC finddialog.h
Outputs = debug\moc_finddialog.cpp
Additional Dependencies = $(QTDIR)\bin\moc.exe;finddialog.h
But carefull by writing this types you need to change somethings here like $(QTDIR) it is my enviroment variables you need to write full form of where your QT located like D:\qt_5\
and also you need to be carefull finddialog you should write your .h and .cpp files name
And then you need to create a folder by right clicking solution explorer Add\New Filter .. Make folder name as Generated Files
And last step right click Generated Files add\existing item and you will see Debug folder in your solution Project and add moc_"projectName".cpp
Then re-build your solution. Problem will be solved.
Also you should add C/C++ /General/Additional Library Directories
$(QTDIR)\include
$(QTDIR)\include\QtGui
$(QTDIR)\include\QtCore
And Link/General/Additional Library Directories
$(QTDIR)\lib
Link/Input/Additional Dependencies
qtmaind.lib
QtCored4.lib
QtGuid4.lib
But dont forget to change $(QTDIR) to your enviroment variables or location of your qt folder. Like D:\qt_4.7.4