Replace dllwrap with a Working MinGW DLL Build
You will identify what x86_64-w64-mingw32-dllwrap can still do on an installed Debian or Ubuntu toolchain, run a harmless interface check, and choose a safer path for new Windows DLL builds. The key result is a clear boundary: dllwrap is a deprecated wrapper, not a tool to introduce into new build scripts.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes for the checks below. You need a shell and the binutils-mingw-w64-x86-64 package. The examples inspect the command and do not create a DLL, alter a linker configuration or require elevated privileges.
1. Confirm the installed command and package
Check which executable your shell would run, then record the package version. Both commands are ordinary read-only checks:
$ command -v x86_64-w64-mingw32-dllwrap
/usr/bin/x86_64-w64-mingw32-dllwrap
$ dpkg-query -W -f='${Package} ${Version}\n' binutils-mingw-w64-x86-64
binutils-mingw-w64-x86-64 2.41.90.20240122-1ubuntu1+11.4
That version matters when you compare output with another machine. This guide was checked against GNU Binutils 2.41.90.20240122, packaged as the version shown above. Your distribution may ship a different build and warning text.
Checkpoint
If command -v prints nothing, stop here. The package or cross-toolchain path is missing; adding sudo to later commands will not make a missing executable appear.
2. Read the warning before using the tool
Ask the installed executable for its help:
$ x86_64-w64-mingw32-dllwrap --help
Usage x86_64-w64-mingw32-dllwrap <option(s)> <object-file(s)>
Generic options:
@<file> Read options from file
--quiet, -q Work quietly
--verbose, -v Verbose
--version Print dllwrap version
--implib <outname> Synonym for --output-lib
...
The full output also lists legacy controls for the driver, dlltool, entry point, image base, export files and import libraries. The important line is not an option, though: the installed program warns that it is deprecated and recommends gcc -shared or ld -shared instead.
The manpage installed with this package is even more direct. It describes dllwrap as an ancient PE DLL generator, says not to use it for new code, and points at ld --shared. Treat that as the compatibility boundary for this guide. Do not mistake a successful help command for a recommendation to preserve dllwrap indefinitely.
3. Verify the version without building anything
Use --version to obtain the program's own identity:
$ x86_64-w64-mingw32-dllwrap --version
GNU x86_64-w64-mingw32-dllwrap (GNU Binutils) 2.41.90.20240122
Copyright (C) 2024 Free Software Foundation, Inc.
...
The command may print the deprecation warning before the version banner. That is expected for this installed build. The version output is a useful diagnostic when a build log from an older machine appears to accept a different option set.
There is no need for sudo. Running dllwrap as root would not make an obsolete interface more compatible, and it would make any files produced by a later experiment harder to remove as your normal user.
4. Test option handling with a dry run
Before connecting dllwrap to real object files, use --dry-run with an explicit output choice. This is still not a DLL build, but it demonstrates an easy failure trap:
$ x86_64-w64-mingw32-dllwrap --dry-run --output-lib /tmp/example.a /tmp/example.o
x86_64-w64-mingw32-dllwrap: WARNING: x86_64-w64-mingw32-dllwrap is deprecated, use gcc -shared or ld -shared instead
...
The object path above is a placeholder. Replace it only with an object file you have already built. The output library path is under /tmp so that an experiment cannot overwrite a project artefact. A dry run can still fail because the input is absent or the installed wrapper cannot assemble a complete command from the supplied arguments. That failure is useful: it has not changed your source tree.
One confusing default is visible here. dllwrap needs an output choice such as --output-lib, its --implib synonym, or a DLL name supplied through its legacy interface. Supplying only an object file is not a complete invocation on this installation.
5. Use the supported shape for a new build
For new code, move the link step to the cross C compiler or linker named by the warning. A representative compiler command is:
$ x86_64-w64-mingw32-gcc -shared -o example.dll example.o
This is a build example, so it needs a real example.o and writes example.dll in the current directory. Check first that the compiler is available and that the object is the one you intend to link:
$ command -v x86_64-w64-mingw32-gcc
/usr/bin/x86_64-w64-mingw32-gcc
$ test -r example.o && echo 'object is readable'
object is readable
Do not paste an untrusted filename into a build script without quoting it. If the object or output path contains spaces, quote each shell argument. Keep the output in a disposable build directory until the DLL has been inspected.
The manpage also names ld --shared. Use the linker directly only when your project already owns the complete linker inputs and flags. The compiler driver normally supplies the language-runtime and startup details expected by a compiler-led build. These are different workflows, so do not mechanically replace a dllwrap command with ld and assume the result is equivalent.
6. Recover from a bad experiment
dllwrap and the replacement linker commands can write files, but they do not need elevated privileges when building in a directory you own. If a test created an unwanted file under /tmp, inspect it before removing it:
$ ls -l /tmp/example.a /tmp/example.dll 2>/dev/null
$ rm -- /tmp/example.a
The rm command is destructive. Remove only the exact disposable path you created, never a broad wildcard. If the compiler wrote an unwanted DLL in your project directory, stop and restore it from version control or a backup according to your project's normal recovery process. Do not overwrite a known-good DLL merely to make a test pass.
If the replacement command fails, preserve the diagnostic and inspect the object file, target architecture and link flags. A dllwrap warning is not evidence that the object is valid, that exports are correct or that the resulting DLL will load on Windows.
Done means
- You confirmed the executable and installed Binutils package version.
- You saw that dllwrap is deprecated and understood the recommended
gcc -sharedorld -shareddirection. - You tested the legacy interface without changing project files.
- New build work uses a deliberate compiler-driver or linker workflow.
- You keep output paths disposable until the DLL and its exports have been checked.