This Mini‑HOWTO offers advice on installation, and explains the conventions which have been adopted by MinGW, (and also by Cygwin), to identify disparate versions of similarly named shared libraries, (DLLs), and so mitigate the “DLL Hell” which may arise, as a result of software dependencies on potentially incompatible versions of such DLLs.
The content herein is derived from an original web document, originally posted by Soren Andersen, (a.k.a. Perlspinr), and now accessible only via this WayBack Machine archive; this, in turn, was inspired by a no‑longer‑accessible posting, by Charles (Chuck) Wilson, on a mailing‑list discussing Portable Network Graphics (PNG) implementation; the original content has been generalized, to eliminate PNG‑specific references, and expanded upon, in a MinGW‑specific context.
When a PE  file,
(typically, but not restricted to,
an executable 
‘*.exe
 ’,
or a shared library 
‘*.dll
 ’
file), is created, the build‑time  linker,
(e.g. the MinGW linker ... not 
the dynamic linker ),
embeds references, within the PE  file itself,
to any shared libraries on which it depends.
Each such reference takes the form of just a DLL file name,
without  any directory path name qualification,
and there is no direct analogue for the ELF
‘rpath
’
feature.
When the Windows dynamic linker  creates a new process image, it first loads the PE  executable program file into memory. It then attempts to load each shared library, named as a DLL reference within the PE  file, (and iteratively, any further named DLL references within the loaded DLLs themselves), mapping each one into the process address space, and resolving symbol references across DLL boundaries; only after all named DLLs have been loaded, and all symbol references successfully resolved, will execution of the process commence.
To locate each DLL, named in PE  file references, the MS‑Windows dynamic linker will search in each of the following directories, in turn; (this search will continue, through the directory sequence, only as far as is necessary to locate the first  DLL file, with a name which matches the reference):
GetSystemDirectory()
function.
GetWindowsDirectory()
function.
PATH
environment variable;
(note that this is the path searched for executables themselves;
the LIBPATH
environment variable is not considered,
and LD_LIBRARY_PATH
— a standard environment variable
which is commonly associated with ELF  shared libraries —
has no defined purpose in the MS‑Windows environment).
Note that each uniquely named DLL file, irrespective of the directory path from whence it is loaded, will be mapped into the process address space only once. Furthermore, if the instance of each named DLL, which is located first in the above directory search sequence, fails to resolve all entry points  which it is expected to provide, process execution will fail; the search will not  be resumed, even if a similarly named DLL file, from a later directory in the search sequence, may be an alternative version, from which the missing entry points  could have been resolved.
It is important to ensure that,
if an application requires a particular version of any DLL,
that the correct DLL is installed in a location whence it will be identified
early in the preceding search sequence.
In a conventional MinGW installation,
(typically in C:\MinGW
),
this is normally achieved by installation of both 
the *.exe
files, and  their associated DLLs,
in the common C:\MinGW\bin
directory,
so that DLL identification is completed in accordance with rule (1), above.
Alternatively,
for any application whose *.exe
files are not 
installed in the C:\MinGW\bin
directory,
(since C:\MinGW\bin
will typically be listed within
the user’s PATH
environment variable),
MinGW DLLs may be identified in accordance with rule (5).
When applications depend on this DLL identification stratagem,
it is strongly  recommended that all 
MinGW DLLs be kept fully up to date,
to ensure that compatibility is maintained,
as explained below,
for all  dependent applications,
regardless of age.
The single value, as assigned as a MinGW shared library version number, is derived from an effective GNU libtool current:revision:age triplet, which itself, is managed in accordance with the convention described in libtool‑versioning section of the GNU libtool manual:
[...] libtool library versions are described by three integers:
current
  interface.
current
-
age
 
to current
.
These current:revision:age
attributes are assigned,
by the maintainer of the library,
as specified in the immediately following section of the GNU libtool manual:
Here are a set of rules to help you update your library version information:
0:0:0
’
for each libtool library.
revision
  (i.e.
‘current:revision:age
 ’ becomes
‘current:revision
+
 1:age
 ’ ).
