1

I have created a custom C++ Matrix class and my intention is to write naive implmentations of some numerical algorithms (Root finding, linear solvers, interpolators) using this class.

I want to unit test my piece of code.

My header files Matrix.h and MatrixX.h containing the logic are in a project Matrix. This project builds successfully, and the target is a DLL file.

My unit tests are in a test project MatrixUnitTest. I have added the Matrix project to this test project in Visual studio, as well added a reference to Matrix.

enter image description here

I setup Project Properties > C/C++ > General > Additional Include Directories to have the path to the directory containing the header files Matrix.h and MatrixX.h.

enter image description here

I setup Project Properties > Linker > General > Additional Library Directories to have the \Debug folder containing my Matrix.dll file.

enter image description here

When I try to build the test project, I get a missing .lib file. But, I have a dynamic library, instead of a static one.

Error LNK1104   cannot open file 'D:\data\dev\quasar\cpp\MatrixUnitTest\Debug\Matrix.lib'
MatrixUnitTest  D:\data\dev\quasar\cpp\MatrixUnitTest\LINK  1   

If I explicitly add Matrix.dll to Project Properties > Linker > Input > Additional Dependencies, it cannot open the file.

How do I properly have Visual Studio find my DLL during the build of the test project, so the linker can resolve the calls to the Matrix API?

Build Log.

