C++ Unresolved external symbol - library problem? - c++

Sorry if the question is dumb, I'm still a noobie.
I've got a header and a .lib file. I've included the header and set up the library file in the linker additional libraries directory, however I keep getting unresolved external symbol error over the functions defined in the header (which should be included in the library).
On the top of the header the following is written:
#pragma once
// To use the framework define _WINDOWS in project's settings!
#if defined(_WINDOWS)
#if defined(FRAMEWORK_PROJECT)
#define FRAMEWORK_API extern "C" __declspec(dllexport)
#else
#define FRAMEWORK_API extern "C" __declspec(dllimport)
#endif
#else
#define FRAMEWORK_API
#endif
Where would I need to define _WINDOWS variable, and what to? (Visual Studio) or is the problem something different entirely?

Related

GLEW - why should I define GLEW_STATIC?

I am using a statically linked library for GLEW and therefore I have to define GLEW_STATIC to compile my programs that are using GLEW. But I have never understood why this is necessary. So could anyone explain the reason?
When a function is implemented in a static library that must be specified. The extern keyword provides linkage information. A function which is imported from a dynamic library has to be marked by extern __declspec(dllimport). GLEW_STATIC is a preprocessor definition which activates the first case.
The relevant code part in the "glew.h" file (verison 2.1.0) is:
/*
* GLEW_STATIC is defined for static library.
* GLEW_BUILD is defined for building the DLL library.
*/
#ifdef GLEW_STATIC
define GLEWAPI extern
#else
ifdef GLEW_BUILD
define GLEWAPI extern __declspec(dllexport)
else
define GLEWAPI extern __declspec(dllimport)
endif
#endif

What does #ifdef WIN32DLL_EXPORTS mean?

I've created a DLL a file, and in the header file I see :
#ifdef WIN32DLL_EXPORTS
I don't understand what does it mean and where/how we can set up WIN32DLL_EXPORTS.
if I use:
#ifdef WIN32DLL_EXPORTS
#define WIN32DLL_API __declspec(dllexport)
#else
#define WIN32DLL_API __declspec(dllimport)
#endif
WIN32DLL_API int testSum(void);
testSum is considered as __declspec(dllimport). So I think my project is not set to WIN32DLL_EXPORTS? How can I change this?
There is a comment block immediately above the line you quoted. Read it.
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the WIN32DLL_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// WIN32DLL_API functions as being imported from a DLL, wheras this DLL sees symbols
// defined with this macro as being exported.
#ifdef WIN32DLL_EXPORTS
#define WIN32DLL_API __declspec(dllexport)
#else
#define WIN32DLL_API __declspec(dllimport)
#endif
You can either:
define WIN32DLL_EXPORTS in the project's Properties > Configuration Properties > C/C++ > Preprocessor > Preprocessor definitions.
if you use a precompiled header (e.g. stdafx.h) then you can also define WIN32DLL_EXPORTS
there with a #define statement.

Where do I create preprocessor directives for a dll export?

I am creating a c++ dll to be imported in vb.net.
I have found that the best way to organize the imports and exports in the header file of the dll, is something of the following type:
#ifndef MY_DLL_EXPORTS
#define MY_DLL_EXPORT __declspec(dllexport)
#else
#define MY_DLL_EXPORT __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C"
{
#endif
MY_DLL_EXPORT BOOL my_function(uint32_t x);
#ifdef __cplusplus
}
#endif
My question is, where are the __cplusplus and MY_DLL_EXPORTS supposed to be defined ?
I have not done this before and I can't seem to find a place in the code for it. I read something about putting these definitions in the
Project Properties -> Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions
Do I put them in the DLL's project properties ? and if i do, on using this DLL, will they always be defined so the if statement will always go to the dllimport ?
Also, is __cplusplus already defined or must I define it ?
__cplusplus is defined for you by a C++ compiler, but NOT by a C compiler. This is how you can determine if your code is being compiled by a C or C++ compiler. That's why this is used to guard the extern "C" construct. A C compiler would just omit it (since it emits C linkage already).
The other constants can be either defined on the compiler's command line (eg. in the menu you listed), or in the code somewhere:
#define MY_DLL_EXPORTS
Best place to define COMPILING_DLL 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.

Create a DLL in C and link it from a C++ project

