inconsistent dll linkage & definition of dllimport static data member not allowed - visual-c++

Assuming I have these two files:
Header.h
class DLL ExportClass{
public:
ExportClass();
static int test;
};
Source.cpp
#ifdef EXPORT
#define DLL __declspec(dllexport)
#else
#define DLL __declspec(dllimport)
#endif
#include "Header.h"
int ExportClass::test = 0;
ExportClass::ExportClass(){
}
And I won't define EXPORT (to import a already exported class with a static member), why do I get these warnings:
1>source.cpp(11): warning C4273: 'test' : inconsistent dll linkage
1> header.h(4) : see previous definition of 'public: static int ExportClass::test'
1>source.cpp(13): warning C4273: 'ExportClass::ExportClass' : inconsistent dll linkage
1> header.h(3) : see previous definition of '{ctor}'
And this error:
1>source.cpp(11): error C2491: 'ExportClass::test' : definition of dllimport static data member not allowed
If I define EXPORT it works. I kind of understand the warnings, but I thought, that the static variable and the ctor could be ignored by the compiler, because the whole class is declared as __declspec(dllimport) anyway. I want to use the same codebase for the __declspec(dllexport) and __declspec(dllimport) - but it seems the compiler stll tries to define these symbols that are marked as __declspec(dllexport) in their declaration. What is the common practice to solve this problem?

You are expecting the compiler to ignore a very serious mishap. It encountered the __declspec(dllimport) attribute on the class declaration, that quite unequivocally states that the class implementation is present in different module that's going to bound at runtime. But then it encountered the definition as well, completely unexpected since the attribute contract says that it is compiled in an entirely different project.
The C4273 warning is generated to remind you that it is very unclear what function is actually going to execute at runtime. There are two, one that is busy compiling, another in the DLL. Which one will actually execute is a wild guess. C4273 is a level 1 warning, the kind that fit the "this is almost surely wrong" category. It is not entirely impossible to work okay since there's some expectation that the functions have at least the same code. The odds that will not cause trouble are however not great, it could only work if the function doesn't have any side effects that change the internal DLL state. Very hard to diagnose bug when it does btw.
Then it encountered the exported variable. Same case, there are two of them. This is where the compiler programmer put his foot down, having code randomly use one or the other is no longer something that can be ignored. That just cannot ever work, the variables cannot have the same value. So C2491 is a hard error.
No idea how you got in this pickle, clearly the road you're trying to travel will make you fall off a steep cliff.

The only way I can reproduce your problem is to do the following:
Create a Win32 DLL project, call it Project1
Add the source code as you described
Compile the DLL and LIB
Change the project properties to remove EXPORT from the preprocessor definitions
Attempt to compile again (then I see your errors/warnings)
If, instead of steps 4 and 5, I do the following, I do not see an error:
Create a Win32 console application, call it Project2
Add source code as follows:
#include "Project1.h"
#pragma comment(lib, "Project1.lib")
int _tmain(int argc, _TCHAR* argv[])
{
ExportClass pClass;
return 0;
}
I suspect you see those errors because you are doing everything from the same DLL project and it is overwriting the LIB that it previously created and then attempting to import it.
If I am correct in guessing what you did, can you try using your DLL/LIB from another project and see what happens?

Although it is an old thread, it will be probably read by others. Therefore, if you want to make this code cross-compilable, I would usually define a header "export.h" like:
export.h
#pragram once
#if ! defined(DLL_API)
# if defined(_WIN32) // for windows builds
# if defined(myDLL_EXPORTS)
# define DLL_API __declspec(dllexport)
# else
# define DLL_API __declspec(dllimport)
# endif
# else // for linux builds
# define DLL_API
# endif
#endif
and include it in all the classes (.h) you want to export from your dll. You will also have to define the variable myDLL_EXPORTS as a parameter of the compiler for the dll project.
The way it works is very simple, when you are compiling your dynamic library (dll/so), because the variable myDLL_EXPORTS is defined, the compiler will replace DLL_API with __declspec(dllexport) so that your class can be consumed by the user of your dll. Conversely, when you are including the header file where you want to use your class at, because the variable myDLL_EXPORTS is not defined in the consumer project (it is defined only in the DLL project), the compiler will replace myDLL_EXPORT with __declspec(dllimport), so it knows that your class symbols are defined somewhere else (in this case, defined in your dll/so).
Finally, as __declspec(...) is a Windows-only thing, for linux we replace DLL_API with nothing.

