How to avoid error "definition is marked dllimport"

Environment: Windows 10 with CMake 3.19.4 + MinGW 7.3.0

When building libraries with CMake + MinGW that contain tests or examples (.exe files) that consume the compiled library, then the compilation of these executables causes errors like this:

error: function 'ur_rtde::RTDE::RobotCommand::RobotCommand()' definition is marked dllimport

This happens for example for this library: https://gitlab.com/sdurobotics/ur_rtde

During the CMake configuration step, an export file is generated by CMake: rtde_export.h

#ifndef RTDE_EXPORT_H
#define RTDE_EXPORT_H

#ifdef RTDE_STATIC_DEFINE
#  define RTDE_EXPORT
#  define RTDE_NO_EXPORT
#else
#  ifndef RTDE_EXPORT
#    ifdef rtde_EXPORTS
        /* We are building this library */
#      define RTDE_EXPORT __declspec(dllexport)
#    else
        /* We are using this library */
#      define RTDE_EXPORT __declspec(dllimport)
#    endif
#  endif

#  ifndef RTDE_NO_EXPORT
#    define RTDE_NO_EXPORT 
#  endif
#endif

#ifndef RTDE_DEPRECATED
#  define RTDE_DEPRECATED __attribute__ ((__deprecated__))
#endif

#ifndef RTDE_DEPRECATED_EXPORT
#  define RTDE_DEPRECATED_EXPORT RTDE_EXPORT RTDE_DEPRECATED
#endif

#ifndef RTDE_DEPRECATED_NO_EXPORT
#  define RTDE_DEPRECATED_NO_EXPORT RTDE_NO_EXPORT RTDE_DEPRECATED
#endif

    #if 0 /* DEFINE_NO_DEPRECATED */
    #  ifndef RTDE_NO_DEPRECATED
    #    define RTDE_NO_DEPRECATED
    #  endif
    #endif

    #endif /* RTDE_EXPORT_H */

This file generates the dllexport / dllimport keywords. While the compilation does not produce any errors when compiling with MSVC compiler, it fails when compiling with MinGW compiler. Normally the dllexport / dllimport definitions are not required for MinGW because it can link directly to DLLs and an import library is not required. I can fix the build error by manually editing the generated export file and defining an empty export macro like in line 4 in the code below.

#ifndef RTDE_EXPORT_H
#define RTDE_EXPORT_H

#define RTDE_EXPORT // empty export macro to fix compilation error

#ifdef RTDE_STATIC_DEFINE
#  define RTDE_EXPORT
#  define RTDE_NO_EXPORT
#else
#  ifndef RTDE_EXPORT
#    ifdef rtde_EXPORTS

This change fixes the build error and enables the complete build of the library but I don’t think that this is the right way to fix this.

So my question is, how should I properly fix the build issue when building a project witg CMake + MinGW ? Is there some setting in CMake that I can change during configuration to fix this and why does CMake generate dllexport / dllimport statements for MinGW if this is not required for MinGW?

Thank you for any help,

Uwe

Do you have the associated CMake code for the rtde target?

Do you mean the CMakeLists.txt file? This is the link to the file:

https://gitlab.com/sdurobotics/ur_rtde/-/blob/master/CMakeLists.txt

Hmm. This seems odd. VTK hasn’t had reports of anything wrong with mingw (though it’s not a tested compiler, some reports and bug fixes come in occasionally). This feels worthy of a new issue though.

@brad.king Thoughts?

rtde_EXPORTS should be defined when compiling the sources that provide the definitions. That way any RTDE_EXPORT markup on them becomes dllexport. You need to track down what goes wrong with that. It means either the definition is missing where it should be, or that RTDE_EXPORT is added on an item it shouldn’t be.

Thank you Brad - I will try to do this. What could be the reason that it works with MSVC and fails with MinGW? What is the right “workaround” to enforce the generation of an empty RTDE_EXPORT macro via CMake configuration because dllexport and dllimport is not required for MinGW. So the right solution for MinGW would be to generate an empty export macro. How can i enforce this in CMake?

Thank you,

Uwe

MS tooling is a bit more tolerant of incorrect markup. Even on MinGW one is still better off with explicit import/export markup. It limits the number of symbols exported from the .dlls to those needed. However, it’s important to have markup specified properly in all sources.

If you don’t want to use CMake’s export approach, don’t use GenerateExportHeader and do your own thing.