As per title, I'm trying to build a DLL using C and link it from a C++ project. I read and followed different tutorials on internet but everytime there is something missing and I don't understand what.
Here's what I did, step by step:
I created a new Win32 project, named testlib, then, from the wizard, I chose "DLL" and "Empty project".
Added a header:
//testlib.h
#include <stdio.h>
__declspec(dllexport) void hello();
Added a source; since I want it to be a C source I read I should simplly rename the .cpp file in .c, so
//testlib.c
#include "testlib.h"
void hello() {
printf("DLL hello() called\n");
}
Build succeded.
Now I would like to use my useful dll in another project.
Then: new project (testlibUse). This time I selected "Empty project".
No need to add an header, just created a cpp source
//main.cpp
#include <testlib.h>
int main() {
hello();
}
Then:
I added the path to the folder where is testlib.dll in Properties->VC++ directories->Executable directories
I added the path to the folder where is testlib.h in Properties->VC++ directories->Include directories
I added the path to testlib.lib (included extension) in Properties->Linker->Input->Additional dependencies
I tried to build but I got a linker error:
LINK : C:\path\testlibUse\Debug\testlibUse.exe not found or not built by the last incremental link; performing full link
main.obj : error LNK2019: unresolved external symbol "void __cdecl hello(void)" (?hello##YAXXZ) referenced in function _main
C:\path\testlibUse\Debug\testlibUse.exe : fatal error LNK1120: 1 unresolved externals
If I go back to testlib, rename back testlib.c in testlib.cpp and rebuild the dll, then I am able to build testlibUse but I get a "dll not found" error at runtime.
I tried also to change the configurations of both projects in "Release" (changing the path where needed), but nothing changed.
Sorry for the long post but I think it was necessary to write down exactly what I did.
Any suggestions?
Besides, are there any configuration parameters I need to change if I want to use my dll in a Qt project?
You have several problems:
The header file should mark the functions as exported when being compiled in the DLL but imported when being compiled by a library user.
The header file should wrap the function declarations in an extern "C" block when being compiled as C++ to ensure that the names do not get mangled
The DLL is not on your executable's library search path, so it can't be found at runtime.
To fix (1) and (2), rewrite your header like this:
#ifdef __cplusplus
extern "C" {
#endif
// Assume this symbol is only defined by your DLL project, so we can either
// export or import the symbols as appropriate
#if COMPILING_MY_TEST_DLL
#define TESTLIB_EXPORT __declspec(dllexport)
#else
#define TESTLIB_EXPORT __declspec(dllimport)
#endif
TESTLIB_EXPORT void hello();
// ... more function declarations, marked with TESTLIB_EXPORT
#ifdef __cplusplus
}
#endif
To fix (3), copy the DLL into the same folder as your executable file. The "executable directories" setting you're setting doesn't affect DLL searching -- see MSDN for a detailed description of how DLLs are searched for. The best solution for you is to copy your DLL into the directory where your executable file lives. You can either do this manually, or add a post-build step to your project that does this for you.
You should extern "C" the include:
extern "C" {
#include <testlib.h>
}
It looks as if you need to make sure the compiler not mangle the symbol name in the cpp build. You should be able to add an extern "C" to the definition in testlib.h:
#ifdef __cplusplus
extern "C"
#endif
__declspec(dllexport) void hello();
Here's a method for your C header file that could be included by C++. Make sure to set TESTLIB_EXPORTS only in your DLL preprocessor settings. In projects that include this header to use the DLL, the header will declare the functions as imports instead of exports.
The __cplusplus guard will tell the compiler to import your functions using C name decoration instead of C++ name decoration.
#include <stdio.h>
#ifdef TESTLIB_EXPORTS
#define TESTLIB_API __declspec(dllexport)
#else
#define TESTLIB_API __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C" {
#endif
TESTLIB_API void hello();
/* other prototypes here */
#ifdef __cplusplus
}
#endif

Exporting static data in a DLL

