Skip to main content

exporting templates from dlls

Submitted by lorien on
Forum

http://support.microsoft.com/default.aspx?scid=kb;EN-US;168958

Bloody windoze... You have to force an explicit instantiation with a __declspec(dllexport) inside the dll, a __declspec(dllimport) when using the dll, and an "extern" in front of the template keyword when using the dll...

Might as well sacrifice a chicken to Bill while you're at it.

Submitted by Daemin on Fri, 08/04/05 - 3:57 AM Permalink

Well templates are really generated at compile time, the compile time of where they are used to be more precise. Therefore in order to have a templated class of some sort (say std::vector) in a library of yours you need to tell it to generate the code for that class. Thus requiring an explicit instantiation, otherwise the template will be compiled when it gets actually used in some other program.

Submitted by lorien on Fri, 08/04/05 - 9:55 PM Permalink

Yeah, but you don't have to do any of this crap on any OS other than windows (it just works), Borland C++ on windows automatically exports and imports templates defined in dlls, and mingw32 doesn't seem to need it either (actually the code won't compile with gcc-3.4.2 on windows).

Submitted by Daemin on Sat, 09/04/05 - 6:43 AM Permalink

Are you sure in those cases that the code generated by the templates is actually inside of those libraries, not just inside their headers (and thus gets compiled like a template would normally?).

Submitted by lorien on Mon, 11/04/05 - 10:25 PM Permalink

I'm not sure about mingw, I know Borland does automatically export because there is a commandline option to tell it to do so.

But if mingw wasn't exporting/importing, then iterating over a a vector full of strings returned from a method inside a dll wouldn't work, and it does.

No idea on other OSs, and don't really care, what I do care about is it working.

It wouldn't surprise me if it was re-compiling, but then throwing away the rendundant template instatiations. The whole shared library thing is much better on unixish platforms (though loading plugins is a little strange on MacOSX)- it defaults to every symbol in a .so file being exported by default, and whilst the ability to hide symbols is part of the ELF specification, it hasn't been properly supported by pre GCC 4.0 compilers (the only way you could hide something was by declaring it as static in a cpp file, or putting it in an anonymous namespace).

It hasn't mattered, on unixish platforms shared objects just work without hassle. No import libraries are needed either.

I think BeOS needed identical __declspec stuff to windows, but BeOS is dead.

Submitted by Daemin on Wed, 13/04/05 - 10:31 PM Permalink

Returning a std::vector from a DLL would still work even if the instantiated template code was not exported from the DLL. This would be because a copy of the code would be created inside the executable and another in the DLL, and all that would be passed would be the data that they use.

I wouldn't be too surprised if it did the same thing in shared libraries on unix platorms too. Because to you still need to compile against the library's header files when you want to use it. Therefore your code knows that it needs to instantiate a std::vector etc, and it would compile that code into the binary. I guess you'd have to inspect the symbols stored and the code generated for the shared library to be able to tell for sure.

Submitted by lorien on Fri, 15/04/05 - 12:52 AM Permalink

The data types still have to be exported, and this is not a normal string (I know std::string is exported from msvcrt).

It is a std::basic_string, MyMetapoolAllocator > i.e. a string that uses an allocator that uses my memory pool system.

Even then this is a nebulous point: msvc throws out a million warning messages about returning vectors from a function in a dll, it says that it will not work.

I'll try removing my exports and running a test in msvc. Another test would be making a public map member variables in an exported class, and try using it in an exe.

Posted by lorien on
Forum

http://support.microsoft.com/default.aspx?scid=kb;EN-US;168958

Bloody windoze... You have to force an explicit instantiation with a __declspec(dllexport) inside the dll, a __declspec(dllimport) when using the dll, and an "extern" in front of the template keyword when using the dll...

Might as well sacrifice a chicken to Bill while you're at it.


Submitted by Daemin on Fri, 08/04/05 - 3:57 AM Permalink

Well templates are really generated at compile time, the compile time of where they are used to be more precise. Therefore in order to have a templated class of some sort (say std::vector) in a library of yours you need to tell it to generate the code for that class. Thus requiring an explicit instantiation, otherwise the template will be compiled when it gets actually used in some other program.

Submitted by lorien on Fri, 08/04/05 - 9:55 PM Permalink

Yeah, but you don't have to do any of this crap on any OS other than windows (it just works), Borland C++ on windows automatically exports and imports templates defined in dlls, and mingw32 doesn't seem to need it either (actually the code won't compile with gcc-3.4.2 on windows).

Submitted by Daemin on Sat, 09/04/05 - 6:43 AM Permalink

Are you sure in those cases that the code generated by the templates is actually inside of those libraries, not just inside their headers (and thus gets compiled like a template would normally?).

Submitted by lorien on Mon, 11/04/05 - 10:25 PM Permalink

I'm not sure about mingw, I know Borland does automatically export because there is a commandline option to tell it to do so.

But if mingw wasn't exporting/importing, then iterating over a a vector full of strings returned from a method inside a dll wouldn't work, and it does.

No idea on other OSs, and don't really care, what I do care about is it working.

It wouldn't surprise me if it was re-compiling, but then throwing away the rendundant template instatiations. The whole shared library thing is much better on unixish platforms (though loading plugins is a little strange on MacOSX)- it defaults to every symbol in a .so file being exported by default, and whilst the ability to hide symbols is part of the ELF specification, it hasn't been properly supported by pre GCC 4.0 compilers (the only way you could hide something was by declaring it as static in a cpp file, or putting it in an anonymous namespace).

It hasn't mattered, on unixish platforms shared objects just work without hassle. No import libraries are needed either.

I think BeOS needed identical __declspec stuff to windows, but BeOS is dead.

Submitted by Daemin on Wed, 13/04/05 - 10:31 PM Permalink

Returning a std::vector from a DLL would still work even if the instantiated template code was not exported from the DLL. This would be because a copy of the code would be created inside the executable and another in the DLL, and all that would be passed would be the data that they use.

I wouldn't be too surprised if it did the same thing in shared libraries on unix platorms too. Because to you still need to compile against the library's header files when you want to use it. Therefore your code knows that it needs to instantiate a std::vector etc, and it would compile that code into the binary. I guess you'd have to inspect the symbols stored and the code generated for the shared library to be able to tell for sure.

Submitted by lorien on Fri, 15/04/05 - 12:52 AM Permalink

The data types still have to be exported, and this is not a normal string (I know std::string is exported from msvcrt).

It is a std::basic_string, MyMetapoolAllocator > i.e. a string that uses an allocator that uses my memory pool system.

Even then this is a nebulous point: msvc throws out a million warning messages about returning vectors from a function in a dll, it says that it will not work.

I'll try removing my exports and running a test in msvc. Another test would be making a public map member variables in an exported class, and try using it in an exe.