I'm currently creating a DLL and the client which goes with it using the stored procedure mentioned at a lot of places on the internet. Basically, create a DLL project which actually defines a PROJECT_EXPORTS in the Project.h file.
Something like this:
// Assume the name of the project is SanProj and the header file is SanProj.h
#ifdef SANPROJ_EXPORTS
#define SANPROJ_API __declspec(dllexport)
#else
#define SANPROJ_API __declspec(dllimport)
#endif
Now the normal way of using this header is to include this in all the headers of your API classes and using SANPROJ_EXPORTS for "exporting" declarations when in the DLL and "importing" declarations when used as a client. For e.g. let's say we have a header file with a currency class:
// currency.hpp
#include "SanProj.h"
#include <ostream>
#include <string>
namespace SanProj {
class SANPROJ_API Currency {
public:
Currency();
const std::string& name();
const std::string& code();
bool empty() const;
protected:
std::string name_;
std::string code_;
};
SANPROJ_API bool operator==(const Currency&,
const Currency&);
SANPROJ_API bool operator!=(const Currency&,
const Currency&);
SANPROJ_API std::ostream& operator<<(std::ostream& out, Currency& c);
}
And another header file with specific currencies:
// allccy.hpp
namespace SanProj {
class SANPROJ_API USDCurrency : public Currency {
public:
USDCurrency() {
name_ = "American Dollar";
code_ = "USD";
}
};
class SANPROJ_API CADCurrency : public Currency {
public:
CADCurrency() {
name_ = "Canadian Dollar";
code_ = "CAD";
}
};
}
The above classes form the contract of the DLL project. Now let's look at the client project files, which is a single class with main function:
#include "currency.hpp"
#include "allccy.hpp"
#include <iostream>
using namespace SanProj;
int main(int argc, char* argv[])
{
USDCurrency uccy;
std::cout << uccy;
}
Assuming all referencing/settings are already done in the Visual Studio project, I get the following error when trying to compile the client:
1>testdll.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) public: __thiscall SanProj::USDCurrency::~USDCurrency(void)" (__imp_??1USDCurrency#SanProj##QAE#XZ)
1>testdll.obj : error LNK2001: unresolved external symbol "__declspec(dllimport) public: __thiscall SanProj::USDCurrency::USDCurrency(void)" (__imp_??0USDCurrency#SanProj##QAE#XZ)
Not surprisingly, this error goes away when I remove the dllimport part from the SanProj.h file and the executable is created.
My question is, what's the point of the IDE generated dllimport if we can't compile clients against the header? Is there a way I can continue to use the header with both dllimport and dllexports and remove the linker errors? Also, why is it trying to resolve the symbol which has dllimport from the LIB file?
TIA,
/sasuke
EDIT: Linker Command used by VisualStudio; as you can see, it has the LIB file.
/OUT:"E:\vsprojects\SomeSln\Release\testdll.exe" /INCREMENTAL:NO
/NOLOGO "E:\vsprojects\SomeSln\Release\SanProj.lib" "kernel32.lib"
"user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib"
"shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib"
"odbccp32.lib" /MANIFEST
/ManifestFile:"Release\testdll.exe.intermediate.manifest"
/ALLOWISOLATION /MANIFESTUAC:"level='asInvoker' uiAccess='false'"
/DEBUG /PDB:"E:\vsprojects\SomeSln\Release\testdll.pdb"
/SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF
/PGD:"E:\vsprojects\SomeSln\Release\testdll.pgd" /LTCG /TLBID:1
/DYNAMICBASE /NXCOMPAT /MACHINE:X86 /ERRORREPORT:QUEUE
EDIT: Sure I'm wrong as the answer of jcopenha is the answer. The linker complains about the missing constructor and destructor that you don't export in the DLL. However the rest is still valid.
[...]
You should have two build targets (or projects, depending on the environment you use).
First target will build the DLL. The files this target will need to be built are, based on what you report:
currency.hpp
allccy.hpp
and probably the implementation of the base class "currency". You must have defined SANPROJ_EXPORTS in the preprocessor defines in order to use the currency.hpp file as a definition of the functions exported by your DLL.
This target will produce a .DLL file and probably (depends on configuration) a .lib file. It may also generate other files like a text representation of the exports of the library (a .DEF file).
Then, you need to build your application (the second target/project):
the header file you need is just simply the same of the library for the #include part. Just be sure to NOT define SANPROJ_EXPORTS or the compiler will try to export again the simbols instead of importing them.
Then you need to add the following settings to the compiler and linker:
Add to the include path the directory containing the .hpp header.
Add to the libraries path of the linker (lib) the directory
containing the .lib file.
Tell the linker to also link against the .lib you just created (add the full name of your lib file, assuming the DLL is named "currency" probably it will be "currency.lib".
Where and how to add this settings depends on the toolchain/environment and compiler you are using.
In the end, be sure that the compiled executable will be able to find the DLL in the project folder or in a system directory (in the PATH) or it will not start. Just copy the DLL with a post-build step if you have the executable in a different folder than the one used to build the DLL.
The fact that removing the _dllimport part will build the project is probably due to the compiler finding the header AND the implementation of the functions you meant to export, and building all of them statically into the executable.
Assuming you are not in the .NET "managed world", and that we are talking about Windows, there are some more points to look at if you want to distribute your library, but this is another answer.
It is specifically complaining about the constructor and destructor for the USDCurrency class but your code does not show those methods as being adorned with SANPROJ_API.
And since you define the USDCurrency constructor in the header, when you remove the dllimport from the class USDCurrency you are getting an implementation defined in your current project and not a reference to the one defined in the DLL.
Everyone else has beat this, I will too.
Re the compiler adding libs, the compiler does just that: compiles. The linker links (doh). Your's appears to be a linker configuration issue, and there are a number of ways to solve this.
If you have a multi-project solution file (.sln) that contains both your DLL project and your EXE project, you can establish an explicit dependency by setting the DLL project to be 'referenced' by the EXE project in the EXE project. Within this, make sure the "Link Library Dependencies" is marked 'true'.
The References configuration is actually a .NET addition starting with VS2005, though it still works for standard C/C++ projects as well. You can skip that and configure the import library to link implicitly on the Linker/Input settings of the EXE project. A setting called "Link Library Dependencies" can me marked true there as well. This also requires you configure the solutions project dependencies (Build/Project Dependencies...). In your case you select your EXE project as "depends on.." and check the DLL project. This ensures that your EXE will be relinked whenever your DLL project is rebuilt and a new import library is created.
If requested, screenshots of all of this are available. It gets to be old habit to set it up after a few go-arounds. At this point I'm fairly sure I can do it blind-folded.
It seems that there is no solution to this problem. I ended up giving up on using dllimport in the client code and take a performance hit. :(
Related
I have a simple project setup for an OpenGL-project for University.
An API project where every library I want to use (GLEW, GLFW, GLM) is linked statically. These libraries should be combined with my own API code into one single DLL file.
The other project should only have one dependency, the DLL. Throw that DLL it should get access to the API code and all libraries linked inside the API.
My problem is that inside the API I have access to all functions of all libraries I linked. But inside the actual project which has the API as a dependency, I can call the functions and the compiler throws out no error (of cause) because the function declaration is in the linked header files but the linker does not find the function definition inside the DLL, which mean the build of the API does not export the linked libraries into the DLL.
In the API project, I also defined the necessary preprocessor definitions:
I defined _GLFW_BUILD_DLL:
from "glfw3.h" l. 233-245
/* GLFWAPI is used to declare public API functions for export
* from the DLL / shared library / dynamic library.
*/
#if defined(_WIN32) && defined(_GLFW_BUILD_DLL)
/* We are building GLFW as a Win32 DLL */
#define GLFWAPI __declspec(dllexport) <----- this one is active
#elif defined(_WIN32) && defined(GLFW_DLL)
/* We are calling GLFW as a Win32 DLL */
#define GLFWAPI __declspec(dllimport)
#elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL)
/* We are building GLFW as a shared / dynamic library */
#define GLFWAPI __attribute__((visibility("default")))
#else
/* We are building or calling GLFW as a static library */
#define GLFWAPI
#endif
I defined GLEW_BUILD:
from "glew.h" l. 200-208
#ifdef GLEW_STATIC
#define GLEWAPI extern
#else
#ifdef GLEW_BUILD
#define GLEWAPI extern __declspec(dllexport) <---- this one is active
#else
#define GLEWAPI extern __declspec(dllimport)
#endif
#endif
Any help?
EDIT:
The linker options:
/OUT:"D:\Programmierung\C++-Projekte\CG-Project\CGAPI\bin\Debug\Win32\CGAPI.dll" /MANIFEST /NXCOMPAT /PDB:"D:\Programmierung\C++-Projekte\CG-Project\CGAPI\bin\Debug\Win32\CGAPI.pdb" /DYNAMICBASE "glew32s.lib" "glfw3.lib" "opengl32.lib" "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /IMPLIB:"D:\Programmierung\C++-Projekte\CG-Project\CGAPI\bin\Debug\Win32\CGAPI.lib" /DEBUG /DLL /MACHINE:X86 /INCREMENTAL /PGD:"D:\Programmierung\C++-Projekte\CG-Project\CGAPI\bin\Debug\Win32\CGAPI.pgd" /SUBSYSTEM:WINDOWS /MANIFESTUAC:NO /ManifestFile:"D:\Programmierung\C++-Projekte\CG-Project\CGAPI\bin-int\Debug\Win32\CGAPI.dll.intermediate.manifest" /ERRORREPORT:PROMPT /NOLOGO /LIBPATH:"D:\Programmierung\C++-Projekte\CG-Project\Dependencies\GLFW\Win32\lib-vc2019\" /LIBPATH:"D:\Programmierung\C++-Projekte\CG-Project\Dependencies\GLEW\lib\Release\Win32\" /TLBID:1
The one I added:
/WHOLEARCHIVE:glew32s.lib
/WHOLEARCHIVE:glfw3.lib
/WHOLEARCHIVE:opengl32.lib
EDIT 2:
So I had to download the source code from glew and build it myself and also I had to remove the .res file inside the option of my own glew build. Now the API builds successfully but the methods aren't part of the DLL. So nothing changed.
I don't fully understand your motivation for doing things this way. The common approach (that I'd also use) is shipping the OpenGL .dlls (I'm not aware of the licensing implications) along with yours.
However, even if this looks like an XY Problem, in order to achieve your goal, you could pass [MS.Docs]: /WHOLEARCHIVE (Include All Library Object Files) to the linker. In order to differentiate which .libs to include and which not, specify the flag once per each target library: /wholearchive:glew32.lib /wholearchive:glfw3.lib /wholearchive:glm.lib.
Check [SO]: Exporting symbols in static library that is linked to dynamic library (#CristiFati's answer) for more details.
As a note: the .libs must have been built with exportable symbols. If not, you'll have to export them "manually", using one of the other choices:
/EXPORT linker option
Module definition (.def) files
or rebuild the .lib as static but with exportable symbols. However, there's high chance it won't work OOTB (you'l probably need to modify a file or 2 or manually pass a compile flag), as it's not a normal way (most of the people would agree that's a NO-NO, especially for someone without a fairly deep know-how) of doing things.
I cannot get a DLL to link, that needs a class exported from the app this DLL will be used with. Visual Studio 2008, Windows 7.
I had a small sample DLL compiling (the default MSFT DLL project actually), and the app can use LoadLibrary() and GetProcAddress() on it correctly. I'm experienced with dllimport/dllexport. Using dumpbin /exports was critical to discover the mangled names to use with GetProcAddress() (MSFT's default empty DLL includes a sample function without extern "C") but this is a solved problem.
The next step was to have the app export a class that the DLL will need to subclass. I do the dllimport/dllexport #define's in the reverse sense from usual: a special symbol when the app is compiled tags the class with dllexport and non-app code (such as the DLL) using that header, without the special symbol, gets a dllimport spec. dumpbin /exports on the .exe file shows exactly this class's (mangled) symbols being exported, and no others, as expected.
The next step was to have the DLL include the header and create an object of the exported object's type (as a baby-step towards actually subclassing it). Compiles fine, but linker shows error:
DynTest.obj : error LNK2019: unresolved external symbol "public: __thiscall Test::Test(class Toast*,double)" (??0Test##QAE#PAVToast##N#Z) referenced in function "public: __thiscall CDynTest::CDynTest(void)" (??0CDynTest##QAE#XZ)
OK, that didn't surprise me, as I know on WIN32 I need to supply DLL's at link time to make a DLL, unlike my usual Unix. Since Windows seems to treat DLLs and executables a bit similarly, I tried adding the .exe at Properties->Configuration Properties->Linker->Input->Additional Dependencies. That gets an error that looks like LINK.EXE didn't auto-detect that it was being given an .exe:
T:\mypath\MyBinary.exe : fatal error LNK1107: invalid or corrupt file: cannot read at 0x348
I then tried adding instead the object file that defines this class... That seems to be understood by the linker, and is probably successfully satisfying the DLL's need to link, but now shows a myriad of other symbols this file depends upon.
So I've considered refactoring the app such that most of it is in a DLL or LIB, just so I can supply that as an "Additional Dependencies" to the DLL I'm actually worried about. But this seems to be draconian. Is that my only option?
Invoking dumpbin /exports gives you a list of mangled names of exe exports. You need to create a module definition file (.def) containing these names:
EXPORTS
#d3d_some_fancy_mangedled_method_1
#d3d_some_fancy_mangedled_method_2
...
Notice that it is basically dumpbin output with first columns removed.
Then you use lib tool to generate export library from module definition file:
LIB /DEF:prog.def /NAME:prog.exe /MACHINE:x86
Finally you link generated export library prog.lib into your application. /MACHINE option should match to your executable. Notice that you don't need to link or anyhow use program executable to link it, only export library is used.
I am using Octave within MSVC 2010. First I downloaded Octave latest version at this link. After installing, I tried to run this simple code:
#include <iostream>
#include<octave-3.6.4\octave\oct.h>
#include<octave-3.6.4\octave\config.h>
#include<octave-3.6.4\octave\octave.h>
using namespace std;
int main (void)
{
std::cout << "Hello Octave world!\n";
system("PAUSE");
return 0;
}
Note that I added these links to my project as well:
C:\Software\Octave-3.6.4\include\octave-3.6.4\octave--->Includ. Dir.,
C:\Software\Octave-3.6.4\include--->Includ. Dir.
C:\Software\Octave-3.6.4\lib--->Lib. Dir.
C:\Software\Octave-3.6.4\lib\octave\3.6.4--->Lib Dir.
I also added 1 and 2 to Additional Inc Dir!!
C:\Software\Octave-3.6.4\lib\octave\3.6.4--->Additional Lib. Dir in Linker.
First, I got this error that it cannot find math.h in Program Files while this file was in my Program Files (x86). So, I changed it to: C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\math.h and it solved this error. However, now I get this error:
error LNK2019: unresolved external symbol "__declspec(dllimport) public: __thiscall octave_value::~octave_value(void)" (__imp_??1octave_value##QAE#XZ) referenced in function "public: void * __thiscall octave_value::`vector deleting destructor'(unsigned int)" (??_Eoctave_value##QAEPAXI#Z)
It is not sufficient to add the library path to the project.
You have to add the library name(s) (including .lib) to the "Additional Dependencies" in the Linker/Input tab.
Edit
To verify what library has been searched you can enable the Linker/General/Show Progress option. Then you can see in the Build Output what library has actually be used in symbol search.
Edit
Your example code doesn't show any instance of an array of octave_value instances. So it's a bit surprising that you need to link with any library with the code you've shown. But anyway you want to have these externals resolved.
If there is no other resource (manual, ...) you should detect where the octave_value class is implemented. This can be a static library or a DLL.
You can detect the DLL implementation with a dumpbin /exports on the DLLs. In that case you need the corresponding import libraries. The LIB should have the same base name as the DLL. Verify that you have added that dependency and how the linker searches this library for symbols.
The name of the symbols __imp_??1octave_value##QAE#XZ indicates that it should be in a DLL. But since you have a problem you might want to search LIBs too.
You can detect the LIB implementation with a dumpbin /symbols. In that case you have to add the LIB directly. Again verify it with the Build Output.
The dumpbin output will probably very verbose. You should use either findstr to limit the output or redirect the output to a file and search the symbols with an editor of your choice.
Search for ocatave_value. If you find a different decoration of the constructor and destructor you might have missed to set an option. A preprocessore directory could be used to define how the library is use. E.g. if you find octave_value::octave_value without the __imp_ prefix you have accidentily compiled for a DLL version altough the class is implemented in a static library. In that case, read the manual and ask at the octave mailing list forum or whatever.
I have two VC++ projects inside a sln file in visual studio 2010. I want to use a_flag in the file of another project, is this possible what i am doing below ?
Project 1:
**sample_header.h**
#ifndef SAMPLE_HEADER_API
#define SAMPLE_HEADER_API __declspec(dllimport)
#endif
extern SAMPLE_HEADER_API int a_flg;
**file1.cpp**
#define SAMPLE_HEADER_API __declspec(dllexport)
#include "sample_header.h"
// Intialization of external
int a_flag = 15;
void m_func()
{
int i = 0;
}
Project 2:
**file2.h**
#include <stdio.h>
**file2.cpp**
#include "file1.h"
#include "sample_header.h"
// provided path of "sample_header.h" in additional include directory as well
void main()
{
if(a_flag > 0)
{
std::cout << "FLAG" ;
}
}
I set project1 as a DLL, project2 as an EXE project.
In linking, I am getting this error :
error LNK2001: `unresolved external symbol "__declspec(dllimport) int a_flg" (__imp_?a_flg##3HA)` in file2.cpp
I have read Microsoft page here about the DLL creation and linking but no idea how to resolve this external symbol error.
Thanks !
You need to set the project that creates your .dll to also generate the .lib file (an import library).
A quick description of the linkage should be something like this :
DLL Dependency Project -> dependecy.dll + dependency.lib
Main Project -> depends at runtime to depedency.dll , depends at link time to dependency.lib.
In other words, your .dll is just another binary that exposes some function signatures.
At runtime you can choose for either c linkage which involves querying the dll for the exposed functors/variables via name (the hard way, but useful when you don't have the .dll source code at hand) or use a more elegant way where you link the generated static library with your main.
When using the 1st approach, you will need to treat inside your code if you cannot find a certain .dll .
When using the 2nd approach, your binary will know that it depends on a certain .dll when you try to run it .
Here's an answer you will find very useful :
How do I build an import library (.lib) AND a DLL in Visual C++?
I would like to build two C++ projects in the same solution in Visual Studio 2010 that can interact with each other. I have created a solution under directory C:\Users\me\Desktop\SolutionDir. The two projects have been created respectively under C:\Users\me\Desktop\SolutionDir\FirstProject and C:\Users\me\Desktop\SolutionDir\SecondProject.
My first project contains two files, a header function.h and a cpp file function.cpp
function.h
#pragma once
void print_stuff();
function.cpp
#include "function.h"
#include <iostream>
void print_stuff() {
std::cout << "hello world" << std::endl;
}
My second project contains the main file main.cpp
main.cpp
#include "FirstProject\function.h"
#include <iostream>
int main(void) {
print_stuff();
int stop;
std::cin >> stop;
return 0;
}
I added the directory C:\Users\me\Desktop\SolutionDir\ in my SecondProject Configuration Properties > C/C++ > General > Additional Include Directories. I still get the classical error : error LNK2019: unresolved external symbol when calling the function print_stuff().
Any ideas ?
Try building the first project as a Static Library in Project Properties/Configuration Properties/General/Configuration Type.
Then in your project properties for the second project, you'll need to change two things:
In Linker/General, you might need to add to "Additional Library Directories" the folder where the first project's .lib is built.
In Linker/Input, you will need to add to Additional Dependencies the name of the .lib file like FirstProject.lib or whatever its name is.
Yes, you need to export the functions using _declspec(dllexport) and import them in the project that calls the functions with _declspec(dllimport).
This duality is usually achieved with a macro:
#pragma once
#ifdef FIRST_PROJECT_BUILD
#define IMPEXP _declspec(dllexport)
#else
#define IMPEXP _declspec(dllimport)
#endif
IMPEXP void print_stuff();
In the configuration of your first project, you add FIRST_PROJECT_BUILD to your preprocessor directives. That way, when you compile first project, you tell the compiler the function is to be exported. However, when you include the file in a different project, that doesn't have FIRST_PROJECT_BUILD defined, you tell the compiler the function is implemented in a different library and should be imported.
Also, besides adding the extra include paths, you need to add the generated .lib files from the projects implementing the functions to the Extra dependencies tab in the Liner settings of your project configuration.
You can include a realPath for you include directory !
Like for your FirstProject include "./../"
And the same include dir for your second Project like that you can move or copy your directory SolutionDir and it will always work !
For your unresolved linked you have to add the function.cpp and function.h in your First and Second Project
You can place it in SolutionDir!
Like that You always have two files for your first and second project instead of four !
Hope it helps !