Related

Linking static native library to managed C++ project pulls unused (and unexpected) dependencies in

Synopsis:
Managed (/clr) C++ project (.dll) statically links native C++ library (which is compiled with /MD). Static library is big and references a lot of other libraries, but functionality used by managed C++ code is trivial and shouldn't pull in any additional dependencies.
Problems:
linking fails with LNK2001 and LNK2019 mentioning symbols that code definitely does not depend on
even if I add required dependencies, switching toolset (e.g. migrating from VS2017 to VS2019) causes errors to come back (this time mentioning other dependencies)
What happens:
Apparently, /clr switch causes compiler to treat inlined functions differently -- they are no longer get embedded into .obj files (as "weak symbols"), instead they get referenced in the table of imports. This means linker has to find things like:
"public: virtual char const * __cdecl std::exception::what(void)const " (?what#exception#std##UEBAPEBDXZ)
... which it does and (since CRT libraries are DEFAULTLIB and therefore are used last) typically it finds it in other library (namely, in aforementioned static native lib). So, it finds first .obj file in static lib that contains std::exception::what() and pulls it in -- meaning we now depend on everything said .obj depends. This explains problem #1 (bogus linker errors).
Now, if you compile your static lib with another toolset -- obj files can be stored in different order, causing problem #2.
To reproduce the issue you can use this code (make sure managed project links static lib):
//--------------------
// statlib.cpp
//
#include <exception>
void this_is_a_trap() { throw std::exception(); }
extern int bar();
int foo() { return bar(); }
//--------------------
// clrdll.cpp (managed code)
//
#include <exception>
__declspec(dllexport) void oops()
{
throw std::exception();
}
If you link with /VERBOSE flag you'll see smth like:
1> Searching C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\um\x64\oleaut32.lib:
1> Searching C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\um\x64\uuid.lib:
1> Searching C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\um\x64\odbc32.lib:
1> Searching C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\um\x64\odbccp32.lib:
1> Searching C:\tst\x64\Release\statlib.lib:
1> Found "public: virtual char const * __cdecl std::exception::what(void)const " (?what#exception#std##UEBAPEBDXZ)
1> Referenced in clrdll.obj
1> Loaded statlib.lib(statlib.obj) <-- Now we depend on `bar()`
Question
What is the best way to deal with this?
Notes:
adding msvcrt.lib to linker inputs (before other static libs) helps, but not always -- certain symbols (such as std::bad_weak_ptr::what() aren't present in msvcrt.lib)
this problem is the root cause for this SO post
In mixed (/clr and native) code std::exception::what() (and other similar symbols) do get inlined, but these definitions are managed (not native). Which normally is not an issue, but native code refers to native definition via std::exception's vtable. Normally, such reference (once it fails to resolve) gets redirected to managed definition (which is generated, as stated above), but in this case -- native definition is found in another object (random object from native static library) before "redirection" kicks in, causing that object to be referenced.
See details here. MS is figuring out a best way to deal with this.

How do decorated names get into import libraries when I only provide the undecorated name?

I'm working in Visual C++, VS2015 Community. I've written this tiny little DLL:
#include "stdafx.h"
int showMsgBox(wchar_t* caption, wchar_t* message)
{
MessageBox(NULL, message, caption, 0);
return 0;
}
And this tiny little client:
#include "stdafx.h"
__declspec(dllimport) int showMsgBox(wchar_t* caption, wchar_t* message);
int main()
{
showMsgBox(L"SimpleDLLClient", L"Hello DLL World!");
return 0;
}
To export the showMsgBox function, I've created this module definition file:
LIBRARY SimpleDLL
EXPORTS
showMsgBox
When I link my client, I pass it the import library that was created when I linked my DLL. Everything compiles and links fine.
And that puzzles me.
According to MSDN, "Because the Visual C++ compiler uses name decoration for C++ functions, you must either use the decorated name as the entryname or internalname, or define the exported functions by using extern "C" in the source code."
But I'm not exporting a decorated name, am I?
If, instead of using a module definition file, I were to prefix the function with the __declspec(dllexport) extended attribute, I wouldn't be surprised (as this ought to have whatever name decoration the compiler applies match the same decoration applied by the compiler to the client).
Likewise, if I prefixed the function with 'extern "C"' in both the DLL and client code, that should also work (and it does: I tested it), because, again, the symbols should match.
But, I would have expected an undecorated export in the module definition file to fail to resolve the client's reference to the same undecorated name, when neither the DLL nor client code uses 'extern "C",' which seems also to be what MSDN says I should expect. Yet, exporting the undecorated name via the module definition file does work, even when I do not use 'extern "C"' anywhere.
Can anyone tell me why this works?
UPDATE
Looking into the files created by the linker, I see that putting the undecorated name into the module definition file apparently results in the decorated name being included in the import library. When I use dumpbin /exports on that file, here's what I get:
File Type: LIBRARY
Exports
ordinal name
?showMsgBox##YAHPEA_W0#Z (int __cdecl showMsgBox(wchar_t *,wchar_t *))
Now, somewhat amazingly (to me, anyway), if I explicitly alias the decorated name, like this:
LIBRARY SimpleDLL
EXPORTS
showMsgBox=?showMsgBox##YAHPEA_W0#Z
dumpbin tells me that this is what shows up in the import library:
File Type: LIBRARY
Exports
ordinal name
showMsgBox
Using that as input to the linker when I build the client works fine too, provided that I use 'extern "C"' when I declare my imported function:
extern "C" int showMsgBox(wchar_t* caption, wchar_t* message);
That makes sense, since the symbol the linker is now looking for is the undecorated "showMsgBox," and I have aliased that symbol to the decorated name created when I compiled my DLL.
Soooo...
What it looks like to me is that pages and pages of MSDN documentation that all say you must use decorated names in module definitions files are mistaken. Rather, it appears that if you use the undecorated name in your module definition file, it is the decorated name that is actually incorporated into your import library, which will resolve the reference to the matching decorated name constructed when you compile your client code. That, of course, is what I would prefer, rather than having to extract the decorated names and use those in my module definition files. It just doesn't match what the MSDN pages repeatedly say.
I like to think I'm a bright boy, but it's pretty arrogant of anyone to suggest that Microsoft doesn't know how its own products work.
What am I missing here?
UPDATE 2
With the DLL and client both using decorated names (that is, no use of 'extern "C"' anywhere), everything builds fine with the undecorated name in the module defintion file, like I said. But, interestingly, with no changes at all to the source code, things build equally well if I do use the decorated name in the module definition file:
LIBRARY SimpleDLL
EXPORTS
?showMsgBox##YAHPEA_W0#Z
At the binary level, the import library this creates is nearly identical to the library created when I use the undecorated name in the module definition file. The only differences appear to be time-stamps, with the exception of one byte near the end. Still trying to make sense of that one, but it appears ever more certain that, somehow, the linker is exporting the decorated name, even when the module definition file refers solely to the undecorated name.

error LNK2001: unresolved external symbol "class"

I've a header file having a "extern class definition" in it. Both these header file and class are in different C++ assembly. Now there is a class in different C++ assembly which is trying to access this "extern" class functions but there are all sorts of linker errors such as LNK2001: unresolved external symbol " class LMSystem LM"(?LM##3VLMSystem##A),LNK2019 etc.
Following is the code snippet:for CPP file
/This header file contains the extern reference/
#include "../lm/lm.h"
BOOL FDInitHW (void)
{
char pFileName[TALLY_MAX_PATH];
ASSERT(0 != g_pFdbPath);
strcpy(pFileName, g_pFdbPath);
strcat(pFileName, FILENAME_HW_KB);
return SUCCESS == LM.LMIOListReadSelective(pFileName,
LMIO_READREPLACE, FDGetSelectListPtrArray());
}
Contents of Lm.h
class LMSystem
{
public:
LMSystem();
~LMSystem();
// getting a specific list
short LMIOListReadSelective(char *fname, unsigned short readflags, LIST_SELECTOR* select_array[]);
};
extern LMSystem LM; // the library global LMSytem
So can you help me in resolving this linker error?
I think it has to do something with project properties as the old assembly developed in VC++ 6.0 is working fine and even in this Win32 C++ assembly,which I'm creating in VS2012,I'm able to go to definition of the LMSystem class using F12 or Intellisense but ideally it should point me to the variable in LM.H header file.
I've seen many post telling how to use functions of one type defined in different C++.dll in another C++ .dll. There are many project level settings changes but it doesn't always give me the correct results. So if anybody can give me a solution to this issue then it will be great help.
Instance of LM needs to be created somewhere and your linker must be able to find it. For example add LMSystem LM; to one of your source (.cpp) files

MSVC: __declspec(dllexport) does not symbols

I have a small issue when it comes to writing a DLL in MSVC (the 2010 version in particular).
My program consists of the main part and a DLL. The DLL contains a function that is
__declspec(dllexport) int test_function(void) {
return 42;
}
The file is compiled using a DLL project (not using pre-compiled headers, I have chosen a empty DLL project). Now, when I want to list the exported symbols using the dumpbin tool, the test_function is not listed under exports. Is there a specific setting that forces __declspec(dllexport) to actually export symbols?
Any help is welcome. Thank you!
That should do it. If this is the whole code, check the following:
1) You are actually checking the correct dll. Look at the timestamp. Double-check the location and the name.
2) You are compiling the specified cpp (I take it your definition is in the cpp file). Just because the file is in the directory doesn't mean it gets compiled, make sure it is added to the project.
3) Make sure your function is not excluded from the compilation unit by preprocessor directives.
Also look for other symbols and try to see what differences are there between the symbols that get exported and your function.
If this fails, you should move __declspec(dllexport) to your .h file and the definition (without __declspec(dllexport) ) to your .cpp. It might not be exported because the compiler might try to optimize it out by inlining it.

