Windows MinGW64 does not export member (static or not) functions defined within class body

Viewed 233

I have updated the code example and added more details since some people say in the comments that this code should not generate any exported symbols period.


I also have added some implementation to the methods, but it didn't change nothing in regards of exporting symbols with MinGW and Clang. (Didn't update objdump outputs though. Essentially they didn't change much).


I came by a very annoying problem with exporting symbols from an executable.

Consider the following code:

# CMakeLists.txt

add_executable(app main.cpp)
set_target_properties(app PROPERTIES ENABLE_EXPORTS 1)

add_library(lib SHARED main.cpp)
// main.cpp
class __declspec(dllexport) foo
{
public:
    int bar()
    {
        static int val = 3;
        return ++val;
    }
    static int buz()
    {
        static int val = 814;
        return ++val;
    }
};

template <typename T>
class __declspec(dllexport) foo_t
{
public:
    int bar()
    {
        static int val = 3;
        return ++val;
    }
    static int buz()
    {
        static int val = 814;
        return ++val;
    }
};

template class foo_t<int>;

int main()
{
    return 0;
}

MSVC

When compiled both executable and dll generate xxx.lib with exported symbols which can be used for linking.

// DUMPBIN.exe /EXPORTS app.lib (exact same as for lib.lib)

Dump of file lib.lib

File Type: LIBRARY

     Exports

       ordinal    name

                  ??4?$foo_t@H@@QEAAAEAV0@$$QEAV0@@Z (public: class foo_t<int> & __cdecl foo_t<int>::operator=(class foo_t<int> &&))
                  ??4?$foo_t@H@@QEAAAEAV0@AEBV0@@Z (public: class foo_t<int> & __cdecl foo_t<int>::operator=(class foo_t<int> const &))
                  ??4foo@@QEAAAEAV0@$$QEAV0@@Z (public: class foo & __cdecl foo::operator=(class foo &&))
                  ??4foo@@QEAAAEAV0@AEBV0@@Z (public: class foo & __cdecl foo::operator=(class foo const &))
                  ?bar@?$foo_t@H@@QEAAXXZ (public: void __cdecl foo_t<int>::bar(void))
                  ?bar@foo@@QEAAXXZ (public: void __cdecl foo::bar(void))
                  ?buz@?$foo_t@H@@SAXXZ (public: static void __cdecl foo_t<int>::buz(void))
                  ?buz@foo@@SAXXZ (public: static void __cdecl foo::buz(void))

As can be seen, both foo and template foo_t methods has been exported.

Clang

Dump of file libapp.dll.a

File Type: LIBRARY

     Exports

       ordinal    name

                  _ZN5foo_tIiE3barEv
                  _ZN5foo_tIiE3buzEv
                  _ZN5foo_tIiEaSERKS0_

As it can be seen only foo_t methods has been exported and only due to explicit template instantiation. If you remove explicit template instantiation there will be no libapp.dll.a. However there will be liblib.dll.a though with an empty EXPORTS section.

MinGW64

Dump of file liblib.dll.a

File Type: LIBRARY

     Exports

       ordinal    name

                  main
                  _ZN5foo_tIiE3buzEv
                  _ZN5foo_tIiE3barEv

Like Clang it has exported only explicit template instantiation methods.
But unlike Clang and MSVC there is no libapp.dll.a generated for an executable!

// objdump -t app.exe

File 
[116](sec  1)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000000016c0 .text$_ZN5foo_tIiE3barEv
AUX scnlen 0xb nreloc 0 nlnno 0 checksum 0x0 assoc 0 comdat 2
[118](sec  1)(fl 0x00)(ty  20)(scl   2) (nx 1) 0x00000000000016c0 _ZN5foo_tIiE3barEv
AUX tagndx 0 ttlsiz 0x0 lnnos 0 next 0
[120](sec  1)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000000016d0 .text$_ZN5foo_tIiE3buzEv
AUX scnlen 0x7 nreloc 0 nlnno 0 checksum 0x0 assoc 0 comdat 2
[122](sec  1)(fl 0x00)(ty  20)(scl   2) (nx 0) 0x00000000000016d0 _ZN5foo_tIiE3buzEv

The executable itself contains symbols for explicitly instantiated template foo_t methods. Why there is no static library generated for an executable then?

Conclusion

  1. In all the cases for a dynamic library there are exported symbols in a static library (libxxx.a or xxx.lib) for explicit class template instantiation. But MinGW64 does not generate a static library for an executable. Why?
  2. Only MSVC exports symbols for non-template class implicitly inlined methods. Why? Is it an expected behavior that a cross-platform application could rely on?
  3. Why is there an inconsistency between exporting implicitly inlined in-class implemented methods of a template and non-template classes (non-template are not exported)? Can a cross-platform application rely on template class methods being exported as a guarantee?

For in-depth understanding of the issue refer to https://github.com/skypjack/entt/issues/719

0 Answers
Related