GNOME Bugzilla – Bug 719847
Missing __declspec(dllimport) when building with MSVC?
Last modified: 2018-05-22 12:13:13 UTC
John Emmas has found bugs in several *mmconfig.h files. '#define *MM_API __declspec(dllimport)' is not activated as it should be, when compiling with Microsoft Visual C++. See https://mail.gnome.org/archives/gtkmm-list/2013-December/msg00002.html
I don't use mm packages in Windows. I hope someone can tell what ought to be done. I've looked at these *mmconfig.h.in files: atkmm/atk/atkmmconfig.h.in ATKMM_API is not used glibmm/gio/giommconfig.h.in GIOMM_API is not used glibmm/glib/glibmmconfig.h.in gtkmm/gdk/gdkmmconfig.h.in GDKMM_API is not defined gtkmm/gtk/gtkmmconfig.h.in libsigc++2/sigc++config.h.in libxml++/libxml++config.h.in pangomm/pango/pangommconfig.h.in PANGOMM_API is not defined mm-common/skeletonmm/skeleton/skeletonmmconfig.h.in SKELETONMM_API is not defined There are differences in the way ATKMM_API, GIOMM_API, GLIBMM_API, GDKMM_API, GTKMM_API, SIGC_API, and LIBXMLPP_API are defined. No *_API macro is used in the packages where none is defined. GIOMM_API --------- This is the definition of GIOMM_API. It's a good starting point for showing the differences between the packages. // Enable DLL-specific stuff only when not building a static library #if !defined(__CYGWIN__) && defined(__MINGW32__) && !defined(GIOMM_STATIC_LIB) # define GIOMM_DLL 1 #endif #ifdef GIOMM_DLL # if defined(GIOMM_BUILD) && defined(_WINDLL) /* Do not dllexport as it is handled by gendef on MSVC */ # define GIOMM_API # elif !defined(GIOMM_BUILD) # define GIOMM_API __declspec(dllimport) # else /* Build a static library */ # define GIOMM_API # endif /* GIOMM_BUILD - _WINDLL */ #else # define GIOMM_API #endif /* GIOMM_DLL */ GLIBMM_API ---------- Equivalent to GIOMM_API, except for these extra initial lines: #ifdef _WIN32 # if defined(_MSC_VER) # define GLIBMM_DLL 1 # endif #endif /* _WIN32 */ GTKMM_API --------- Equivalent to GIOMM_API, except that the first #if directive contains defined(_WIN32) instead of defined(__MINGW32__). LIBXMLPP_API ------------ No LIBXMLPP_DLL is defined. GLIBMM_DLL is used instead. Otherwise equivalent to GIOMM_API: #ifdef GLIBMM_DLL // Definitions of LIBXMLPP_API ............ #endif /* GLIBMM_DLL */ ATKMM_API --------- Much shorter than GIOMM_API, but equivalent to it, except for a missing '&&' in the first #if directive: /* Enable DLL-specific stuff only when not building a static library */ #if !defined(ATKMM_STATIC_LIB) defined(__MINGW32__) && !defined(__CYGWIN__) # define ATKMM_DLL 1 #endif /* Do not dllexport as it is handled by gendef on MSVC */ #if defined(ATKMM_DLL) && !defined(ATKMM_BUILD) # define ATKMM_API __declspec(dllimport) #else # define ATKMM_API #endif SIGC_API -------- Very different: #ifdef _WIN32 # if defined(_MSC_VER) # define SIGC_DLL 1 # endif #endif /* !_WIN32 */ #ifdef SIGC_DLL # if defined(SIGC_BUILD) && defined(_WINDLL) # define SIGC_API __declspec(dllexport) # elif !defined(SIGC_BUILD) # define SIGC_API __declspec(dllimport) # else # define SIGC_API # endif #else /* !SIGC_DLL */ # define SIGC_API #endif /* !SIGC_DLL */ Which definition of *MM_API is most correct? John's https://mail.gnome.org/archives/gtkmm-list/2013-December/msg00002.html looks like a vote for GLIBMM_API. But is it correct that GLIBMM_DLL is defined if defined(_WIN32) && defined(_MSC_VER), regardless of _WINDLL and GLIBMM_STATIC_LIB? Hope someone can tell what's correct. We could then define a macro, e.g. #define GLIBMM_DEFINE_MM_API(prefix) .............. that expands to the correct preprocessor directives.
Are the *MM_API macros used correctly? According to https://mail.gnome.org/archives/gtkmm-list/2013-December/msg00002.html *MM_API must be used in declarations of exported data ('extern' declarations, I suppose). Such use is missing in glibmm/glib/src/varianttype.hg gtkmm/gtk/gtkmm.h What about protected and public static data in class definitions? Shall *MM_API be used in such definitions? *MM_API is used in a few class definitions (class *MM_API). Is that correct? Is it necessary?
The libxml++ bug 570620 also concerns *_API macros. Can someone tell what's the right way to fix that bug? Insert GLIBMM_API in the definition of class Glib::usting, remove LIBXMLPP_API from the definition of class LIBXMLPP_API exception: public std::exception, or something else?
Hello Kjell, I think I will look into this soon, or at least when the next dev cycle starts, since a stable release, as until very lately the Visual Studio build files are getting out-of-date as Armin probably is not around for a long time. Personally I think it might be a better idea that we just say bye to gendef and just rely on declspec(dllexport) for exporting the API/classes, like what GLib and GTK+, and sigc++ is doing now-as it seems to me that lots of non-*mm symbols were put in the .def files by gendef during the process, which IMHO is probably not optimal. I think what needs to be done is that we need to see for any public variables and classes (that are compiled, not just a header-only implementation) whether they have the *MM_API macros as decorations, and ensure that __declspec(dllimport) is defined on Visual Studio. I am adding John to the list here, as the original problem he mentioned in the mail list is a crash relating to the *mm libraries, and this bug report might be of interest to him... ----- Hi John, Regarding your crash in the mail list, can you please try to rebuild the *mm libraries without the /vd2 switch (which will be in "Additional Options" in the "C/C++ compilation" section)? I have removed that upstream for glibmm, atkmm, pangomm and gtkmm (2.x/3.x) for the MSVC 2008/2010 builds, but I did not do so for MSVC 2005 (which is what I remember you using) as I don't have MSVC 2005 to test those builds. Any thoughts about how we look into the API/variable importing/exporting issue here? With blessings, thank you!
While it is tempting to use __declspec(dllexport) in place of gendef, we might be opening a can of worms. For example, glibmm has ustring class that has std::string string_ as a data member. If we attempt to export entire class, we will get problem with STL stuff export. This can be circumvented by exporting template instantiation (e.g. see http://stackoverflow.com/q/13864510/673826 ). "Extern" keyword for a template will cause tons of C4231 warnings by (at least) Visual Studio 2010 and older as non-standard extension. The next surprise would be things like libxml++ that uses STL. So same templates should be explicitly marked extern otherwise linker will complain that it is already defined in glibmm-xxx.lib. Another option would be to just ignore the warning as string_ is private and it seems have no noticeable side effect (http://stackoverflow.com/a/767709/673826). An alternative would be something like pimpl to hide away STL data members. Anyway I started with glibmm (see bug 749091) to see what it takes to ditch gendef. I had to add extra m4 definition to fetch proper outer namespace to add <outer namespace>MM_API depending on Gio or Glib stuff being compiled. Also I suggest we generate CMake files for MSVC users with autotools (and m4?) instead of maintaining tons of different MSVC projects ourselves.
Is this something that we still need?
Hi, Sorry, I did not get back to this soon enough, as I previously mentioned and promised. Once again, sorry! I think this might be something that would still be worth going in-depth to--as this portion still stands today even if we moved to C++-11-but since we are late in the cycle, this is something that would be better for the next cycle. I think for the warning that Mikhail mentioned, we might have to live with it--similar things do go on when building/using Boost as DLLs, for instance. By the way, though this is clearly another issue, even Visual Studio 2015 is currently unable to support enough of C++-14 to build libsigc++3 fully, so when we do eventually need to see how MS is doing for that, or perhaps need to use their newly-added CLang support for Windows in Visual Studio. With blessings, thank you!~
-- GitLab Migration Automatic Message -- This bug has been migrated to GNOME's GitLab instance and has been closed from further activity. You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.gnome.org/GNOME/gtkmm/issues/8.