The issues are in 3rdparty libraries and they use GenerateExportHeader - that means the option of not using GenerateExportHeader is not there because it is not my CMake source. So therefore my hope that there is an option to disable this during the CMake configuration step but this seems to be impossible according to your response.

So my conclusion is, libraries use the standard function GenerateExportHeader in a right way and it produces wrong results for MinGW. Additionally the export macros are not required for MinGW so CMake generates wrong code for MinGW - this smells like a bug. I just wanted to clarify the situation before I open a bug report.

Did you add the define that you are going to link those libraries static? The RTDE_STATIC_DEFINE must be used somewhere. Ideally the rtde library target adds that as a INTERFACE compile definition when built statically.

No, I did not add the define RTDE_STATIC_DEFINE because I build and use shared libraries. I will try to dig into the compilation process to see what CMake is doing wrong here.

There is almost certainly not a bug in GenerateExportHeader. It is well-tested and widely used.

Please check that the markup used in the third-party libraries is correct. Please verify that rtde_EXPORTS is defined for the sources containing the definitions of symbols whose declarations are marked with RTDE_EXPORT, and that rtde_EXPORTS is not defined for sources in other libraries that consume rtde.

If you really think it is a bug, please post a complete minimal example demonstrating it.

I followed your suggestion to find out why compilation fails. The compilation first compiles the library and then compiles the examples. When compiling the first example, I see the following error:

[ 42%] Building CXX object CMakeFiles/servoj_example.dir/examples/cpp/servoj_example.cpp.obj
In file included from C:\CodingXP\cetoni_libraries\ur_rtde\examples\cpp\servoj_example.cpp:3:0:
C:/CodingXP/cetoni_libraries/ur_rtde/include/ur_rtde/rtde_control_interface.h:717:15: error: function 'ur_rtde::PathEntry::PathEntry(ur_rtde::PathEntry::eMoveType, ur_rtde::PathEntry::ePositionType, std::vector<double>)' definition is marked dllimport
   RTDE_EXPORT PathEntry(eMoveType move_type, ePositionType position_type, const std::vector<double> parameters)
               ^~~~~~~~~
make[2]: *** [CMakeFiles\servoj_example.dir\build.make:82: CMakeFiles/servoj_example.dir/examples/cpp/servoj_example.cpp.obj] Error 1
make[1]: *** [CMakeFiles\Makefile2:137: CMakeFiles/servoj_example.dir/all] Error 2
make: *** [Makefile:148: all] Error 2

The example consumes the library, so it is perfectly right that the library functions are marked as dllimport - like written in the generated export header:

#  ifndef RTDE_EXPORT
#    ifdef rtde_EXPORTS
        /* We are building this library */
#      define RTDE_EXPORT __declspec(dllexport)
#    else
        /* We are using this library */
#      define RTDE_EXPORT __declspec(dllimport)
#    endif
#  endif

So that means, we are using the library and dllimport should be defined - and it is defined, like the error message tells us. I noticed, that both mentioned functions in the error message are constructors. When reading the source code of the header, I noticed, that the classes do not use a dllexport for the whole class but for each single member function separately:

class RTDE
{
 public:
  RTDE_EXPORT explicit RTDE(const std::string hostname, int port = 30004, bool verbose = false);

  RTDE_EXPORT virtual ~RTDE();
...

As soon, as I remove the RTDE_EXPORT statement from both constructors the compilation succeeds.
So, that indicates, that either dllexport macro is only allowed for class member functions but not for costructors or that MinGW has a problem, if a constructor is marked dllexport.

I have not found a valid information so far, if class constructors should be marked as dllexport but this seems to be the problem here.

@githubuser0xFFFF did you ever figure out why this was so?

I just had the very same identical situation. Cross compiling for linux, macOS and Windows.
Linux and macOS works fine. Windows complains about marked dllimport.

ModuleInterface.cpp:62:17: error: function 'long int GetModuleVersion()' definition is marked dllimport
   62 | MODULE_API long GetModuleVersion()

Simply deleting statements in front of the constructors makes compilation succeed on MinGW.

MODULE_API long GetModuleVersion()

to:

long GetModuleVersion()

Trying to understand why if I ever would attempt to make the thing work on MSbuild again.

MODULE_API’s definition was in some codepath that thought it wasn’t going to compile the definition in ModuleInterface.cpp. It is an error to have a declaration with “this comes from another library” (what dllimport means) and then provide a definition for it.