I have a DLL which contains a class with static members. I use __declspec(dllexport) in order to make use of this class's methods. But when I link it to another project and try to compile it, I get "unresolved external symbol" errors for the static data.
e.g.
In DLL, Test.h
class __declspec(dllexport) Test{
protected:
static int d;
public:
static void m(){int x = a;}
}
In DLL, Test.cpp
#include "Test.h"
int Test::d;
In the application which uses Test, I call m().
I also tried using __declspec(dllexport) for each method separately but I still get the same link errors for the static members.
If I check the DLL (the .lib) using dumpbin, I could see that the symbols have been exported.
For instance, the app gives the following error at link time:
1>Main.obj : error LNK2001: unresolved external symbol "protected: static int CalcEngine::i_MatrixRow" (?i_MatrixRow#CalcEngine##1HA)
But the dumpbin of the .lib contains:
Version : 0
Machine : 14C (x86)
TimeDateStamp: 4BA3611A Fri Mar 19 17:03:46 2010
SizeOfData : 0000002C
DLL name : CalcEngine.dll
Symbol name : ?i_MatrixRow#CalcEngine##1HA (protected: static int CalcEngine::i_MatrixRow)
Type : data
Name type : name
Hint : 31
Name : ?i_MatrixRow#CalcEngine##1HA
I can't figure out how to solve this. What am I doing wrong? How can I get over these errors?
P.S. The code was originally developed for Linux and the .so/binary combination works without a problem
EDIT: In the given case, the static variables are not directly referred by the application but the method is inlined since it's in the header. I was able to resolve the link errors by moving the methods to the .cpp file.
In this thread at cprogramming.com it is suggested that a static variable is local to the dll and not exported.
Summary of discussion below
The static member is not accessed directly by code in the calling application, only through member functions of the class in the dll. However there are several inline functions accessing the static member. Those functions will be inline expanded into the calling applications code makeing the calling application access the static member directly. That will violate the finding referenced above that static variables are local to the dll and cannot be referenced from the calling application.
My guess is that the class which uses the DLL should see dllimport instead of dllexport in the header. If I am correct, this can typically be achieved by defining a preprocessor macro like:
#ifdef EXPORTING
#define DECLSPEC __declspec(dllexport)
#else
#define DECLSPEC __declspec(dllimport)
#endif
and then use it in the class declaration:
class DECLSPEC Test{
protected:
static int d;
public:
static void m(){}
}
So that in Test.cpp (or wherever it makes sense in your DLL project) you can specify that you are exporting so that it will be exported with dllexport:
#define EXPORTING
#include "Test.h"
int Test::d;
while the other project, which does not define EXPORTING, will see dllimport.
Does it make sense?
With Windows DLLs, there is a specific distinction between __declspec(dllexport) vs __declspec(dllimport), dllexport should be used when compiling the DLL, dllimport should be used when compiling programs that link to this DLL. The standard way of defining this would be with a macro.
The following is the visual studio example:
// The following ifdef block is the standard way of creating macros which make exporting
// from a DLL simpler. All files within this DLL are compiled with the DLL_EXPORTS
// symbol defined on the command line. this symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see
// DLL_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef DLL_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
Despite the summary, one can export static data from a DLL. However, there is a problem that comes up with the standard macros supplied by the Visual Studio DLL project:
#ifdef DLL_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
If you have multiple DLLs calling code from one DLL to another or between EXE and DLL, there is going to be a problem with this macro because every header is going to be exporting. One needs unique macros that handle __declspec. The safest way to handle this problem is as follows:
#ifdef MYPROJECT_DLL_EXPORTS
#define MYPROJECT_API __declspec(dllexport)
#else
#define MYPROJECT_API __declspec(dllimport)
#endif
Then only in the compiler preprocessor options for the DLL project define MYPROJECT_API.
In your header code:
struct/class MYPROJECT_API myclass {
static int counter;
};
And in a .cpp file:
int myclass::counter = 0;
Although it's kinda an old post. I would like to add that (for some reason) to resolve this problem I needed to add the (Windows) __declspec(dllexport)/(import) also INSIDE the .cpp file so the outside code could access it.
// From another answer to ilustrate this =)
#ifdef DLL_EXPORTS
#define DLL_API __declspec(dllexport)
#else
#define DLL_API __declspec(dllimport)
#endif
some_app.h
class DLL_API SomeApp
{
static void MyFunc();
}
some_app.cpp
DLL_API void SomeApp::MyFunc()
{
// Some impl of my app.
}
In my case that was specially required because my functions are templated. Maybe this could work for someone else too.
use inline for c++17
static inline std::string static_variable