C++ : inline functions with dllimport/dllexport?

2019-01-19 08:09发布

问题:

I create a DLL (say CORE.DLL) ,I have classes/functions declared as follows:

#ifdef RINZOCORE_SHARED
#define RINZO_LIB __declspec(dllexport)
#else
#define RINZO_LIB __declspec(dllimport)
#endif

I have defined many inline functions with "dllexport" macro ,

class RINZO_LIB CVector
{

public:
    CVector();//!< default constructor
    ..
    real& x();//!< accessor for the x component (can be used as l-value too)
    real& y();//!< accessor for the y component (can be used as l-value too)
    real& z();//!< accessor for the z component (can be used as l-value too)
    CVector& operator=(const CVector& other);//!< the assignment
    CVector& operator+=(const CVector& other);//!< the sum & assign
    CVector& operator-=(const CVector& other);//!< the subtract & assign
    CVector& operator*=(const real& fact);//!< the short multiply by a scalar factor & assign
    CVector& operator/=(const real& fact);//!< the short divide by a scalar factor & assign
..
}

RINZO_LIB inline CVector& CVector::operator=(const CVector& other)
{
    //check for 'a=a' case
    if (this==&other) return *this;
    vec[0]=other.vec[0];
    vec[1]=other.vec[1];
    vec[2]=other.vec[2];
    return *this;
}

RINZO_LIB inline CVector& CVector::operator+=(const CVector& other)
{
    vec[0]+=other.vec[0];
    vec[1]+=other.vec[1];
    vec[2]+=other.vec[2];
    return *this;
}

RINZO_LIB inline CVector& CVector::operator-=(const CVector& other)
{
    vec[0]-=other.vec[0];
    vec[1]-=other.vec[1];
    vec[2]-=other.vec[2];
    return *this;
}

RINZO_LIB inline CVector& CVector::operator*=(const real& fact)
{
    vec[0]*=fact;
    vec[1]*=fact;
    vec[2]*=fact;
    return *this;
}

RINZO_LIB inline CVector& CVector::operator/=(const real& fact)
{
    assert(fabs(fact) >= epsilon);
    vec[0]/=fact;
    vec[1]/=fact;
    vec[2]/=fact;
    return *this;
}

but when I use this DLL (import) compile another DLL (say PluginA.DLL) it gives following compile errors :

Info: resolving std::cout  by linking to __imp___ZSt4cout (auto-import)
CMakeFiles\ContourViewer.dir/objects.a(RzStateDoAnimation.cpp.obj):C:/svn/osaka3d/trunk/osaka3d/rinzo-platform/src/dlplugins/contourviewer/statemachine/RzStateDoAnimation.cpp:79: undefined reference to `operator!=(quaternion const&, quaternion const&)'
Info: resolving vtable for __cxxabiv1::__vmi_class_type_info by linking to __imp___ZTVN10__cxxabiv121__vmi_class_type_infoE (auto-import)
CMakeFiles\ContourViewer.dir/objects.a(RzStateDoAnimation.cpp.obj):C:/svn/osaka3d/trunk/osaka3d/rinzo-platform/src/dlplugins/contourviewer/statemachine/RzStateDoAnimation.cpp:146: undefined reference to `operator==(quaternion const&, quaternion const&)'
CMakeFiles\ContourViewer.dir/objects.a(BallController.cpp.obj):C:/svn/osaka3d/trunk/osaka3d/rinzo-platform/src/dlplugins/contourviewer/trackball/BallController.cpp:159: undefined reference to `operator*(CVector const&, CVector const&)'
CMakeFiles\ContourViewer.dir/objects.a(BallController.cpp.obj):C:/svn/osaka3d/trunk/osaka3d/rinzo-platform/src/dlplugins/contourviewer/trackball/BallController.cpp:165: undefined reference to `operator^(CVector const&, CVector const&)'
CMakeFiles\ContourViewer.dir/objects.a(BallController.cpp.obj):C:/svn/osaka3d/trunk/osaka3d/rinzo-platform/src/dlplugins/contourviewer/trackball/BallController.cpp:168: undefined reference to `operator-(CVector const&, CVector const&)'
CMakeFiles\ContourViewer.dir/objects.a(BallController.cpp.obj):C:/svn/osaka3d/trunk/osaka3d/rinzo-platform/src/dlplugins/contourviewer/trackball/BallController.cpp:292: undefined reference to `operator*(CVector const&, CVector const&)'
CMakeFiles\ContourViewer.dir/objects.a(BallController.cpp.obj):C:/svn/osaka3d/trunk/osaka3d/rinzo-platform/src/dlplugins/contourviewer/trackball/BallController.cpp:292: undefined reference to `operator*(CVector const&, float const&)'
CMakeFiles\ContourViewer.dir/objects.a(BallController.cpp.obj):C:/svn/osaka3d/trunk/osaka3d/rinzo-platform/src/dlplugins/contourviewer/trackball/BallController.cpp:292: undefined reference to `operator-(CVector const&, CVector const&)'

Any tips on how to use inline functions with dllexport/dllimport ?

回答1:

Inline and dllexport/dllimport don't mix.

You either

  1. inline your functions, and have them compiled separately for each source file that uses them; or
  2. store them in a library, that is, have them compiled just once (export them), and link the rest of the program against that single compiled version (import them).

There's little sense in trying to do both at the same time.

Remove either inline or RINZO_LIB from each function definition that have both, and you should be fine.

Edit To eliminate any misunderstanding: it is possible to export and import inline functions, and in fact simply placing a dllexport/dllimport on a declaration should just work.



回答2:

I'd like to provide some extra information since this is a very tricky issue and there's a good bit of incorrect information floating around about inline with export/import.

First: inline functions can be used with dllimport/dllexport without issue. The meaning is perfectly sensible: you provide an inline definition that can be used internally in your DLL or externally by client code (which can inline it), yet can still be accessed as though it were a standard exported function. In other words, you can still get a pointer to the implementation of the function that resides in the DLL if you need it. Use cases include, for example, accessing the function through an FFI, being able to access memory allocation/free routines that should be inlined within modules but need to use the DLL's impl for memory that crosses the DLL boundary, etc.

Please see https://blogs.msdn.microsoft.com/oldnewthing/20140109-00/?p=2123 for a thorough treatment and clarification of what it means to be inline and exported / imported at the same time.

Next, in your specific case, I see nothing immediately wrong with what you're trying to do. You want to provide fast, inlined vector math for yourself and clients, while still being able to access that function as though it were a standard export. If that last bit isn't true (i.e., you don't ever explicitly need a pointer to the DLL's implementation of the function), then the comments/answer are correct: remove the export/import and make it part of the .hpp. Use import/export + inline only when you know that you will still require access to the DLL's exported version of the function. Again, this is a perfectly-reasonable thing, however, it's not usually what's required -- so make sure you do indeed require it.

All that being said, it looks like your DLL is not exporting the symbols.

Double-check to make sure that you're defining RINZOCORE_SHARED when you build the library. Check the DLL's symbols and see if those functions have been exported (if not, and you're positive that you've defined RINZOCORE_SHARED, then I'm really quite stumped).

Check to make sure you're including the header that has the function definitions from wherever you're calling this. Check to make sure that RINZOCORE_SHARED is NOT defined in your plugin build. It looks like your plugin is trying to find an exported version of the functions, which would seem to imply that it doesn't have the definitions of those inline functions.

I usually use this only with C-linkage functions, so I'm honestly not quite sure what all could be going wrong in terms of the C++ ABI.