I am wrapping a static library in Dll to hide a lot of the implementation stuff since only 4-5 functions are needed and to avoid providing all third-party libraries and many header files. I seem to be having an issue with exporting a function to the dll from the static lib.
The static lib has settings classes / structs similar to the one below
struct FooSettings
{
bool Read(const std::string& file); // implemented in .cpp
bool Write(const std::string& file); // implemented in .cpp
// rest members, just plain types
};
In the Dll side
#include "FooSettings.h"
#if defined(WIN32) || defined(_WIN32)
#if defined(LIB_EXPORT)
// DLL Build, exporting symbols
#define LIB_API __declspec(dllexport)
#elif LIB_IMPORT
// DLL use, importing symbols
#define LIB_API __declspec(dllimport)
#endif
#endif
#ifndef LIB_API
#define LIB_API
#endif
class LIB_API LibSDK
{
public:
LibSDK();
~LibSDK();
FooSettings get() const noexcept;
void set(const FooSettings& settings) const noexcept;
void dummy()
{
foo.Read("");
}
private:
// etc...
};
I can call dummy() on the "client" side without any issues
but the code below leads to unresolved symbols
FooSettings foo;
foo.Read("");
I would have expected that the FooSettings:Read is at least exported since it is part of a dummy function. Am I missing something ? My preference is to export it without the dummy function but I dont seem to be able to make it work either way.
Coming back to all this, the answer was actually to #define LIB_EXPORT in the static library build as well which I did not expect.
I did not think that such a thing would be needed for a static .lib files since all they are is just a bundle of object files so they did not need to be marked for export. Apparently, it was needed if you want to export the functions from the static lib to your wrapper dll.
Related
We are working on two C++ code base, let's call it A and B, the A is an build as an library, and distribute the header files .h and .a file to B.
Let's say there is Lock.h file in A as following:
// Lock.h in code base A
class Lock {
... ...
#ifdef TRACK_THREAD_OWNER_FOR_DEBUG
virtual int GetLockOwner();
#endif
... ...
private:
CriticalSection section;
#ifdef TRACK_THREAD_OWNER_FOR_DEBUG
int threadOwner;
#endif
};
// Caller.cc in code base B
#include "xxx/xxx/Lock.h"
Lock lockObject;
lockObject.Lock();
In code base A, we by default will enable TRACK_THREAD_OWNER_FOR_DEBUG and may change it just before final release day.
We hit some hard bug because TRACK_THREAD_OWNER_FOR_DEBUG are different in A and B, and cause memory corruption because the sizeof(Lock) is different in two library.
So how to protect from this error? Can we trigger an compiler error when build the caller.cc file if the build macro TRACK_THREAD_OWNER_FOR_DEBUG is different in two project?
It is not possible to make this into compiler error, however it should be possible to make this into reasonably clear linker error by exporting some symbol which name depends on the currently defined macros. For example using static guard variable:
// Foo.hpp - library header file
#pragma once
class Foo
{
public: Foo();
#ifdef IMPORTANT_CONDITION
int m_field;
#endif
};
class ConditionGuard
{
public:
ConditionGuard(void) noexcept
{
#ifdef IMPORTANT_CONDITION
CONDITION_ON();
#else
CONDITION_OFF();
#endif
}
#ifdef IMPORTANT_CONDITION
private: static void CONDITION_ON(void);
#else
private: static void CONDITION_OFF(void);
#endif
};
static ConditionGuard const condition_guard{};
// Foo.cpp - library implementation file
#include "Foo.hpp"
Foo::Foo(void) {}
#ifdef IMPORTANT_CONDITION
void ConditionGuard::CONDITION_ON(void) {}
#else
void ConditionGuard::CONDITION_OFF(void) {}
#endif
Now when user code includes library header Foo.hpp it will also trigger construction of condition_guard static variable which will call a library function depending on condition being protected. So if there is a translation unit including Foo.hpp where IMPORTANT_CONDITION is defined differently than in compiled library then there will be a linker error for missing CONDITION_ON or CONDITION_OFF. CONDITION_ON and CONDITION_OFF function names should contain error text.
One option is to just include the full code for A into project B. What are you trying to do by compiling A into a static library?
I think you're best option is to generate different .a files depending the target. i.e. libA_debug.a when TRACK_THREAD_OWNER_FOR_DEBUG is set, libA.a when it is not.
Then you could set the library to link B to based on whether you are compiling a debug or release version.
Most of my C/C++ development involves monolithic module files and absolutely no classes whatsoever, so usually when I need to make a DLL with accessible functions I just export them using the standard __declspec(dllexport) directive. Then access them either dynamically via LoadLibrary() or at compile time with a header and lib file.
How do you do this when you want to export an entire class (and all it's public methods and properties)?
Is it possible to dynamically load that class at runtime and if so, how?
How would you do it with a header and lib for compile time linking?
What about late-binding? As in loading
it with LoadLibrary() and
GetProcAddress() ? I'm used being able
to load the library at run time and it
would be great if you could do that
here.
So there are two ways to load the DLL. The first is to reference one or more symbols from the DLL (your classname, for example), supply an appropriate import .LIB and let the linker figure everything out.
The second is to explicitly load the DLL via LoadLibrary.
Either approach works fine for C-level function exports. You can either let the linker handle it or call GetProcAddress as you noted.
But when it comes to exported classes, typically only the first approach is used, i.e., implicitly link to the DLL. In this case the DLL is loaded at application start time, and the application fails to load if the DLL can't be found.
If you want to link to a class defined in a DLL, and you want that DLL to be loaded dynamically, sometime after program initiation, you have two options:
Create objects of the class using a special factory function, which internally will have to use (a tiny bit of) assembler to "hook up" newly created objects to their appropriate offsets. This has to be done at run-time AFTER the DLL has been loaded, obviously. A good explanation of this approach can be found here.
Use a delay-load DLL.
All things considered... probably better to just go with implicit linking, in which case you definitely want to use the preprocessor technique shown above. In fact, if you create a new DLL in Visual Studio and choose the "export symbols" option these macros will be created for you.
Good luck...
When you build the DLL and the module that will use the DLL, have some kind of #define that you can use to distinguish between one and the other, then you can do something like this in your class header file:
#if defined( BUILD_DLL )
#define IMPORT_EXPORT __declspec(dllexport)
#else
#define IMPORT_EXPORT __declspec(dllimport)
#endif
class IMPORT_EXPORT MyClass {
...
};
Edit: crashmstr beat me to it!
Adding a simple working example for exporting a C++ class from a DLL :
The given below example gives you only a short overview of how dll and exe can interact each other (self explanatory ) but it needs more things to add for changing into a production code.
Full sample example is divided in to two part
A. Creating a .dll library (MyDLL.dll)
B. Creating an Application which uses .dll library (Application).
A. .dll project file (MyDLL.dll):
1. dllHeader.h
#ifdef MYDLL_EXPORTS
#define DLLCALL __declspec(dllexport) /* Should be enabled before compiling
.dll project for creating .dll*/
#else
#define DLLCALL __declspec(dllimport) /* Should be enabled in Application side
for using already created .dll*/
#endif
// Interface Class
class ImyMath {
public:
virtual ~ImyMath() {;}
virtual int Add(int a, int b) = 0;
virtual int Subtract(int a, int b) = 0;
};
// Concrete Class
class MyMath: public ImyMath {
public:
MyMath() {}
int Add(int a, int b);
int Subtract(int a, int b);
int a,b;
};
// Factory function that will return the new object instance. (Only function
// should be declared with DLLCALL)
extern "C" /*Important for avoiding Name decoration*/
{
DLLCALL ImyMath* _cdecl CreateMathObject();
};
// Function Pointer Declaration of CreateMathObject() [Entry Point Function]
typedef ImyMath* (*CREATE_MATH) ();
2. dllSrc.cpp
#include "dllHeader.h"
// Create Object
DLLCALL ImyMath* _cdecl CreateMathObject() {
return new MyMath();
}
int MyMath::Add(int a, int b) {
return a+b;
}
int MyMath::Subtract(int a, int b) {
return a-b;
}
B. Application Project which load and link the already created .dll file:
#include <iostream>
#include <windows.h>
#include "dllHeader.h"
int main()
{
HINSTANCE hDLL = LoadLibrary(L"MyDLL.dll"); // L".\Debug\MyDLL.dll"
if (hDLL == NULL) {
std::cout << "Failed to load library.\n";
}
else {
CREATE_MATH pEntryFunction = (CREATE_MATH)GetProcAddress(hDLL,"CreateMathObject");
ImyMath* pMath = pEntryFunction();
if (pMath) {
std::cout << "10+10=" << pMath->Add(10, 10) << std::endl;
std::cout << "50-10=" << pMath->Subtract(50, 10) << std::endl;
}
FreeLibrary(hDLL);
}
std::cin.get();
return 0;
}
I use some macros to mark the code for import or export
#ifdef ISDLL
#define DLL __declspec(dllexport)
#endif
#ifdef USEDLL
#define DLL __declspec(dllimport)
#endif
Then declare the class in a header file:
class DLL MyClassToExport { ... }
Then #define ISDLL in the libary, and USEDLL before including the header file in the place you want to use the class.
I don't know if you might need to do anything differently for working with LoadLibrary
Recently I asked myself exactly the same question, and summarized my findings in a blog post. You may find it useful.
It covers exporting C++ classes from a DLL, as well as loading them dynamically with LoadLibrary, and discusses some of the issues around that, such as memory management, name mangling and calling conventions.
If you're willing to put a vtable in the class you're exporting, you can export a function that returns an interface and implement the class in the .dll, then put that in the .def file. You might have to do some declaration trickery, but it shouldn't be too hard.
Just like COM. :)
I am using Visual Studio 2012 and I creared dll without using MFC, it generating the dll. But when I specify to generate a lib file in specific directory using the following option:-
go to proeperties page->Advanced->Import Library
../../../lib/myapp.lib
It is not genearting the lib file in the specified folder. Please help me .
Thanks & Regards
Vikas
Just resolved a similar problem. Visual Studio does not create a .lib file without instructing which objects to expose in dll. You need to create a win exports header like this:
#ifndef BLABLABLA
#define BLABLABLA
#ifdef MYAPPLIB_EXPORTS
#define MYAPPLIB_API __declspec(dllexport)
#elif defined(MYAPPLIB_EXPORTS_STATIC)
#define MYAPPLIB_API
#else
#define MYAPPLIB_API __declspec(dllimport)
#endif
#endif // !BLABLABLA
Then, you need to declare MYAPPLIB_EXPORTS as a preprocessor macro. After including this new header file in other API headers, for every class or method which you want to expose in your API, you can add MYAPPLIB_API to their declarations like:
class MYAPPLIB_API MyClass{ ... };
calculatelibrary.h
/*
By default, the New Project template for a DLL adds PROJECTNAME_EXPORTS to the defined preprocessor symbols for the DLL project.
In this example, CALCULATELIBRARY_EXPORTS is defined when your calculateLibrary DLL project is built.
When the CALCULATELIBRARY_EXPORTS symbol is defined, the CALCULATELIBRARY_API symbol sets the __declspec(dllexport) modifier on the member function declarations in this code.
This modifier tells the compiler and linker to export the function or variable from the DLL so that it can be used by other applications.
When CALCULATELIBRARY_EXPORTS is undefined—for example, when the header file is included by a client application—CALCULATELIBRARY_API defines the __declspec(dllimport) modifier on the member function declarations. This modifier optimizes the import of the function in an application. For more information
*/
#ifndef _calculate_library_h
#define _calculate_library_h
#ifdef CALCULATELIBRARY_EXPORTS
#define CALCULATELIBRARY_API _declspec(dllexport)
#else
#define CALCULATELIBRARY_API _declspec(dllimport)
#endif
namespace calculatelibrary
{
class CALCULATELIBRARY_API clsCalculateLibrary{
// Returns a + b
double Add(double a, double b);
};
}
#endif _calculate_library_h
// CalculateLibrary.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "CalculateLibrary.h"
namespace calculatelibrary
{
double clsCalculateLibrary::Add(double a, double b)
{
return a + b;
}
}
See the following: you may need to declare /EXPORTS (http://msdn.microsoft.com/en-us/library/7k30y2k5.aspx)
http://msdn.microsoft.com/en-us/library/67wc07b9.aspx see "REMARKS"
My problem is remarkably similar to this one: A class in a DLL has a static member. In this case, the static member is of Type QString (a QT type) and provides a name for the class. I provide the normal export on class level: __declspec(dllexport).
When I link the DLL with my class to another project and try to compile it, I get an "unresolved external symbol" error for the static data. I verified two things:
Dumpbin definitely reports the static data member to be exported by compiled DLL.
Actually, the static data member seems not to be used in the application which reports the error.
HEADER file (.h) in DLL is:
class __declspec(dllexport) MyClass {
public:
virtual ~MyClass();
static const QString JUST_A_NAME;
};
IMPLEMENTATION file (.cpp) in DLL is:
#include "MyClass.h"
MyClass::~MyClass() { }
const QString MyClass::JUST_A_NAME("call_me_al");
In contrast to already mentioned post, I avoided methods to be inline, e.g. implementation is obviously not in the header. The type, QString (see line 83 ff.), contains several inlines itself. May that cause the error?
EDIT: I added an import statement in the header of my application. It is located before any includes.
HEADER file (.h) in APPLICATION is:
class __declspec(dllimport) MyClass {
public:
virtual ~MyClass();
static const QString JUST_A_NAME;
};
The error remains the same:
error LNK2001: non resolved external symbol ""public: static class QString const MyClass::JUST_A_NAME" (?JUST_A_NAME#MyClass##2VQString##B)". <name of .obj file from application>
In your application header file you need to do two things.
When exporting, declare the definition __declspec(dllexport)
When importing, declare the definition __declspec(dllimport)
You obviously cannot do them both at the same time.
What you have to do is define a macro like this:
#ifdef __COMPILING_MYLIB
#define MYLIBAPI __declspec(dllimport)
#else
#define MYLIBAPI __declspec(dllexport)
#endif
Then declare your exports like this:
// mylib.h
class MYLIBAPI MyClass {
public:
virtual ~MyClass();
static const QString JUST_A_NAME;
};
Then, when compiling MYLIB, you pass -D__COMPLING_MYLIB to the compiler, which triggers the #if above.
That way, when compiling the library itself, the header file declares things as exports, but when compiling things which will use the library, they are declared as imports.
Most of my C/C++ development involves monolithic module files and absolutely no classes whatsoever, so usually when I need to make a DLL with accessible functions I just export them using the standard __declspec(dllexport) directive. Then access them either dynamically via LoadLibrary() or at compile time with a header and lib file.
How do you do this when you want to export an entire class (and all it's public methods and properties)?
Is it possible to dynamically load that class at runtime and if so, how?
How would you do it with a header and lib for compile time linking?
What about late-binding? As in loading
it with LoadLibrary() and
GetProcAddress() ? I'm used being able
to load the library at run time and it
would be great if you could do that
here.
So there are two ways to load the DLL. The first is to reference one or more symbols from the DLL (your classname, for example), supply an appropriate import .LIB and let the linker figure everything out.
The second is to explicitly load the DLL via LoadLibrary.
Either approach works fine for C-level function exports. You can either let the linker handle it or call GetProcAddress as you noted.
But when it comes to exported classes, typically only the first approach is used, i.e., implicitly link to the DLL. In this case the DLL is loaded at application start time, and the application fails to load if the DLL can't be found.
If you want to link to a class defined in a DLL, and you want that DLL to be loaded dynamically, sometime after program initiation, you have two options:
Create objects of the class using a special factory function, which internally will have to use (a tiny bit of) assembler to "hook up" newly created objects to their appropriate offsets. This has to be done at run-time AFTER the DLL has been loaded, obviously. A good explanation of this approach can be found here.
Use a delay-load DLL.
All things considered... probably better to just go with implicit linking, in which case you definitely want to use the preprocessor technique shown above. In fact, if you create a new DLL in Visual Studio and choose the "export symbols" option these macros will be created for you.
Good luck...
When you build the DLL and the module that will use the DLL, have some kind of #define that you can use to distinguish between one and the other, then you can do something like this in your class header file:
#if defined( BUILD_DLL )
#define IMPORT_EXPORT __declspec(dllexport)
#else
#define IMPORT_EXPORT __declspec(dllimport)
#endif
class IMPORT_EXPORT MyClass {
...
};
Edit: crashmstr beat me to it!
Adding a simple working example for exporting a C++ class from a DLL :
The given below example gives you only a short overview of how dll and exe can interact each other (self explanatory ) but it needs more things to add for changing into a production code.
Full sample example is divided in to two part
A. Creating a .dll library (MyDLL.dll)
B. Creating an Application which uses .dll library (Application).
A. .dll project file (MyDLL.dll):
1. dllHeader.h
#ifdef MYDLL_EXPORTS
#define DLLCALL __declspec(dllexport) /* Should be enabled before compiling
.dll project for creating .dll*/
#else
#define DLLCALL __declspec(dllimport) /* Should be enabled in Application side
for using already created .dll*/
#endif
// Interface Class
class ImyMath {
public:
virtual ~ImyMath() {;}
virtual int Add(int a, int b) = 0;
virtual int Subtract(int a, int b) = 0;
};
// Concrete Class
class MyMath: public ImyMath {
public:
MyMath() {}
int Add(int a, int b);
int Subtract(int a, int b);
int a,b;
};
// Factory function that will return the new object instance. (Only function
// should be declared with DLLCALL)
extern "C" /*Important for avoiding Name decoration*/
{
DLLCALL ImyMath* _cdecl CreateMathObject();
};
// Function Pointer Declaration of CreateMathObject() [Entry Point Function]
typedef ImyMath* (*CREATE_MATH) ();
2. dllSrc.cpp
#include "dllHeader.h"
// Create Object
DLLCALL ImyMath* _cdecl CreateMathObject() {
return new MyMath();
}
int MyMath::Add(int a, int b) {
return a+b;
}
int MyMath::Subtract(int a, int b) {
return a-b;
}
B. Application Project which load and link the already created .dll file:
#include <iostream>
#include <windows.h>
#include "dllHeader.h"
int main()
{
HINSTANCE hDLL = LoadLibrary(L"MyDLL.dll"); // L".\Debug\MyDLL.dll"
if (hDLL == NULL) {
std::cout << "Failed to load library.\n";
}
else {
CREATE_MATH pEntryFunction = (CREATE_MATH)GetProcAddress(hDLL,"CreateMathObject");
ImyMath* pMath = pEntryFunction();
if (pMath) {
std::cout << "10+10=" << pMath->Add(10, 10) << std::endl;
std::cout << "50-10=" << pMath->Subtract(50, 10) << std::endl;
}
FreeLibrary(hDLL);
}
std::cin.get();
return 0;
}
I use some macros to mark the code for import or export
#ifdef ISDLL
#define DLL __declspec(dllexport)
#endif
#ifdef USEDLL
#define DLL __declspec(dllimport)
#endif
Then declare the class in a header file:
class DLL MyClassToExport { ... }
Then #define ISDLL in the libary, and USEDLL before including the header file in the place you want to use the class.
I don't know if you might need to do anything differently for working with LoadLibrary
Recently I asked myself exactly the same question, and summarized my findings in a blog post. You may find it useful.
It covers exporting C++ classes from a DLL, as well as loading them dynamically with LoadLibrary, and discusses some of the issues around that, such as memory management, name mangling and calling conventions.
If you're willing to put a vtable in the class you're exporting, you can export a function that returns an interface and implement the class in the .dll, then put that in the .def file. You might have to do some declaration trickery, but it shouldn't be too hard.
Just like COM. :)