current
,
and set revision
  to 0
.
age
.
age
  to 0
.
Never try to set the interface numbers so that they correspond to the release number of your package. This is an abuse that only fosters misunderstanding of the purpose of library versions. [...]
The following explanation may help [you] to understand the above rules a bit better: consider that there are three possible kinds of reactions from users of your library to changes in a shared library:
revision
  only,
don’t touch current
 
[or] age
.
revision
  to 0
,
bump [i.e. increment both] current
 
and age
.
current
,
set [both] revision
 
and age
  to 0
.
In the above description, programs using the library in question may also be replaced by other libraries using it.
To derive the single‑valued MinGW shared library version number,
from the GNU libtool compatible
current:revision:age
  triplet,
we adopt the convention originally suggested by Gary Vaughan,
in a posting to the Cygwin mailing‑list,
to the effect that the effective shared library version should be
set equal to the version number of the oldest ABI  version
supported by the shared library;
this is equivalent to the result of the calculation
current
-
age
,
taking the individual values of current
,
and age
  from the libtool triplet.
(Note that this does not require  use of libtool
for maintanence of the shared library;
it is sufficient to adopt the libtool numbering convention,
and to calculate
current
-
age
 
manually).
To further illustrate the evolution of MinGW shared library versions,
let us consider the development life‑cycle of
a hypothetical library, libfoo.dll
,
for which the most recent release corresponds to a GNU libtool
current:revision:age
  triplet
of 5:4:3
;
this indicates that the current ABI  version of
this hypothetical library is 5
,
and that this version is fully backwardly compatible  with
each of the three  preceding releases,
with ABI  version numbers 4
,
3
, and 2
;
thus, the MinGW library version,
computed as current
-
age
,
will be 2
,
yielding a versioned library name of libfoo-2.dll
;
it may be observed that this version‑indicating name corresponds to
the oldest ABI  version which is fully compatible with
the current ABI  version 5
release.
There are many evolutionary paths,
which libfoo‑2.dll
may have followed,
to become the equivalent of a libtool‑managed 5:4:3
release;
the following example represents just one such possible path:
0:0:0
, yielding a computed
current
-
age
 
value of 0
-
0
,
(or simply 0
);
thus, the MinGW designation for the initial release
will be libfoo‑0.dll
.
revision
  is incremented,
at each release,
through 0:1:0
, 0:2:0
, ...
,
but, since neither current
,
nor age
  is changed,
the MinGW release designation remains as libfoo‑0.dll
.
This is correct,
because the interface  remains unchanged from
the initial  release;
programs linked against the initial release may continue to use
this libfoo‑0.dll
,
as a drop‑in replacement for the original,
while benefitting from any bug‑fixes
which may have been applied in the newer releases.
libfoo‑0.dll
,
corresponding to (say) libtool release 0:4:0
,
a new function entry point  is added,
without  changing the established interface
in any way.
This introduces a forwardly incompatible 
change in the API,  (because any new application
which depends on the new entry point  will be
incompatible with any earlier release of libfoo‑0.dll
);
however, the API  remains backwardly compatible 
with previous releases, (because none  of the
previously existing entry points  exhibit
any change in behaviour).
To reflect this change in compatibility,
the libtool current
  version number
is incremented,
while resetting the revision
 
to 0
,
(to account for the addition of the new entry point );
at the same time, age
 
is incremented in lock‑step,
(because backward  compatibility,
with the preceding release, is preserved).
Consequently, the libtool release identification becomes 1:0:1
,
since the result of computing
current
-
age
,
(which now becomes 1
-
1
),
remains equal to 0
, and thus,
the MinGW library designation remains as
libfoo‑0.dll
.
Once again, this is correct; in spite of the change
in libtool current
  release number,
the oldest  value of current
 
