I'm trying to build an application and link it against the ffmpeg DLL's. However I want to build a static exe file.
I'm using MSYS2
and mingw-w64
(x86_64) with gcc version 13.2.0, when building this is the command being used by the Makefile
gcc -g -O2 -static -o \
comskip.exe comskip-comskip.o comskip-mpeg2dec.o comskip-platform.o comskip-video_out_dx.o ccextratorwin/comskip-608.o ccextratorwin/comskip-ccextractor.o ccextratorwin/comskip-encoding.o ccextratorwin/comskip-general_loop.o ccextratorwin/comskip-myth.o \
-largtable2 -Lffmpeg-6.1.1-full_build-shared/lib -lavutil -lavformat -lavcodec -lswscale -lcomdlg32 -lgdi32 -lpthread -lm
However the exe file produced is not statically linked to the ffmpeg libraries (avcodec, avutil, avformat and swscale). When I try to run the exe it's still asking for the dll file separately.
The file I have in the lib folder are avcodec.lib
, avcodec-60.def
and avcodec.dll.a
.
The question is,
(a) Why is mingw-w64 still linking dynamically instead of linking statically to the *.lib
files?
(b) What do I need to have it link statically to the avcodec library?
I also have the avcodec.dll
file, but my understanding is that the *.lib
files are needed to link statically). These are 64 bit dll and lib files.
I'm trying to build an application and link it against the ffmpeg dll's. However I want to build a static exe file.
That's not an option I'm afraid. You can't statically link DLLs into a program. A program can only load DLLs at runtime: that's the nature of Dynamic Link Libraries. The only things you can statically link into a program are object files, which may be explicitly named to the linker or selectively extracted by the linker from a static library. Object files are always statically linked; dynamic libraries are always dynamically linked. Those are the only options.
But the fact that your program persists in trying to load its DLLs even though you succeed in linking it statically:
gcc -g -O2 -static -o comskip.exe ....
presents a more murky problem.
We would hope and expect it is impossible for a command like gcc ... -static -o prog ...
to produce an executable that has dynamic dependencies. But on Windows there is a way, thanks to Microsoft's historical
decision that name.lib
might as well be the name of the DLL import library
for name.dll
, as well as the name for the static library version of name.dll
.
my understanding is that the .lib files are needed to link statically
It sounds as if you're thinking that if you have e.g. "the" avcodec.lib
file that matches avcodec.dll
then you can use it to statically link avcodec.dll
into a program.
You can't. If there is an avcodec.lib
file that matches avcodec.dll
then avcodec.lib
might be
either:
avcodec
library, for static linkage only, whereas name.dll
is
a dynamic library version, for dynamic linkage only. They're both made from the same object files,
but in completely different ways. avcodec.dll
and avcodec.lib
are independent of each other.
You don't need avcodec.lib
to link a program with avcodec.dll
. You don't need avcodec.dll
to
link with avcodec.lib
. You'd never (intentionally) link a program with both.or avcodec.lib
might be:
avcodec.dll
with a program. The MS linker is unable to link with DLLs directly:
to do it indirectly, it needs an import library to be input to the
linker instead. The import library avcodec.lib
is
a link-time proxy for avcodec.dll
. It contains stubs representing the
symbols exported by avcodec.dll
, which the runtime linker will resolve to
the real symbols once avcodec.dll
is found and co-loaded with the program.As you see, the two different things that avcodec.lib
might be,
per the MS library naming convention, have entirely conflicting purposes :)
Library naming conventions observed by the Msys2/mingw64 linker.
To get Msys2/mingw64 linkages right, it helps to understand the names and types of file the linker can use as libraries of different sorts. We'll stick with the relevant avcodec
example library.
libavcodec.dll
: The canonical Msys2/mingw64 name for the avcodec
dynamic library.libavcodec.a
: The canonical Msys2/mingw64 name for the avcodec
static library. This file
is an archive produced by the GNU archiver ar
- canonical file extension .a
- filled with
object files for selective consumption in static linkage.libavcodec.dll.a
: The canonical Msys2/mingw64 name for the import library matching libavcodec.dll
. This
file is an ar
archive containing very small object files that serve as link-time
stubs for the symbols exported by libavcodec.dll
avcodec.dll.a
: A non-canonical Msys2/mingw64 name for an import library, possibly made to match libavcodec.dll
and possibly to match avcodec.dll
.avcodec.dll
: The canonical Microsoft name for the avcodec
dynamic library.avcodec.lib
: The canonical Microsoft name for the avcodec
static library. This file
is an archive produced by the Microsoft archiver LIB
- canonical extension .lib
- filled
with object files for selective consumption in static linkage.avcodec.lib
: Also the canonical Microsoft name for the import library matching avcodec.dll
. This
file is a LIB
archive containing very small object files that serve as link-time stubs for the symbols exported by name.dll
.
Since it is a LIB
archive, and contains object files, it strictly is a static library - it's just
no use for statically linking the avcodec
library! If the "real" static library avcodec.lib
exists at all,
it's somewhere else.How the Msys2/mingw64 linker resolves -l name
.
Unlike the Microsoft linker The Msys2/mingw64 linker does not actually need an import library to link against a DLL, but it will use an import library if it comes across one first. Either way, you still have dynamic, not static linkage: the program is runtime dependent on the DLL.
The linker gives preference to libraries that conform to its own naming conventions, but tries to accommodate the Microsoft naming convention as well.
By default the linker will allow linkage with DLLs , and prefer them to static libraries. To resolve -l name
,
it traverses its list of explicit and implicit search directories seeking candidate files.
In each directory it will accept the following files, in order of preference:
libname.dll, libname.dll.a, name.dll.a, name.dll, libname.a, name.lib
If the option -static
has been passed to gcc
then only the last two of those will
be accepted because all the rest imply dynamic linkage. As soon as the linker finds any candidates in a directory it picks the
preferred one, inputs it to the linkage and looks no further.
What's gone wrong
For a -static
linkage, libname.a
or name.lib
ought to be the genuine static library
that you want. But either of them might really be an import library and the linker would
be none the wiser, as long the file is indeed an archive containing object files.
With libname.a
, it's very improbable that the file will really be an import library
and not a static library, because the canonical import library will be libname.dll.a
. But with
the Microsoft-styled name.lib
, there is no such distinction: an import library could readily
infiltrate your linker search path somewhere where a real static library is supposed to be, or just be mistaken for a static
library when you work out the -L dir
options for library search.
One of those things has happened to you. In your -static
linkage, the linker accepts
avcodec.lib
as resolving -l avcodec
. It is in a search directory also containing avcodec.def
and avcodec.dll.a
. avcodec.def
is not any kind of library name (it is a gendef
output file) and avcodec.dll.a
will not be accepted to
resolve -l avcodec
in a -static
linkage. So avcodec.lib
is linked. It is in fact a MS-styled import library that
proxies for avcodec.dll
and your "statically linked" comskip.exe
accordingly attempts to load avcodec.dll
at runtime.
In unix-like OSes the linker can't be fooled like this, because it doesn't use import libraries, even optionally.
And the MS linker can't be fooled like this either, because it has no equivalent of the gcc
-static
option. The
Msys2/mingw64 linker can be fooled like this because it's the GNU/Linux linker, ported to Windows with added support
for import libraries.
From your linkage option -Lffmpeg-6.1.1-full_build-shared/lib
it appears that ffmpeg-6.1.1-full_build-shared/lib
is the search directory where this library confusion abides. Probably the pattern:
name.lib, name.def, name.dll.a
is repeated for all the other ffmpeg
libraries you are linking. If you didn't create this
setup yourself then I'd guess that the
name.lib
files have been deposited there to be import libraries for building with the MS Visual C++ toolchain and that the
name.dll.a
files have originated with commands like:
> gendef.exe [lib?]name.dll
> dlltool.exe -d [lib?]name.def -D [lib?]name.dll -l name.dll.a
and been deposited there to be import libraries for building with the Msys2/mingw64 GCC toolchain.
What to do?
To statically link your comskip.exe
you need to link the real ffmpeg
static
libraries for mingw64 GCC. You can install all these in MSYS2 from the mingw-w64-x86_64-ffmpeg package.
In the MSYS2 shell run:
$ pacman -S mingw-w64-x86_64-ffmpeg
Then link with -L C:\msys64\mingw64\lib
instead of -Lffmpeg-6.1.1-full_build-shared/lib
.
Of the non-ffmpeg libraries you are linking,
-largtable2 ... -lcomdlg32 -lgdi32 -lpthread -lm
you should find that C:\msys64\mingw64\lib
has static versions of all but libargtable2.a
. There is no pacman package for that.
Google tells me that source distributions of argtable2 are on Sourceforge
and github. You likely got it from one of those
sources and can build build the static library yourself with gcc
and ar
. Those sources however have seen
no development in ~10 years and I also spotted a more active github fork argtabl3 which you might check out.