1>------ Rebuild All started: Project: Matrix, Configuration: Debug Win32 ------
1>pch.cpp
1>dllmain.cpp
1>Matrix.vcxproj -> D:\data\dev\quasar\cpp\MatrixUnitTest\Debug\Matrix.dll
2>------ Rebuild All started: Project: MatrixUnitTest, Configuration: Debug Win32 ------
2>pch.cpp
2>MatrixUnitTest.cpp
2>D:\data\dev\quasar\cpp\Matrix\MatrixX.h(72,1): warning C4812: obsolete declaration style: please use 'MatrixX<scalarType>::MatrixX' instead
2>D:\data\dev\quasar\cpp\Matrix\MatrixX.h(72,1): warning C4812: obsolete declaration style: please use 'MatrixX<int>::MatrixX' instead
2>D:\data\dev\quasar\cpp\Matrix\MatrixX.h(72): message : while compiling class template member function 'MatrixX<int>::MatrixX(const MatrixX<int> &)'
2>D:\data\dev\quasar\cpp\Matrix\MatrixX.h(209): message : see reference to function template instantiation 'MatrixX<int>::MatrixX(const MatrixX<int> &)' being compiled
2>D:\data\dev\quasar\cpp\Matrix\MatrixX.h(94): message : while compiling class template member function 'MatrixX<int>::MatrixX(std::initializer_list<std::initializer_list<_Ty>>)'
2>        with
2>        [
2>            _Ty=int
2>        ]
2>D:\data\dev\quasar\cpp\MatrixUnitTest\MatrixUnitTest.cpp(16): message : see reference to function template instantiation 'MatrixX<int>::MatrixX(std::initializer_list<std::initializer_list<_Ty>>)' being compiled
2>        with
2>        [
2>            _Ty=int
2>        ]
2>D:\data\dev\quasar\cpp\MatrixUnitTest\MatrixUnitTest.cpp(16): message : see reference to class template instantiation 'MatrixX<int>' being compiled
2>LINK : fatal error LNK1104: cannot open file 'D:\data\dev\quasar\cpp\MatrixUnitTest\Debug\Matrix.lib'
2>Done building project "MatrixUnitTest.vcxproj" -- FAILED.
========== Rebuild All: 1 succeeded, 1 failed, 0 skipped ==========
Quasar
  • 501
  • 4
  • 16
  • Can not open input file means one or more of the following 1. The path or file name is incorrect, 2. You are mixing 32 and 64 bit or 3. The file is corrupt. – drescherjm Nov 10 '21 at 15:21
  • 1
    ***f I explicitly add Matrix.dll to Project Properties > Linker > Input > Additional Dependencies, it cannot open the file.*** This is correct. In native c++ and msvc you don't link to a dll. Instead you link to the import library for the dll. Then at runtime the dll must be in able to be found by your OS at runtime: [https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order#standard-search-order-for-desktop-applications](https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order#standard-search-order-for-desktop-applications) – drescherjm Nov 10 '21 at 15:21
  • @drescherjm, is there a blog-link which shows these steps, because I followed, what's given on the Microsoft page. – Quasar Nov 10 '21 at 15:25
  • An import library will have a `.lib` extension but is not the same as a static library. The implementation of the functions are not in this import library. – drescherjm Nov 10 '21 at 15:25
  • I don't know of a blog or tutorial. I learned this stuff 25+ years ago. It has not really changed that much over time. Other that 32 bit versus 64 bit and search order for the dll. – drescherjm Nov 10 '21 at 15:26
  • So,my source code project only has a `.dll` extension file, and no `.lib` file. – Quasar Nov 10 '21 at 15:29
  • How did you build such a dll? If you have no import library you probably are not exporting symbols with `__declspec(dllexport)` – drescherjm Nov 10 '21 at 15:29
  • @Quasar -- Rebuild the DLL file, and look at the Output Window. Do you see a message saying that the lib file was created? If you do, then that's where the .lib file is sitting. – PaulMcKenzie Nov 10 '21 at 15:31
  • Well, in VS2019, I chose Create a New Project > Dynamic-Link Library (C++). – Quasar Nov 10 '21 at 15:31
  • @PaulMcKenzie, this is build output: `` 1>------ Rebuild All started: Project: Matrix, Configuration: Debug Win32 ------ 1>pch.cpp 1>dllmain.cpp 1>Matrix.vcxproj -> D:\data\dev\quasar\cpp\MatrixUnitTest\Debug\Matrix.dll ========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ========== `` – Quasar Nov 10 '21 at 15:32
  • Does it have a macro that changes from `__declspec(dllexport)` to `__declspec(dllimport)` depending on if you are building the dll or using the dll. Should be something like this: [https://stackoverflow.com/questions/14980649/macro-for-dllexport-dllimport-switch](https://stackoverflow.com/questions/14980649/macro-for-dllexport-dllimport-switch) – drescherjm Nov 10 '21 at 15:32
  • If you are not using `__declspec(dllexport)` you are not exporting symbols. You won't get an import library in that case. This question discusses alternatives: [https://stackoverflow.com/questions/225432/export-all-symbols-when-creating-a-dll](https://stackoverflow.com/questions/225432/export-all-symbols-when-creating-a-dll) – drescherjm Nov 10 '21 at 15:37
  • I see, so even for writing unit tests, I must export(expose) these functions to the outside world, by writing __declspec(dllexport), is that correct? – Quasar Nov 10 '21 at 15:39
  • 2
    @Quasar -- You can't simply take code that used to build a standalone app and simply recompile it to create a DLL. You have to make source code changes in some way (as drescherjm mentioned). The only other option if you have no .lib file is to use `LoadLibrary` and `GetProcAddress` API calls in your main app to point to the DLL function(s). – PaulMcKenzie Nov 10 '21 at 15:39
  • @Quasar -- The second option of `LoadLibrary` removes the need to have an import library in the build. However your main app has to have coding changes to declare function pointers that get setup in the `GetProcAddress` call, and then calling the DLL functions via those pointers. – PaulMcKenzie Nov 10 '21 at 15:49
  • @drescherjm, I added this pre-processor macro which conditionally #define's DLLEXPORT as __declspec(dllexport) in the source code. I also set COMPILE_DLL=1 in the pre-processor definitions. Then, I put DLLEXPORT against the classes I want to export. The result is that a (*.ilk) (Incremental linker file) got generated, but still no .lib file. – Quasar Nov 10 '21 at 16:12
  • You probably should try this Microsoft tutorial before continuing with actual project code: [https://learn.microsoft.com/en-us/cpp/build/walkthrough-creating-and-using-a-dynamic-link-library-cpp?view=msvc-170](https://learn.microsoft.com/en-us/cpp/build/walkthrough-creating-and-using-a-dynamic-link-library-cpp?view=msvc-170) – drescherjm Nov 10 '21 at 16:37
  • @drescherjm, thanks for sharing this. I will try this. I think, that all my code is C++ templated classes, so they are not really definitions, and unless they are instantiated, they won't be exported. – Quasar Nov 10 '21 at 16:40
  • You are correct. Templates are not exported unless you can instantiate a concrete type and export that. Related: [https://stackoverflow.com/questions/362822/how-do-i-export-templated-classes-from-a-dll-without-explicit-specification](https://stackoverflow.com/questions/362822/how-do-i-export-templated-classes-from-a-dll-without-explicit-specification) – drescherjm Nov 10 '21 at 16:57

0 Answers0