0

I'm experimenting a bit with building DLLs on windows using MINGW.

A very good summary (in my opinion) can be found at: https://www.transmissionzero.co.uk/computing/building-dlls-with-mingw/

There is even a basic project which can be used for the purpose of this discussion: https://github.com/TransmissionZero/MinGW-DLL-Example/releases/tag/rel%2Fv1.1

Note there is a cosmetic mistake in this project which will make it fail out of the box: the Makefile does not create an "obj" directory - Either adjust the Makefile or create it manually.

So here is the real question. How to change the Windows DLL name so it differs from the actual DLL file name ?? Essentially I'm trying to achieve on Windows, the effect which is very well described here on Linux: https://www.man7.org/conf/lca2006/shared_libraries/slide4b.html

Initially I tried changing "InternalName" and ""OriginalFilename" in the resource file used to create the DLL but that does not work.

In a second step, I tried adding "-Wl,-soname,SoName.dll" on the command that performs the final link, to change the Windows DLL name.

However, that does not seem to have the expected effect (I'm using MingW 7.3.0, x86_64-posix-seh-rev0). Two things makes me say that:

1/ The test executable still works (I would expect it to fail, because it tries to locate SoName.dll but can't find it).

2/ "pexports.exe AddLib.dll" produces the output below, where the library name hasn't changed:

LIBRARY "AddLib.dll"
EXPORTS
Add
bar DATA
foo DATA

Am I doing anything wrong ? Are my expectations wrong perhaps ?

Thanks for your help ! David

DaveC
  • 115
  • 8

2 Answers2

0

First of all, I would like to say it's important to use either a .def file for specifying the exported symbols or use __declspec(dllexport) / __declspec(dllimport), but never mix these two methods. There is also another method using the -Wl,--export-all-symbols linker flag, but I think that's ugly and should only be used when quick and dirty is what you want.

It is possible to tell MinGW to use a DLL filename that does not match the library name. In the link step use -o to specify the DLL and use -Wl,--out-implib, to specify the library file.

Let me illustrate by showing how to build chebyshev as a both static and shared library. Its sources consist of only only 2 files: chebyshev.h and chebyshev.c.

  1. Compile
gcc -c -o chebyshev.o chebyshev.c -I. -O3
  1. Create static library
ar cr libchebyshev.a chebyshev.o
  1. Create a .def file (as it wasn't supplied and __declspec(dllexport) / __declspec(dllimport) wasn't used either). Note that this file doesn't contain a line with LIBRARY allowing the linker to specify the DLL filename later. There are several ways to do this if the .def file wasn't supplied by the project:

3.1. Get the symbols from the .h file(s). This may be hard as sometimes you need to distinguish for example between type definitions (like typedef, enum, struct) and actual functions and variables that need to be exported;

echo "EXPORTS" > chebyshev.def
sed -n -e "s/^.* \**\(chebyshev_.*\) *(.*$/\1/p" chebyshev.h >> chebyshev.def

3.2. Use nm to list symbols in the library file and filter out the type of symbols you need.

echo "EXPORTS" > chebyshev.def
nm -f posix --defined-only -p libchebyshev.a | sed -n -e "s/^_*\([^ ]*\) T .*$/\1/p" >> chebyshev.def
  1. Link the static library into the shared library.
gcc -shared -s -mwindows -def chebyshev.def -o chebyshev-0.dll -Wl,--out-implib,libchebyshev.dll.a libchebyshev.a

If you have a project that uses __declspec(dllexport) / __declspec(dllimport) things are a lot easier. And you can even have the link step generate a .def file using the -Wl,--output-def, linker flag like this:

gcc -shared -s -mwindows -o myproject.dll -Wl,--out-implib,myproject.dll.a -Wl,--output-def,myproject.def myproject.o

This answer is based on my experiences with C. For C++ you really should use __declspec(dllexport) / __declspec(dllimport).

Brecht Sanders
  • 6,215
  • 1
  • 16
  • 40
  • Thanks a lot for all the details and for sharing your experience ;-) I was able to replicate all the steps you indicated without any trouble. With your approach, I can see two key points: 1/ The DEF file doesn't contain a line with LIBRARY 2/ the -Wl,--out-implib option allows me to have an "import library" name that differs from the DLL name. However the effect I was specifically trying to achieve is a little different - See: https://www.man7.org/conf/lca2006/shared_libraries/slide4b.html Apologies for the poor formatting - I still don't understand how to do what I want – DaveC Sep 22 '20 at 16:55
  • Not sure I understand what you need exactly, but note that unlike `.so` file in the Unix/Linux world (where `LD_LIBRARY_PATH` helps locating the shared library), `.dll` files on Windows need to be in the same place as the `.exe` or in a folder listed in the `PATH` environment variable. – Brecht Sanders Sep 22 '20 at 18:53
  • To be more specific: your approach almost does what I wanted: `dlltool -I libchebyshev.dll.a` produces `chebyshev-0.dll` which is half of the job (when linking with the import library). However what I was curious to understand is how the DLL internal name can be set to something different than the DLL file name. Your approach does not address this half the job. `pexports.exe chebyshev-0.dll` still produces `LIBRARY "chebyshev-0.dll"` – DaveC Sep 22 '20 at 19:22
  • @DaveC The internal name must match the .dll name. It's also the name (without .dll extenstion) stored in the PE format used for .dll and .exe files to specify which shared libraries they depend upon. I don't see how these can be different, or why you would want this. With my tips above you can already choose any name you want. – Brecht Sanders Sep 23 '20 at 16:36
-1

I believe I have found one mechanism to achieve on Windows, the effect described for Linux in https://www.man7.org/conf/lca2006/shared_libraries/slide4b.html

This involves dll_tool

In the example Makefile there was originally this line:

gcc -o AddLib.dll obj/add.o obj/resource.o -shared -s -Wl,--subsystem,windows,--out-implib,libaddlib.a

I simply replaced it with the 2 lines below instead:

dlltool -e obj/exports.o --dllname soname.dll -l libAddLib.a obj/resource.o obj/add.o
gcc -o AddLib.dll obj/resource.o obj/add.o obj/exports.o -shared -s -Wl,--subsystem,windows

Really, the key seems to be the creation with dlltool of an exports file in conjunction with dllname. This exports file is linked with the object files that make up the body of the DLL and it handles the interface between the DLL and the outside world. Note that dlltool also creates the "import library" at the same time

Now I get the expected effect, and I can see that the "Internal DLL name" (not sure what the correct terminology is) has changed:

First evidence:

>> dlltool.exe -I libAddLib.a
soname.dll

Second evidence:

>> pexports.exe AddLib.dll
LIBRARY "soname.dll"
EXPORTS
Add
bar DATA
foo DATA

Third evidence:

>> AddTest.exe
Error: the code execution cannot proceed because soname.dll was not found.

Although the desired effect is achieved, this still seems to be some sort of workaround. My understanding (but I could well be wrong) is that the gcc option "-Wl,-soname" should achieve exactly the same thing. At least it does on Linux, but is this broken on Windows perhaps ??

DaveC
  • 115
  • 8
  • You're creating a file `libAddLib.a` - which should really be called `libAddLib.dll.a` as it's the import library for a shared library - which refers to `soname.dll` while your binary is actually called `AddLib.dll`. That doesn't make any sense, so it's normal your AddTest.exe won't find the right library. I have no idea why you want to do such a thing. – Brecht Sanders Sep 23 '20 at 19:27
  • I completely understand why you are confused.... I am not surprised that that my AddTest.exe doesn't find the right library - This is exactly the behaviour I would expect, when the DLL file name ("AddLib.dll") does not match the DLL name in the PE structure ("soname.dll"). The point I was making in my original post is that when I use "-Wl,-soname,SoName.dll " to build my DLL, I would expect the AddTest.exe to fail in the very same way. Yet it still works.... Hence the title of this discussion: does “-Wl,-soname” work on MinGW ? – DaveC Sep 23 '20 at 23:02
  • As to why it can be useful to build a DLL for which the "file name" does not match the "internal name" in the PE structure (i.e. the "soname"). There is a good discussion [here](https://stackoverflow.com/questions/12637841/what-is-the-soname-option-for-building-shared-libraries-for) and a lof of information [there](https://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html). These links describe mechanisms traditionally used on linux but not on Windows. Nevertheless, the concept of "soname" exists on Windows, therefore I would expect “-Wl,-soname” to work on MinGW, but it seems not. – DaveC Sep 23 '20 at 23:19
  • At last, “-Wl,-soname” might have no effect on Windows (or my expectations are wrong perhaps), but the solution I'm proposing above shows that it is possible to achieve the same effect with dlltool & dllname. The fact that AddTest.exe does not find the right library shows that "soname" was effectively set inside the PE structure of the DLL. – DaveC Sep 23 '20 at 23:35
  • I always assumed `-Wl,-soname,libname.dll` doesn't work on MinGW. I also believe you should avoid `dlltool` as much as possible when you're building from source. My advice is to only use `dlltool` to make `.dll.a` files for `.dll` files that you don't have the source of. I have built all my http://winlibs.com/ releases based on these principles (except that there everything is built from source from the ground up). – Brecht Sanders Sep 24 '20 at 05:43
  • The good news when porting to Windows is that build frameworks like autoconf/configure, CMake, Meson, QMake all take care of this for you. Just porting the occasional project that only comes with only a `Makefile` needs replacing some stuff to essentially use `-Wl,--out-implib` instead of `-Wl,-soname`. – Brecht Sanders Sep 24 '20 at 05:47
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/222028/discussion-between-davec-and-brecht-sanders). – DaveC Sep 24 '20 at 15:11