To do unit testing I had to export many small, internal classes which were never intended for consumption by the clients of my DLL.
I know that each exported function results in a stub in executable image and that Windows loader has to perform fix-up on those stubs if DLL is not loaded at its preferred location.
Someone suggested building DLL as a static lib, solely for the purposes of unit testing.
I wonder if it is worth the trouble? I could find no reference to how significant a problem of exporting every class from DLL may be, or is there any significant gain in loader performance and memory consumption if I am selective about it.
I think I read somewhere that GCC compiler exports everything by default.
EDIT: since the stated motivation for the question is disputable, let me rephrase it: Should I go through my DLLs and remove DLLEXPORT on all classes that are not exposed to its clients? Let's say I am working with a bunch of legacy DLLs and I noticed they have a lot of unnecessary exports. Will that improve the speed of loading? Specifically on Windows 7 and 8 using MSVC version 9+.
The exports table contains the name of every function that the DLL exports to other executables. These functions are the entry points into the DLL; only the functions in the exports table can be accessed by other executables. Any other functions in the DLL are private to the DLL.
You can declare C++ classes with the dllimport or dllexport attribute. These forms imply that the entire class is imported or exported. Classes exported this way are called exportable classes.
The dllexport and dllimport storage-class attributes are Microsoft-specific extensions to the C and C++ languages. You can use them to export and import functions, data, and objects to or from a DLL.
Does exporting everything from DLL affect performance?
It probably does, however the effect is immeasurably small. I made a python script that creates a test DLL exporting > 50,000 symbols. It consists of 1024 exported classes that each contain 48 functions (16 member functions, 16 virtuals and 16 static functions). The compiler also generates about 4-5 exports for each class that appear to be things like the vtable.
I measured load time of the application using SysInternals ProcMon. The load time on the very ancient underpowered test machine before linking the DLL was between 15-30ms. Adding the DLL, and one call to each of the ~50,000 exported functions resulted in no measurable change.
This is not a completely conclusive test, but it is good enough to convince me that the symbol resolution and fix-ups are probably an order of magnitude or more faster than any other limiting factor.
Interestingly, to be able to create such an insane DLL with the Microsoft tools required adding the /bigobj compiler flag and it appears there is also limit of 64K exported symbols in the PE format of a DLL. Furthermore, the static (compile time) compile and link phases for the DLL and application each took many minutes and used a lot of memory.
So you will be pushing on all kinds of other limits before you get to loader performance problems.
Let's say I am working with a bunch of legacy DLLs and I noticed they have a lot of unnecessary exports. Will that improve the speed of loading?
Nope.
Should I go through my DLLs and remove DLLEXPORT on all classes that are not exposed to its clients?
It depends.
Not simply because of load performance. If this was so critical to the application, then presumably somebody would be benchmarking the startup and would know exactly where the performance problems were. We shouldn't guess about performance impacts:
"We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil." -- Knuth
However, there may be other reasons for not exporting those "internal" classes and functions. The point to exporting a class/function is so that client code can use it. It should match the DLL's logical external API. If that wasn't the case for a function or class, then it shouldn't have been exported. If there is a lot of functionality in internal classes that cannot be used, or tested, without going through the DLL's public API, it makes one wonder why that functionality exists? If the intent was to create generic reusable classes, perhaps they should be in a library of their own?
Test Driven Design doesn't mean you have to go around exposing everything publicly. And DLL exports are not necessarily required for even the most invasive white-box unit testing of a class. For example, the unit test fixture could be built monolithically and statically link (or even directly include the sources) to whatever internal classes are needed.
Conversely, a completely excusable explanation for having done it this way may be simply that it was easy and simple to implement. If everything else is essentially equal (modulo style and some theoretical architecture concerns), it is also poor form to needlessly change and disrupt a system that was already done a certain way and is working fine.
So this may be a design that should not be copied or extended, and maybe it is worth cleaning it up whenever maintenance or refactoring opportunities come up.
I think I read somewhere that GCC compiler exports everything by default.
Mingw LD documentation concurs. Although, note that it says that if you export with __declspec or .DEF files, this auto-export behavior is disabled.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With