Is it possible to create a dll without dllexport?
-
As the title already almost says, is it possible to create a dll without explicit dllexport?
I am splitting off an application into different dll. So far, I have compiled everything in one run into a static application using only Qt dlls. The whole application is composed of several "libs" as code is used in multiple applications. Each time I had cut off some source the application size was shrinking as expected. The main part of the application was still 1.2 MB.
At last I intended to separate the typically main program with the event loop as used in many Qt based applications. Basically I duplicated the .pro file and did change one copy using the lib template while the other still used the app template. Certainly I ensured that the code file of main is only in the app pro-file. I have tried to compile and link for checking that all is in place before adding the typically dllimport and dllexport for the last change required to have all separated.
All compiled and linked well and also the execution of the application performed as expected. Out of curiosity I checked the size of the exe and expected something of a similar size as before (1.2 MB) because the mimic for import and export was still missing for the large main class and several other also large classes. However, the size of the new exe collapsed already to 50 kB. That caught me by surprize.
The main class, which is instanciated in the main program is a class which inherits from another class already exported to one of the previous dlls as well those classes are inferiting from QObject.
All done on Win 10 with MinGW 4.9.1.
I have tried to find an explanation in the web, but what I have found from Microsoft I understand that all the class have to be marked with dllexport. So the behaviour is probably not possible for MS compilers. For gcc I could not find a similar documentation.
Has anybody an explanation for this behaviour?
-
I'm not sure if I got you right.
You have a "main" class and it inherits from a class defined in a shared library, and this caused the size of the executable to shrink. Is that right? Sounds logical. What's the issue? -
Not exactly.
More like this here:
First classes level1 are exprted to dll1
class DLL1SHARED_EXPORT level1_1 { };
Second classes level2 are exported to dll2
class DLL2SHARED_EXPORT level2_1 : public level1_1 { };
Finally classes level_main are initially statically linked with code in program main.
class level_main_1: public level2_1 { };
main.exe has sized of about 1.2 MB as long as the compilation is done with all those "level_main_" classes through a project template "app" and one .pro file.
Duplication of .pro-file, renaming in one "TEMPLATE = app" -> "TEMPLATE = lib". Also ensured that only the file with "TEMPLATE = app" holds the source file with "program main(...)". LIBS += statement added to point to location of .lib (all the resulting dll).
The other .pro holds all remaining code files.Since I did NOT add so far the macro "DLL_MAIN_SHARED_EXPORT" or something to the definition of classes starting with "level_main_" I did expect that the size of the resulting .exe is statically linked and has a similar size of 1.2 MB.
However, apparently there is a dll already created and the exe size has dropped to 50 kB of .exe.
The only explanation I have at the moment is that a dynamic lib is default for "TEMPLATE=LIB" and I did not bother to change to make the library static through qmake. However, I thought that I would need also the macro "DLL_MAIN_SHARED_EXPORT" mimic for actually creating a dll.
-
TEMPLATE = lib
creates a dynamic shared library (lib+dll) by default. To make a static library (lib) you need to passCONFIG += staticlib
in the .pro of your library. -
@koahnig
Hi,As the title already almost says, is it possible to create a dll without explicit dllexport?
If I remember correctly, if you don't export anything the linker will not generate any code (thus no dll).
The only explanation I have at the moment is that a dynamic lib is default for "TEMPLATE=LIB"
It is. If you don't put "CONFIG += static" qmake will generate a makefile that compiles into a dynamic library.
However, I thought that I would need also the macro "DLL_MAIN_SHARED_EXPORT" mimic for actually creating a dll.
I don't follow. You don't export from static libraries in the first place. A static library has no notion of visibility, it doesn't have a header or any way to load dependencies. It's only a collection of translation units (object files). So exporting/importing is not relevant to static libraries at all.
Kind regards.
-
@Chris-Kawa said:
TEMPLATE = lib
creates a dynamic shared library (lib+dll) by default. To make a static library (lib) you need to passCONFIG += staticlib
in the .pro of your library.I can live with that, but why should I handle an additional include file?
Just created a new lib project called "testDll" and 4 files are created plus .pro.user. Those files are:
TestDll.cpp#include "TestDll.h" TestDll::TestDll() { }
TestDll.h
#ifndef TESTDLL_H #define TESTDLL_H #include "testdll_global.h" class TESTDLLSHARED_EXPORT TestDll { public: TestDll(); }; #endif // TESTDLL_H
testdll_global.h
#ifndef TESTDLL_GLOBAL_H #define TESTDLL_GLOBAL_H #include <QtCore/qglobal.h> #if defined(TESTDLL_LIBRARY) # define TESTDLLSHARED_EXPORT Q_DECL_EXPORT #else # define TESTDLLSHARED_EXPORT Q_DECL_IMPORT #endif #endif // TESTDLL_GLOBAL_H
and the TestDll.pro
#------------------------------------------------- # # Project created by QtCreator 2016-06-12T20:32:38 # #------------------------------------------------- QT -= gui TARGET = testDll TEMPLATE = lib DEFINES += TESTDLL_LIBRARY SOURCES += TestDll.cpp HEADERS += TestDll.h\ testdll_global.h unix { target.path = /usr/lib INSTALLS += target }
My conclusion was that I need to have always the "testdll_global.h" and the macro "TESTDLLSHARED_EXPORT" in every header and every class declared which I like to export to the dll.
-
To add to previous post:
The new conclusion would be that one can save quite a bit of work when ignoring the "testdll_global.h" and the macro "TESTDLLSHARED_EXPORT" stuff.
So why is that stuff added in the project template, if I do not need to have it at least with Qt? -
@koahnig said:
Just created a new lib project called "testDll" and 4 files are created plus .pro.user.
Note that the wizard lets you choose the type of the project. The default is "Shared Library" i.e. a DLL. That is what you got and for that the macros are required.
The other settings in the wizard are "Statically Linked Library" and "Qt Plugin". The statically linked library has only two files - a .h/.cpp of your class without the extra export/import macros.
-
@Chris-Kawa said:
@koahnig said:
Just created a new lib project called "testDll" and 4 files are created plus .pro.user.
Note that the wizard lets you choose the type of the project. The default is "Shared Library" i.e. a DLL. That is what you got and for that the macros are required.
The other settings in the wizard are "Statically Linked Library" and "Qt Plugin". The statically linked library has only two files - a .h/.cpp of your class without the extra export/import macros.
Agreed and all this is fine, but actually one can create a dll without using "testdll_global.h".
Possibly our posts crossed:
@koahnig said:To add to previous post:
The new conclusion would be that one can save quite a bit of work when ignoring the "testdll_global.h" and the macro "TESTDLLSHARED_EXPORT" stuff.
So why is that stuff added in the project template, if I do not need to have it at least with Qt?Basically there is my issue, why shall I add an include not required?
It looks logical to have the include "testdll_global.h", because it makes the look compatible to the typical things you have to do for creating a dll. However, as long as you stay within the Qt world it is additional work which is not required?
-
@koahnig said:
However, as long as you stay within the Qt world it is additional work which is not required?
It has nothing to do with Qt.
For a dynamically linked library you do need the import/export stuff, at least if you want to behave nicely. If you try it with MSVC you will see that your symbols are not visible if you don't export them.The thing you experience is a weirdness of GCC (or MinGW in this case). It has this weird behavior that if you don't export anything explicitly it will export everything (sic!). I'm guessing it's to keep libraries that didn't have MSVC in mind working. As soon as you export any symbol the MSVC-like behavior kicks in and only those symbols declared as export will be exported.
To test that try to build your lib without any symbols exported (comment out the macros). Use DependencyWalker to examine the library - note that everytihing is exported. Now add this single export in your header:
___declspec( dllexport ) int foo;
and inspect the library again - onlyfoo
is exported. -
@Chris-Kawa said:
The thing you experience is a weirdness of GCC (or MinGW in this case). It has this weird behavior that if you don't export anything explicitly it will export everything (sic!). I'm guessing it's to keep libraries that didn't have MSVC in mind working. As soon as you export any symbol the MSVC-like behavior kicks in and only those symbols declared as export will be exported.
OK, that is the explanation I was looking for.
I thought already right from the beginning that this might have something to do with MinGW. However, assuming such weirdness right away is typically not a good choice. Similar to assuming it is a compiler error if you do not find something right away.Thanks a lot for confirmation. I was trying to find a note somewhere, but I could not.
-
It has nothing to do with Qt.
Nor with C++ actually. These things are OS specific and depend on the implementation of the linker/loader and the ABI.
I'm guessing it's to keep libraries that didn't have MSVC in mind working.
Most probably, yes. This is the default behavior on Linux - everything is exported by default, so I would assume this is to "facilitate" porting from *nix to windows.
Basically there is my issue, why shall I add an include not required?
As Chris said, it might not be an include file, but you do need the linkage specifiers.
-
So basically all is broadened to hopefully all compilers and OSs.
It should be. To be honest, this default exporting behavior is one of the more suspicious decisions in Linux. Windows' way of enforcing symbols to be hidden by default (like we have with classes' members) is much more logical. I actually define two macros when making shared libraries - one that is for the export/import and one that forces symbols not explicitly exported to be hidden on Linux, thus getting a similar binary interface on all platforms; like done here.
Kind regards.