~skeeto/public-inbox

3 2

How to build and use DLLs on Windows: import library, .lib or .dll.a?

Antonin Décimo <antonin@tarides.com>
Details
Message ID
<CACCWBSDcFmSHuMgezT1jycJf+S8eCjGyOwCyn5GON1MWecmjZg@mail.gmail.com>
Sender timestamp
1739458694
DKIM signature
missing
Download raw message
Dear Mr. Wellons,

Thank you for your blog, which has been an invaluable source of
information for me.

I was just using your post "How to build and use DLLs on Windows" to
fix a C library. I'm using the MinGW-w64 toolchain. You suggest
generating import libraries with mingw for compatibility with MSVC.
MSVC expects .lib files, however, looking at MinGW-w64 packages from
Arch Linux and Cygwin, it seems that the MinGW-w64 toolchain generates
.dll.a files. Am I correct in understanding that the two types of
files are identical (regardless of the extension)?
The autotools/libtool suite generates two files: lib${name}.dll and
lib${name}.dll.a. Maybe you could mention this other naming scheme in
your blogpost.

Best regards and thanks again,
-- Antonin
Details
Message ID
<20250215034831.gmnlfa2wcw6cjhqb@nullprogram.com>
In-Reply-To
<CACCWBSDcFmSHuMgezT1jycJf+S8eCjGyOwCyn5GON1MWecmjZg@mail.gmail.com> (view parent)
Sender timestamp
1739573311
DKIM signature
missing
Download raw message
Thanks for the kind words, Antonin, and I'm happy to hear that!

> Am I correct in understanding that the two types of files are identical 
> (regardless of the extension)?

Yup, it's no more than a difference in naming convention, and these are 
the same format. I've added a brief note about this to my article. I do 
think the Mingw-w64 convention is better, but it wouldn't have worked on 
the old 8.3 filesystems where the MSVC conventions originated.

> You suggest generating import libraries with mingw for compatibility 
> with MSVC.

My views have shifted since writing my article 4 years ago. Not only have 
import libraries grown on me, I quite like the concept. They're powerful 
and flexible (symbol renaming, forwarding, etc.). I miss DEF files when 
working on other platforms. Being explicit about your exported interface 
is important. They also fit naturally into a cross toolchain. So even more 
than compatibility, they're good for clean linking.

The traditional unix exporting of everything, which Binutils emulates by 
default, is simple but messy. In practice such libraries are a tangle of 
semantic interposition. Case in point I ran into last month: In your 
favorite Linux distribution, examine libreadline's dynamic symbols.

$ nm -D /usr/lib/*/libreadline.so | grep '\<x'

This likely lists xfree, xmalloc, and xrealloc, meaning these functions 
are accidentally part of its public interface. If a libreadline-using 
binary defines any of these as dynamic symbols then they'll be quietly 
interposed into libreadline, possibly with disastrous results. Lots of 
libraries on Linux look like this due to automatic exporting of symbols.

Along these lines, just a couple weeks ago Binutils accepted a patch from 
me to further tighten up --export-all-symbols, which relies on a complex 
heuristic to guess about which symbols should be exported and which should 
not. Better to skip such guessing entirely.
Details
Message ID
<2h6bwccswchxdg37wpinytti2fjn4jbbljcmpdxkx6kri53ui3@gypyuvl3jmgy>
In-Reply-To
<20250215034831.gmnlfa2wcw6cjhqb@nullprogram.com> (view parent)
Sender timestamp
1739622478
DKIM signature
pass
Download raw message
On Fri, Feb 14, 2025 at 10:48:31PM GMT, Christopher Wellons wrote:
> Case in point I ran into last month: In your favorite Linux
> distribution, examine libreadline's dynamic symbols.
>
> $ nm -D /usr/lib/*/libreadline.so | grep '\<x'