release, with which this release remains backwardly  compatible,
is still 0
.
libfoo‑0.dll
,
at libtool release point 1:0:1
,
one of the publicly visible entry point  functions
is deemed to have become obsolete, and is removed.
This represents another change to the public interface,
so once again the libtool current
 
release number must be incremented,
and the revision
  reset;
however, this is not  a backwardly
compatible  change, so, for this release,
age
  is reset to 0
,
rather than being incremented.
The effect of this is that the libtool release number advances
to 2:0:0
, and the MinGW release number, computed as
current
-
age
,
advances to 2
, resulting in a new MinGW library designation
of libfoo‑2.dll
.
Note that this is, once again, correct:
the libtool current
  release number has advanced,
to 2
; this release is no longer backwardly 
compatible with any other release, older than itself,
and the MinGW release number has also advanced accordingly;
this libfoo‑2.dll
is not  suitable for
use as a drop‑in replacement for libfoo‑0.dll
,
and the DLL file name has been changed, to prevent any such misuse.
libfoo‑2.dll
,
may proceed as described in (2), above, thus requiring only
the libtool revision
  to be incremented,
without  affecting the MinGW release number,
in any way.
These may be interspersed with three further cycles,
similar to that described in (3), above,
in which any number of new entry points  are added,
but none  are removed or modified;
after the third such type (3) release,
the libtool release number will have advanced through
3:0:1
, 4:0:2
, and finally 5:0:3
.
If this is then followed by by four further type (2) releases,
there will be four further increments in
the libtool revision
,
ultimately advancing the libtool release number to 5:4:3
;
at this stage in the release cycle sequence, the
current
-
age
 
computation will continue to yield a MinGW release number of 2
,
and the MinGW library will continue to be named libfoo‑2.dll
.
It may be observed that,
following the preceding sequence of release cycles,
whereas the libtool release number is able to convey the information that
the current library version implements revision 4
of
the implementation of version 5
of the interface,
and that this implementation is fully backwardly compatible 
with version 2
of this interface,
the MinGW release number cannot adequately convey any more than
the last of these pieces of information.
Although this limitation may appear to be problematic,
in practice it isn’t, provided  the installed
version of libfoo‑2.dll
is its most recently
released distribution;
unlike ELF dynamic linkers,
the PE dynamic linker  simply isn’t smart enough
to select a DLL on the basis of a range  of supported
interface  versions,
so the best we can hope for is that the selected library,
as named for its oldest  supported version,
covers the required range;
the most effective assurance that we can have for this
is that the selected library is the most recently released distribution,
with the specified name.
“DLL Hell” arises when two identically named shared library files provide different (incompatible) APIs  ... perhaps even incompatible versions of fundamentally the same API ; a common cause is that installation of some third‑party software product has overwritten an installed DLL file with an obsolete version.
Sometimes, a particular software product requires a particular version of a specific DLL, with which the most recent version of that DLL is not backwardly compatible,  (because the developer of that DLL may not have exercised good version control discipline). To avoid this kind of issue, MinGW has adopted a DLL version management discipline, conforming to the following conventions:
Adoption of these conventions ensures that, if the most recent release of each, and every required MinGW DLL is installed, at an appropriate location within the DLL directory search path, then, on account of the promise of backwards compatibility,  applications which are dependent on any releases of these DLLs will continue to operate as intended. Additionally, it allows releases of mutually incompatible, similarly named (but for the version identifier) DLLs to co‑exist, within the DLL search path, thus ensuring that applications which may depend on older, incompatible DLL versions, may continue to operate correctly.
Unfortunately, the conventions alone cannot  prevent any user, or third‑party package installer, from replacing the most recent MinGW release of any DLL with an older release, (or with an incompatible third‑party DLL with the same name). Since forward compatibility  is never  promised, for an older MinGW DLL release used in conjunction with an application which may be dependent on a more recent release, (nor is there any  expectation of any form of compatibility  from any  third‑party DLL), it becomes incumbent upon the user, to ensure that only  the most recent releases of MinGW DLLs are (and remain) installed.