I have inherited a Linux project that I need to port to Windows and Visual Studio. I have setup the same project structure as was the case in Linux but I find the structure a bit strange (maybe it is all good in Linux) and I believe that's what's causing the LNK4217 (locally defined symbol 'symbol' imported in function 'function') and C4273 ('function' : inconsistent DLL linkage) warnings I receive. I would like some advice on how to re-structure the project or change the code to avoid these warnings. Basically this is what I have:
Dll project called Foo
Dll project called Bar (depends on the Foo dll)
The part that I find strange and what I believe causes the LINK4217 and C4273 warnings is that both the Foo and Bar library contain the header and source file for the class MyClass (the warnings mention this class):
//MyClass.h
class BAR_API MyClass
{
//Methods etc.
}
Where BAR_API is defined as __declspec(dllexport) in the Bar library while in the Foo library it is __declspec(dllimport) according to:
#ifdef BAR_EXPORTS
#define BAR_API __declspec(dllexport)
#else
#define BAR_API __declspec(dllimport)
#endif
How do you propose I change this? Would it help to move MyClass to its own library and have Foo and Bar include it or change so that BAR_API is defined as nothing instead of __declspec(dllimport) in the Foo library?
Let's see what you have here
1. Foo.dll that defines MyClass and exports it
2. Bar.dll that depends on Foo.dll, but also defines MyClass - and this is the source of ambiguity that confuses your linker.
The right thing, to my understanding, is to:
Define MyClass in Foo.dll (since Bar.dll already depends on it) and export MyClass using __declspec(dllexport) in Foo.dll's MyClass declaration.
#include header file that declares MyClass (where it will be specified as imported using __declspec(dllimport)) where appropriate in the Bar.dll's .cpp files; however, do not include the .cpp file that implements MyClass.
BAR_API (which in this case should be renamed to FOO_API) helps you achieve this by being defined as either dllexport or dllimport based on whether BAR_EXPORTS (which in this case should be renamed to FOO_EXPORTS) is defined. You should #define FOO_EXPORTS in every source file in the Foo project either by setting compiler command line parameter or by #including common header that #defines FOO_EXPORTS in every .cpp file in the Foo project (but not in the Bar project).
This way both Foo.dll and Bar.dll will use MyClass from the Foo.dll.
HTH
Related
#if COMPILING_DLL
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT __declspec(dllimport)
#endif
How / where do I define COMPILING_DLL ?
Seen here:
what does __declspec(dllimport) really mean?
Sounds like I can't use load-time dynamic linking at all if I can't use the same header?
One another option:
Use the default defined macro local to the project.
You can see the default defined macros local to the project in the below location:
Properties -> C/C++ -> Preprocessor -> Preprocessor Definition.
Example:
Suppose your Project Name is: MyDLL
Default Macro Local to that project: MYDLL_EXPORTS
#ifdef MYDLL_EXPORTS
/*Enabled as "export" while compiling the dll project*/
#define DLLEXPORT __declspec(dllexport)
#else
/*Enabled as "import" in the Client side for using already created dll file*/
#define DLLEXPORT __declspec(dllimport)
#endif
Best place to define COMPILING_DLL=1 is command line of compiler. If you use Visual Studio IDE then it is in Project properties ... C/C++ ... Preprocessor ... Preprocessor Definitions.
__declspec(dllimport) is Microsoft specific extension to C++. Microsoft has excellent online documentation.
In the DLL project, you add a #define (either in a header file or in the project properties) for COMPILING_DLL. As this will not be set for any other project (especially if you name it something better than COMPILING_DLL) then the #if directive will work properly.
You (actually Visual Studio in ideal cases) defines the COMPILING_DLL as an argument to the compiler when you build the DLL. So, it will default to __declspec(dllexport). On the other end, when you USE the DLL's header file, you don't define this, so DLLEXPORT will be evaluated by default to __declspec(dllimport).
If you use CMake to generate your build configuration, you should be able to use
the macro <projectname>_EXPORTS the way you want to use COMPILING_DLL, where projectname was defined with the CMake command project(projectname):
A preprocessor macro, <target_name>_EXPORTS is defined when a shared library compilation is detected.
source
I tested and it works on Windows using the Ninja generator with compiler MSVC from Visual Studio 2015 Express.
Related: CMake adds -Dlibname_EXPORTS compile definition
You can't define function body that way in the header file. It is prohibited by __declspec(dllimport). This specifier can only be specified on function declaration, not definition.
You have to move the function body to a source file.
in header file:
extern DLLEXPORT void test2();
In .cpp file:
void test2()
{
// ...
}
As folks said, don't forget to add COMPILING_DLL to the project preprocessor definitions.
Actually, the real problem is the preprocessor directive.
You should use #ifdef and not #if to test if the variable is really defined (and we don't care about the defined value or if there is any).
NOTE: I know this thread is 1-year old but it still may be useful for somebody who have this problem in the future.
#if COMPILING_DLL
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT __declspec(dllimport)
#endif
How / where do I define COMPILING_DLL ?
Seen here:
what does __declspec(dllimport) really mean?
Sounds like I can't use load-time dynamic linking at all if I can't use the same header?
One another option:
Use the default defined macro local to the project.
You can see the default defined macros local to the project in the below location:
Properties -> C/C++ -> Preprocessor -> Preprocessor Definition.
Example:
Suppose your Project Name is: MyDLL
Default Macro Local to that project: MYDLL_EXPORTS
#ifdef MYDLL_EXPORTS
/*Enabled as "export" while compiling the dll project*/
#define DLLEXPORT __declspec(dllexport)
#else
/*Enabled as "import" in the Client side for using already created dll file*/
#define DLLEXPORT __declspec(dllimport)
#endif
Best place to define COMPILING_DLL=1 is command line of compiler. If you use Visual Studio IDE then it is in Project properties ... C/C++ ... Preprocessor ... Preprocessor Definitions.
__declspec(dllimport) is Microsoft specific extension to C++. Microsoft has excellent online documentation.
In the DLL project, you add a #define (either in a header file or in the project properties) for COMPILING_DLL. As this will not be set for any other project (especially if you name it something better than COMPILING_DLL) then the #if directive will work properly.
You (actually Visual Studio in ideal cases) defines the COMPILING_DLL as an argument to the compiler when you build the DLL. So, it will default to __declspec(dllexport). On the other end, when you USE the DLL's header file, you don't define this, so DLLEXPORT will be evaluated by default to __declspec(dllimport).
If you use CMake to generate your build configuration, you should be able to use
the macro <projectname>_EXPORTS the way you want to use COMPILING_DLL, where projectname was defined with the CMake command project(projectname):
A preprocessor macro, <target_name>_EXPORTS is defined when a shared library compilation is detected.
source
I tested and it works on Windows using the Ninja generator with compiler MSVC from Visual Studio 2015 Express.
Related: CMake adds -Dlibname_EXPORTS compile definition
You can't define function body that way in the header file. It is prohibited by __declspec(dllimport). This specifier can only be specified on function declaration, not definition.
You have to move the function body to a source file.
in header file:
extern DLLEXPORT void test2();
In .cpp file:
void test2()
{
// ...
}
As folks said, don't forget to add COMPILING_DLL to the project preprocessor definitions.
Actually, the real problem is the preprocessor directive.
You should use #ifdef and not #if to test if the variable is really defined (and we don't care about the defined value or if there is any).
NOTE: I know this thread is 1-year old but it still may be useful for somebody who have this problem in the future.
I want to export a decorated function name in a def file like this:
LIBRARY Example
EXPORTS
??0__non_rtti_object#std##QAE#ABV01##Z=myfunc #1
The Problem is that the linker strips the function name at the first #-sign and places just
"??0__non_rtti_object" into the export table. My question is now, if there is a way to include
the #-characters as well? I use Visual Studio 2010. Maybe there is someone who can help me.
Thanks in advance, Hannes.
Preamble
You didn't answer my comment about the use of the .DEF file, so I assume you must be unfamiliar with the the dllexport and dllimport qualifiers. With them, there is no need for the .DEF file to export symbols.
If there is a particular need for the .DEF file that invalidate the use of the dllimport/dllexport feature, please ignore the following.
How to use dllimport/dllexport?
In your public header (say, public.hpp), write something like:
#ifdef MY_PROJECT_EXPORTS
#define MY_PROJECT_API __declspec(dllexport)
#else
#define MY_PROJECT_API __declspec(dllimport)
#endif
This way, the macro MY_PROJECT_API will enable the export/import of your symbols. For example, later, in the same public.hpp, you can declare:
// A global variable
MY_PROJECT_API int myGlobalVariable ;
// A function
MY_PROJECT_API void my_function() ;
// A class or struct
class MY_PROJECT_API MyClass
{
public :
int i;
virtual int foo() ;
// etc.
} ;
Then, what you need to do is, in the project options of your library, define the MY_PROJECT_EXPORTS: This way, when you compile your library, the symbols above are declared dllexport, and when someone else includes your public.hpp header, the symbols above will be dllimport
And if your code is cross-platform (dllimport/dllexport is a MS compiler feature), just wrap the defines above around a compiler test. For example:
#ifdef _MSC_VER
// For MS Visual Studio
#ifdef MY_PROJECT_EXPORTS
#define MY_PROJECT_API __declspec(dllexport)
#else
#define MY_PROJECT_API __declspec(dllimport)
#endif
#else
// For other compilers
#define MY_PROJECT_API
#endif
About the .DEF file?
The .DEF file was used before, when exportable C functions were still "the way to go" on Visual Studio.
For strong type safety, C++ decorate its symbols.
The downside is that each compiler has its own decoration scheme (which never bothered me in 12-years of development), and that finding the exact, decorated name of a symbol can't be painful.
But the merits of that is that:
You can now export overloaded/namespaced functions/symbols
the parameter types are part of the ABI, meaning the linker can verify you aren't screwing up or cheating with your types
The dllimport and dllexport features have the following advantages:
it enables the export to be done at source level, instead of using yet another project file
the programmer can now ignore the particular decoration scheme (which usually only interests the linker), all the while profiting from the strong type safety of C++ extended to the linker.
Sources
For more information, see:
__declspec : http://msdn.microsoft.com/en-us/library/dabb5z75.aspx
dllexport, dllimport : http://msdn.microsoft.com/en-us/library/3y1sfaz2.aspx
Using dllimport and dllexport in C++ Classes : http://msdn.microsoft.com/en-us/library/81h27t8c.aspx
I have a dll with a class that define some methods and variables inside it. I marked it as
__declspec(dllexport)
and i imported the .h header inside a win32 application project in the same solution. I can use the functions but when I try to compile the project I have a lot of errors about external symbols not resolved. Why?
Please read about the standard way of using macros for this very common task here: http://wiki.tcl.tk/8721
The basic idea is that you define a macro, say MY_API like so:
#ifdef BUILD_MYAPI
# define MY_API __declspec(dllexport)
#else
# define MY_API __declspec(dllimport)
#endif
When you declare a function or a class in the header file you do this:
void MY_API myApiFunction(int x);
When you build your own dll which declares the body of the function, you add the definition of BUILD_MYAPI to the build. This makes all declerations to be dllexport
when you include the header from some other dll you don't add BUILD_MYAPI so the decelerations are dllimport
When compiling with visual studio, you can add a macro definition to the compilation without changing the source from project properties -> C/C++ -> Preprocesson -> Preprocessor definitions
For the application where you want to import that class, you will need to mark the class as
__declspec(dllimport)
Instead of dllexport.
You must also make sure to link with the import library of the DLL (a .lib file).
Probably a simple question but I only have Linux to test this code on where __declspec(dllexport) is not needed. In the current code __declspec(dllexport) is in front of all files in the .h file but just in front of like 50% of the functions in the cpp file so I am wondering if they are really needed in the cpp file at all ?
No, its only needed in the header.
Here's a link with more info.
Expanding on what Vinay was saying, I've often seen a macro defined
#if defined(MODULENAME_IMPORT)
#define EXPORTED __declspec(dllimport)
#elif defined(MODULENAME_EXPORT)
#define EXPORTED __declspec(dllexport)
#endif
Then in your header you do
void EXPORTED foo();
set the defines accordingly in the project settings for the project doing the import/exporting.
No, it is not required in cpp file. Only in declaration it is required.
For Example if I have a class CMyClass. If I want to export this then .h will have
.h Server code
__declspec(dllexport) CMyClass
{
};
In the client code i.e., which uses this class you have to forward declare the class as
Client code
__declspec(dllimport) CMyClass;
// Code to use the class
You may use in .cpp file also when you have templated code and you are instantiating in .cpp file then you need to export the definition when it is instantiated. But even in this case, I have seen that doing in .h also works. On windows you can use dumpbin.exe /exports *.dll to see what signatures are exported, there is similar utility in Linux too. This will give you an idea how signature is exported.