Building Visual C++ app that doesn't use CRT functions still references some

This is part of a series of at least two closely related, but distinct questions. I hope I'm doing the right thing by asking them separately.
I'm trying to get my Visual C++ 2008 app to work without the C Runtime Library. It's a Win32 GUI app without MFC or other fancy stuff, just plain Windows API.
So I set Project Properties -> Configuration -> C/C++ -> Advanced -> Omit Default Library Names to Yes (compiler flag /Zl) and rebuilt. Let's pretend I have written a suitable entry point function, which is the subject of my other question.
I get two linker errors; they are probably related. The linker complains about unresolved external symbols __fltused and _memcpy in foobar.obj. Needless to say, I use neither explicitly in my program, but I do use memcpy somewhere in foobar.cpp. (I would have used CopyMemory but that turns out to be #defined to be identical to memcpy...)
(I thought I could get rid of the memcpy problem by using a compiler intrinsic, like #pragma intrinsic(memcpy), but this makes no difference.)
If I look at the preprocessor output (adding /P to the compiler command line), I see no references to either __fltused or _memcpy in foobar.i.
So, my question is: Where do these linker errors come from, and how do I resolve them?
__fltused implies you are using or have at least declared some floats or doubles. The compiler injects this 'useless' symbol to cause a floating support .obj to get loaded from the crt. You can get around this by simply declaring a symbol with the name
#ifdef __cplusplus
extern "C" {
#endif
int _fltused=0; // it should be a single underscore since the double one is the mangled name
#ifdef __cplusplus
}
#endif
WRT _memcpy - memcpy is a __cdecl function, and all cdecl functions get an automatic _ as part of their decoration. so, when you say "__cdecl memcpy" - the compiler & linker go looking for a symbol called '_memcpy'. Intrinsic functions - even explicitly requested - can still be imported if the build settings have debug settings that contra-indicate intrinsics. So you are going to need to implement your own memcpy and related functions at some point anyway.
I recommend setting the "generate assembly listing" (or some such) compiler option for foobar.cpp once, and then inspecting the assembler code. This should really tell you where these symbols are used.

Resources