1

I am using 3rd party libraries to build my executable. More specifically I have in ./extern/bin/win64

libfoo.dll
libfoo.dll.a
libbar.dll

Despite its name, it looks like libfoo.dll.a isn't really an import library, but rather an archive (static library). After scratching my head for some time, I came to this conclusion by looking at the output of lib /list libfoo.dll.a (from here) which gives me a bunch of .o files.

The command line I'm using to build my executable is always the same:

g++ -std=c++14 test.cpp -I./extern/include -L./extern/bin/win64 -lbaz -static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ -lpthread -Wl,-Bdynamic -lfoo -lbar -s -o test.exe

My understanding is that the final -Wl,-Bdynamic gives preference to dynamic linkage but doesn't insist on dynamic linkage. The linker should still be happy if only the static version of a library exist, but it should pick the dynamic version when both the static and the dynamic version exist. Correct ?

Now here is the part that puzzles me a little bit. If, in ./extern/bin/win64, I only keep libbar.dll and:

  1. libfoo.dll then the executable has dependencies on libfoo.dll and libbar.dll (expected: dynamic linkage to libfoo is the only option)
  2. libfoo.dll.a then the executable has a dependency on libbar.dll only (expected: static linkage to libfoo is the only option)
  3. Both libfoo.dll and libfoo.dll.a then the executable has a dependency on libbar.dll only (surprising: static linkage seems to have been used but dynamic linkage was supposed to be preferred)

Does anyone have a theory to explain #3 ? Are my expectations incorrect ?

[Edit] As an extension to #3, I have also found that if I separate libfoo.dll and libfoo.dll.a into different folders, then the first folder to appear on the command line following -L determines which version of the library is selected. Again -Wl,-Bdynamic does not seem to have the expected effect....

PS: if anyone wants to have a detailed inspection of the libraries, they're distributed with Matlab, located in extern\bin\win64 as discussed. For completeness, the source code for my example can be found here but is this probably not relevant. Also using gcc 6.3 from here.

DaveC
  • 115
  • 8
  • 1
    In `ld` point of view, it did choose the dynamic linking option in #3. Because it expects the `.dll.a` file to be a dynamic linker library, not a static one (which should be `.a`). – ssbssa Mar 17 '21 at 11:55
  • You're absolutely right ;-) I simply renamed the `.dll.a` file as `.a` and then suddenly everything behaved as expected ! This made me realize that having the correct file name extensions is critical (although in this specific example, I should blame it on the 3rd party who provides the libraries) - I wrongly assumed that `ld` was actually looking at the content of the libraries to find out if static linkage or dynamic linkage would be used. – DaveC Mar 17 '21 at 16:02
  • Let me rephrase slightly. After renaming the .dll.a file as .a, everything behaves as expected when using my windows **native** toolchain ('as expected' in the sense that in #3, the executable has a dependency on both `libfoo.dll` and `libbar.dll`). However, when using my windows **cross-compilation** toolchain (runs on Linux), I still get the same behavior as before (the executable has a dependency on `libbar.dll` only). But I also found that if I change the command line to `-llibfoo -llibbar` then I do get dynamic linking. Can anyone make sense of that ?? – DaveC Mar 17 '21 at 22:33
  • The section 'direct linking to a DLL' in the [win32 ld documentation](https://sourceware.org/binutils/docs/ld/WIN32.html#WIN32) is very informative. I still cannot explain the behavior seen with my windows cross-compilation toolchain though. – DaveC Mar 17 '21 at 22:37
  • Last but not least, I have found that `libfoo.dll.a` actually seems to be some kind of hybrid (not sure what to call it) in the sense that it is **both** an archive (`lib /list libfoo.dll.a` gives me a bunch of .o files) and an import library (`link /dump /linkermember libfoo.dll.a` gives me a bunch of exported functions - Thanks to Alan in [this discussion](https://stackoverflow.com/questions/3573475/how-does-the-import-library-work-details)). It could well be the cause of all this confusion. Has anybody seen anything like this before ? – DaveC Mar 17 '21 at 22:50
  • `link /dump /linkermember` gives you all functions that the linker can use, but that doesn't necessarily mean that they were exported in the dll sense. – ssbssa Mar 18 '21 at 11:18
  • @ssbssa: thanks for the clarification ! As a sanity check I tried using `link /dump /linkermember` on a proper archive (static library) and realised it was still giving me a bunch of names.... In the end I found that `dumpbin /symbols /exports libfoo.dll.a` removed any ambiguity. It's not very readable (to me) but clearly shows what I suspected: both a bunch of static functions, and a bunch of exported functions. – DaveC Mar 19 '21 at 16:27

0 Answers0