Importing inline functions in MinGW

2019-02-18 08:56发布

问题:

I'm using a shared library that defines inline functions in its header.

Here is a reduced test case, as seen by the compilation unit linking to the library (for the version seen by the library, just replace dllimport by dllexport).

class __declspec(dllimport) MyClass {
public:
    int myFunc2();
    int myFunc1();
};

inline int MyClass::myFunc2(void) {
    return myFunc1();
}

inline int MyClass::myFunc1(void) {
    return 0;
}

Compiling this gives the warning:

warning: 'int MyClass::myFunc1()' redeclared without dllimport attribute after being referenced with dll linkage [enabled by default]

Please note that the order in which the functions are defined is important, as putting the definition of myFunc1 before the definition of myFunc2 results in no warnings.

Note also that this code compiles without warnings under Visual C++. These warnings are specific at least to MinGW, maybe to GCC in general. Edit: it came to my mind that I may have to verify if the warning is not inhibited by one of the flags set by the project.

My questions are then:

  • Why this behavior ?
  • Declaring myFunc1 as inline inside the class declaration fixes the problem. Why is that ? It's also against the recommended way of doing things.
  • Is there another (better ?) way to fix this problem ?

回答1:

The problem comes about because of some magic in the way that dllimport works which normally means you only need it on the first declaration.

Basically, when you declare a function as dllimport and then later redeclare the function with an identical declaration except for the dllimport, the second declaration implicitly gets the dllimport. If the redeclaration is NOT identical, it doesn't get the implicit dllimport.

So what happens here is you first declare the function as dllimport/non-inline, and then declare it as non-dllimport/inline. Adding an inline to the first declaration fixes the problem, as the second then becomes implicitly dllimport. Alternately, adding a __declspec(dllimport) to the second declaration should fix the problem.

Note that reordering the definitions gets rid of the warning, since the warning is about using it before redeclaring it. With a reorder, you're no longer using it before the redeclaration, so you get no warning, though it will be using the non-dllimport version (ie, it will never use the version of the function from the dll).

Note also, using inline dllimport is dangerous. Any program built against the dll might use the inline function in some places and the non-inline function (from the dll) in others. Even if the two functions are identical NOW, a future version of the dll might change and have a different implementation. At which point the old program might start misbehaving if run with the new version of the dll.



回答2:

Further information to Chris Dodd's answer:

I tested with MSVC 2017 and MinGW-w64 7.2.0; in both cases, with optimization enabled, the call of myFunc1() from myFunc2 resolved to the inline version, despite the warning. Even if the body of myFunc1 were moved to below main().

So my tentative conclusion is that it is safe to ignore this warning.


In the interest of a clean compile, the only method that seems to work in MinGW-w64 is to mark the function declaration within the class definition as inline. The compiler does not allow applying __declspec(dllimport) to the out-of-class function definition.

I have been unable to determine if there is a warning flag for g++ which will specifically disable this warning.