2012-06-10: Published on my blog at berlios.de.
2017-12-22: I discovered a copy of this text on my laptop.
A common problem with the MinGW gcc is the C (runtime) library msvcrt.dll
used by default. If you combine object files or DLLs compiled with MinGW and Visual Studio 20XX, you end up with executables linking to multiple C libraries. All sort of nasty misbehaviour can occur. For instance, you run into this problem, if you compile python modules, because python uses recent versions of Visual Studio. Python 2.7 is compiled using VS 2008 professional using msvcr90.dll
Older versions of gcc from the GPL2 age were not able to utilise the non system libraries msvcrXX.dll for legal reasons, but since gcc switched to GPLv3 it is legally possible to distribute a libgcc linked against the C-runtime libraries provided by Microsoft. Unfortunately, it is still not well documented how to actually do it.
Actually, you need to perform 3 tasks:
I'll explain how you can patch your MinGW installation to do all 3 tasks automatically.
Recent builds of MinGW provide everything you need. Look at the lib
subdirectory of your MinGW installation. If it contains the files libmsvcrXX.a
and libmoldnameXX.a
, where XX is the runtime version number, then your installation can be used.
Now you need to instruct the compiler to use these files instead of the default files libmoldname.a
and libmsvcrt.a
. In addition you need to define the preprocessor macro __MSVCRT_VERSION__
. There are many ways to do that.
%rename cpp msvcrXX_cpp %rename cc1plus msvcrXX_cc1plus *cpp: %(msvcrXX_cpp) -D__MSVCRT_VERSION__=0x0900 *cc1plus: %(msvcrXX_cc1plus) -D__MSVCRT_VERSION__=0x0900 *libgcc: %{mthreads:-lmingwthrd} -lmingw32 %{shared-libgcc:-lgcc_s} -lgcc -lmoldname90 -lmingwex -lmsvcr90
Usually you add a manifest using the tool mt.exe
. It is available as part of Visual Studio but also included in various versions of the platform SDK. If you add a manifest, mt.exe
adds a special resource of type RT_MANIFEST
to your DLL or executable. Usually the manifest of an exe is resource number 1 and the manifest of a DLL is resource number 2. This knowledge leads to a second possibility for adding an manifest. The GNU linker ld.exe
is able to place a resource into the generated DLL or executable. You can simply link the manifest.
This is the usual manifest of a program using msvcr90.dll. Look at the documentation in MSDN for details.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> <security> <requestedPrivileges> <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel> </requestedPrivileges> </security> </trustInfo> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="Microsoft.VC90.CRT" version="9.0.21022.8" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity> </dependentAssembly> </dependency> </assembly>
Now follow the description of David Cournapeau and create two resource files, msvcr90.dll.rc
for DLLs and msvcr90.exe.rc
for executables.
msvcr90.dll.rc
#include "winuser.h" 2 RT_MANIFEST msvcr90.manifest
msvcr90.exe.rc
#include "winuser.h" 1 RT_MANIFEST msvcr90.manifest
Compile these files into *.res files:
windres --input msvcr90.dll.rc --output msvcr90.dll.res --output-format=coff windres --input msvcr90.exe.rc --output msvcr90.exe.res --output-format=coff
To link the correct *.res-file we have again several options.
%rename link_gcc_c_sequence msvcrXX_link_gcc_c_sequence *link_gcc_c_sequence: %(msvcrXX_link_gcc_c_sequence) %{shared|mdll: msvcr90.dll.res%s} %{!shared: %{!mdll: msvcr90.exe.res%s}}
Microsoft decided in its infinite wisdom, that the POSIX specification is unsafe and needs to be improved. Especially if you call a function with an invalid parameter, what you really want is to terminate the program using Dr. Watson. And Microsoft implemented Dr. Watson starting with msvcr80.dll
Since msvcr80.dll you need to set an invalid parameter handler within each DLL or EXE, if you want standard behaviour of POSIX functions. This requires either modification of the source or another trick.
Fortunately it is possible to install an invalid parameter handler by simply linking an object file libcontinue_on_invalid_param.a
, that was created using C++ and contains nothing but an initialiser with the desired side effect. This is the source of continue_on_invalid_param.cpp. The initialiser and the invalid parameter handler are plain C functions. This way, we don't need the C++ runtime libraries. Compile it using the command line
g++ -D__MSVCRT_VERSION__=0x800 -c continue_on_invalid_param.cpp -o libcontinue_on_invalid_param.a
Why do I name the output libcontinue_on_invalid_param.a
instead of continue_on_invalid_param.o
. Because libtool sucks! Libtool tries to improve the link order given in the gcc specs file and sorts *.o files after the libraries. The result are unresolved symbols. Fortunately gcc does not care if a *.a
file is really an archive.
Again you have to modify the gcc specs file and add a -lcontinue_on_invalid_param
option:
*libgcc: -lcontinue_on_invalid_param %{mthreads:-lmingwthrd} -lmingw32 %{shared-libgcc:-lgcc_s} -lgcc -lmoldname90 -lmingwex -lmsvcr90
Following the previously given instructions you are able to build simple programs ("hello world"). But you will soon discover, that you need to rebuild the mingw runtime library.
You need at least:
and for gcc 4.7 you need another patch from the fedora fc17 mingw32-runtime source rpm. You may need to build the new runtime package two times: first for msvcrt.dll and then for msvcr90.dll. The reason is a header file bug in older mingwrt versions, that breaks compiling for msvcr90.dll.
If you replace the mingw runtime with your newly compiled version, you will not be able to link against the old msvcrt.dll any longer. Therefore you probably want to create a new default gcc spec file, that incorporates the changes. I made a small python script mingw32-patch-gcc4msvcrXX.py, that creates such a spec file for you and also creates the manifest resources files.
mingw32-patch-gcc4msvcrXX.py
90
mingw32-patch-gcc4msvcrXX.py
60
A last hint: If possible I avoid MSYS and use the MinGW cross compiler that comes with Fedora Linux, because MSYS is very slow compared to Linux. The compiler patches described here also apply to the Fedora MinGW compiler. And rebuilding RPMs is realy simpl. I rebuild all mingw*-RPMs from Fedora 16 for msvcr90.dll.