سؤال

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:

  1. Create a Win32 DLL project, call it Project1
  2. Add the source code as you described
  3. Compile the DLL and LIB
  4. Change the project properties to remove EXPORT from the preprocessor definitions
  5. 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.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top