Interestingly, I don't get this in my gentoo system. Digging around the
ebuild (https://github.com/gentoo/gentoo/blob/dc4ee4820331dbba559ddf8cd115ae6c5441e684/sys-libs/readline/readline-9999.ebuild#L174):

	# https://lists.gnu.org/archive/html/bug-readline/2010-07/msg00013.html
	append-cppflags -Dxrealloc=_rl_realloc -Dxmalloc=_rl_malloc -Dxfree=_rl_free

Looks like the gentoo maintainers are (rightfully) patching this mess
up. Following the bug link was rather dreadful, though.

	>> why do you need to use those function names ?  using a name spaced function 
	>> like rl_malloc or _rl_malloc would keep the same functionality without 
	>> clashing with other people.
	>
	>No, it wouldn't.  It would not allow, for instance, an application to
	>control all the memory allocation and management readline performs.

Looks like this is intentional and the maintainer (I presume that's the
maintainer) doesn't want to change it to some "name spaced" name either.
Mind you, such malloc hooks without context pointer is rather useless
already for any actual usecase where user is using a custom allocator.
So really, it's just a very bad decision from libreadline/gnu. Perhaps
debian ought to patch it up too if upstream won't.

- NRK
Details
Message ID
<20250217211538.qw3engo4k72ufiix@nullprogram.com>
In-Reply-To
<2h6bwccswchxdg37wpinytti2fjn4jbbljcmpdxkx6kri53ui3@gypyuvl3jmgy> (view parent)
Sender timestamp
1739808938
DKIM signature
missing
Download raw message
Thanks for digging this up, NRK. I hadn't taken time to investigate, and 
there's more to it than I expected. Looks like Gentoo has been patching 
this since February 2011 with Readline 6.2.

If ELF had something like DEF files, the packager could list a complete, 
clean interface in a DEF file, then include it at link time (e.g. via LIBS 
or whatever). It would set the entire public surface area of the library, 
hiding all the internal functions it exposes, without touching the code, 
which in the case of Readline otherwise defines no "RL_API" prefix macro 
to control custom visibility/dllexport attributes of API symbols. A DEF 
can even rename symbols, so a packager could prepend a namespace prefix to 
the exported name without macro hacks:

LIBRARY libreadline8
EXPORTS
_rl_malloc = xmalloc
...

(Despite having DEF, on Windows none of this particular issue matters 
anyway. No interposition, and imports are a (module, symbol) tuple, not 
just a symbol. That means no LD_PRELOAD, but otherwise, IMHO, it's a 
cleaner, better linking model.)

With import libraries we can apply the DEF tricks without rebuilding nor 
relinking a library. Generate an import library from your custom DEF, and 
it works so long as used imports ultimately map onto an export in the DLL. 
For Readline this might matter if you wanted to link xmalloc from another 
library (e.g. gnulib) without worrying that the linker will pick Readline 
xmalloc, no longer visible to the linker (not listed as such in the import 
library). Otherwise you must carefully order libraries at link time.

On its own, a DEF-like listing wouldn't solve deoptimizations (i.e. lack 
of inlining) resulting from semantic interposition that could no longer 
occur, because it's a linker input. IMHO, interposition should be opt-in 
not opt-out.

> Looks like this is intentional

Yup, that's the maintainer. I had assumed it was an accident because these 
functions are not documented by Readline. If they're undocumented, how can 
someone overriding them be sure they're defining them correctly?

I agree Debian ought to patch it up. Gentoo's 14-year situation clearly 
makes the case that virtually nobody's using Readline interposition on 
purpose. I'm not using Readline, and it matters little to me personally, 
though. I had merely stubbed my toe on it while examining a project, and 
was shocked at the mess I found, and that it's tolerated from such a high 
profile system library.

Even with those three functions renamed, there's still some oddities like 
"crlf" and "ding". They've since been given rl_ prefixes, but the original 
exports remain for compatibility I guess.
Reply to thread Export thread (mbox)