Home Page: | http://www.xraylith.wisc.edu/~khan/software/gnu-win32/ |
Author: | Mumit Khan |
Created: | Sun Feb 21 13:19:34 1999 |
Updated: | Mon Apr 5 14:28:08 1999 |
This howto provides some insight into creating Mingw executables, ie., applications that do not rely on Cygwin DLL, using Cygwin development environment.
TOC: - Introduction. - What's new? - What is this -mno-cygwin option and how does it work? - Yeah, but what's the problem? - Other sources of problems. * Cygwin b20.1 related problems - Where to get the "target" headers/libraries to create Mingw binaries/DLLs. Last Modified: Mon Apr 5 13:16:08 CDT 1999
============ Introduction. This document describes how to use Cygwin development tools to build Mingw applications that do not depend on Cygwin DLL and only depend on runtime libraries distributed as part of the OS (Win9x/NT). The current Cygwin release, B20.1, is fully capable of compiling to Mingw environment, but lacks the Mingw ("target") libraries to actually link the final application in all but the simplest cases. In this document, I'll refer to Cygwin as the "host" and Mingw as the "target" system; eg., "target" libraries imply the libraries built for Mingw applications. Using -mno-cygwin is really just a specialized and simplified case of cross-compilation, where you're shielded from some of the usual pains of cross-compilation. I'll assume that you know what Cygwin and Mingw means. If you want a quick introduction, see: http://www.xraylith.wisc.edu/~khan/software/gnu-win32/ After you look through my one-liner defintions, please follow the links in the "Related Sites" for more information. Colin Peters, the "father" of Mingw, maintains a web site with valuable information. I'll also assume that you already have at least Cygwin B20.1 development environment installed on your computer. The easiest way to do so is to get the "full.exe" distribution from Cygnus Cygwin project: http://sourceware.cygnus.com/cygwin/ As of this writing, B20.1 is the latest release. Newer versions, as they become available, should equally apply. Cygwin B20.1 comes with the EGCS-1.1 compiler. I have since released EGCS-1.1.1 (by the time you read this, there'll probably be a newer release), and you can get all of this from my web site cited above.
============ What's new? New since last posting of Feb-20-1999: - update mingw "extra" headers/libraries package - add info on _G_config.h when building C++ programs using iostreams - add info on creating Mingw DLLs using Cygwin dllwrap.
============ What is this -mno-cygwin option and how does it work? The reason behind implementing the -mno-cygwin option is quite simple: since you already have the Cygwin development tools loaded, wouldn't it be nice to be able to create Mingw executables using the same compilers and tools instead of having to load yet another set of Mingw-specific development tools? In fact, this is precisely how the Mingw32 project started (cf: Colin Peters Mingw32 web page), but it was quite messy and involved to get things to work out correctly. Geoffrey Noer of Cygnus later added the -mno-cygwin flag to make this process easier. The idea is quite simple -- the default compilation mode is "cygwin", and the compiler by default looks for header files that are Cygwin specific and also links in the Cygwin runtime libraries. When instead you specify -mno-cygwin, the development tools instead look for Mingw32 headers and links in the Mingw32 runtime libraries. To see how this works, consider the following trivial piece of code: /* hello.c -- hello world example. */ #includeint main () { printf ("Hello world!\n"); return 0; } Let's say that you've installed Cygwin development tools on your system and everything checks out. Now you want to build hello.exe as a Cygwin application which will depend on Cygwin runtime DLL. $ gcc -c hello.c $ gcc -o hello hello.o This will create hello.exe and you can now run it to test. $ ./hello Hello world! To see what DLLs it's using: $ objdump -p hello.exe | grep "DLL Name" DLL Name: cygwin1.dll DLL Name: kernel32.dll Note that you're using CYGWIN1.DLL that is part of the Cygwin distribution and KERNEL32.DLL, which is part of the OS distribution. If you have not purchased a Cygwin license from Cygnus, your application now falls under the GNU General Public License (GPL), whether you intended that or not! (Please don't send me email on whether that is good or bad or anything related to the topic of licensing/copyright!) So far so good. Now, you want to build a version of hello.exe that only depends on OS-supplied runtime without any dependence on "external" DLLs (eg., Cygwin DLL). $ gcc -c -mno-cygwin hello.c $ gcc -o hello -mno-cygwin hello.o $ ./hello Hello world! To see what DLLs it's using: $ objdump -p hello.exe | grep "DLL Name" DLL Name: crtdll.dll DLL Name: kernel32.dll You've just created the first non-cygwin application using the Cygwin development tools without any fuss at all. Both CRTDLL.DLL and KERNEL32.DLL are part of your OS distribution. You want to specify "-v" option when compiling and linking to see what the compiler is really doing. It's noisy, but very instructive! You'll see how the compiler is passing different libraries to the linker so that you get the Cygwin runtime library in the default case, and the Mingw runtime libraries when using -mno-cygwin. Know thy Tools. So, how exactly does -mno-cygwin work? To understand that, let's take a look closer took at the compiler does without and with this option. $ gcc -c -H hello.c C:\cygnus\cygwin-b20\H-i586-cygwin32\bin\..\lib\gcc-lib\i586-cygwin32\egcs-2.91.57\..\..\..\..\i586-cygwin32\include\stdio.h C:\cygnus\cygwin-b20\H-i586-cygwin32\bin\..\lib\gcc-lib\i586-cygwin32\egcs-2.91.57\..\..\..\..\i586-cygwin32\include\_ansi.h C:\cygnus\cygwin-b20\H-i586-cygwin32\bin\..\lib\gcc-lib\i586-cygwin32\egcs-2.91.57\..\..\..\..\i586-cygwin32\include\sys/config.h C:\cygnus\cygwin-b20\H-i586-cygwin32\bin\..\lib\gcc-lib\i586-cygwin32\egcs-2.91.57\include\stddef.h C:\cygnus\cygwin-b20\H-i586-cygwin32\bin\..\lib\gcc-lib\i586-cygwin32\egcs-2.91.57\include\stdarg.h C:\cygnus\cygwin-b20\H-i586-cygwin32\bin\..\lib\gcc-lib\i586-cygwin32\egcs-2.91.57\..\..\..\..\i586-cygwin32\include\sys/reent.h Here you can see what include files are actually being included, and these really determine what runtime library you must use to make it all work. The "runtime" is essentially the set of related header files and the corresponding libraries; there's one set for Cygwin (the default), and another for Mingw32 and mixing these two will bring you much grief. Now for -mno-cygwin case: $ gcc -mno-cygwin -c -H hello.c C:\cygnus\cygwin-b20\H-i586-cygwin32\bin\..\lib\gcc-lib\i586-cygwin32\egcs-2.91.57\..\..\..\..\i586-cygwin32\include\mingw32\stdio.h C:\cygnus\cygwin-b20\H-i586-cygwin32\bin\..\lib\gcc-lib\i586-cygwin32\egcs-2.91.57\..\..\..\..\i586-cygwin32\include\mingw32\stddef.h Note how the compiler is now picking up the headers from a "mingw32" directory buried deep within the installation area. When you link using the -mno-cygwin, the compiler driver (gcc, c++, etc) pass the right runtime library to the linker and you end up with an application that does not depend on the Cygwin DLL. ============ Yeah, but what's the problem? Now, let's build the following trivial C++ program: // hello.cc -- hello world example. #include int main () { cout << "Hello world!" << endl; return 0; } $ c++ -c hello.cc $ c++ -o hello hello.o This will create hello.exe and you can now run it to test. $ ./hello Hello world! Great. Now let's build it for the Mingw target: $ c++ -c -mno-cygwin hello.cc $ c++ -o hello -mno-cygwin hello.o C:\cygnus\cygwin-b20\H-i586-cygwin32\bin\..\lib\gcc-lib\i586-cygwin32\egcs-2.91.57\..\..\../libstdc++.a(iostream.o)(.text+0x113):iostream.cc: undefined reference to `_ctype_' C:\cygnus\cygwin-b20\H-i586-cygwin32\bin\..\lib\gcc-lib\i586-cygwin32\egcs-2.91.57\..\..\../libstdc++.a(iostream.o)(.text+0x549):iostream.cc: undefined reference to `_ctype_' C:\cygnus\cygwin-b20\H-i586-cygwin32\bin\..\lib\gcc-lib\i586-cygwin32\egcs-2.91.57\..\..\../libstdc++.a(iostream.o)(.text+0x195d):iostream.cc: undefined reference to `_impure_ptr' C:\cygnus\cygwin-b20\H-i586-cygwin32\bin\..\lib\gcc-lib\i586-cygwin32\egcs-2.91.57\..\..\../libstdc++.a(iostream.o)(.text+0x196b):iostream.cc: undefined reference to `_impure_ptr' C:\cygnus\cygwin-b20\H-i586-cygwin32\bin\..\lib\gcc-lib\i586-cygwin32\egcs-2.91.57\..\..\../libstdc++.a(stdstrbufs.o)(.text+0x32):stdstrbufs.cc: undefined reference to `_impure_ptr' C:\cygnus\cygwin-b20\H-i586-cygwin32\bin\..\lib\gcc-lib\i586-cygwin32\egcs-2.91.57\..\..\../libstdc++.a(streambuf.o)(.text+0x34c):streambuf.cc: undefined reference to `__errno' [ ... more errors ... ] Ouch! What went wrong here? It's such a trivial piece of code! The trouble here is that Cygwin development tools provide *only* the Mingw32 C runtime libraries, and nothing else (eg., C++/F77/ObjC runtime libraries, Tcl/Tk libraries, and a few others folks expect). I suppose Cygnus could provide all the libraries needed for Mingw linking as well, but we may be asking a bit too much of them. When we try to link the above code, it's trying to link to -lstdc++, the C++ runtime library, and it's linking against the installed one meant for Cygwin application. There is also a problem with C++ programs that use the C++ iostreams; most of the iostreams code include _G_config.h, a header file that has certain system-specific definitions. The Cygwin distributions provides this header, but it's tailored for Cygwin, not for Mingw. A symptom is that you'll get undefined references of the type: foo.cpp:71: undefined reference to `streambuf::sys_read(char *, long)' foo.cpp:71: undefined reference to `streambuf::sys_write(char const *, long)' The _G_config.h determintes the type of the 2nd argument, and it's ``long'' for Cygwin, but for ``int'' for mingw. What's the solution? Get the Mingw target headers and libraries yourself and make sure you link against those instead of the installed libraries. It's really easy, and takes just a few minutes. See "Where to get the target headers/libraries to create Mingw binaries/DLLs" below on how and where to get these. Once you have the Mingw target headers and libraries, do the following: - untar the distribution under a directory, say /usr/local/mingw. This will create a lib directory containing the target libraries and include directory containing target headers (currently the only header needed is _G_config.h). - Add the -I/usr/local/mingw/include to all compilation when using the -mno-cygwin option so that the compiler looks there first. - Add the -L/usr/local/mingw/lib to all your link commands when using -mno-cygwin option. and you should be all set provided of course all the libraries are there that you need. A similar problem occurs even for the simplest of FORTRAN programs or any problem that links against the math library (-lm). ============ Other sources of problems. One particular vexing source of error is when you include a file that exists for Cygwin, but not for Mingw32; the compilation goes ok, but the compiler is really using the *WRONG* include file and you get link time errors. Let's say you have some code that uses the POSIX/BSD "times" function which is not part of the ANSI standard and does not exist under Mingw32 runtime. #include #include int main () { struct tms time_info; times (&time_info); printf ("user_time = %d, system_time = %d\n", time_info.tms_utime, time_info.tms_stime); return 0; } Now build the "times" program: $ gcc -c -mno-cygwin times.c $ gcc -o times -mno-cygwin times.o times.o(.text+0x34):times.c: undefined reference to `times' collect2: ld returned 1 exit status Notice that the compilation goes just fine, but you get an undefined reference to the "times" function. What happens is that Cygwin first looks in the mingw32 include directory the file and it can't find it; it then looks at the default directory and does find it and uses it and everything is fine at this point. However, at link time, the Mingw32 runtime library lacks this function and you get an undefined error. Sometimes these are so confusing that you may get sidetracked and not look at the real source of the problem -- your own code! So, how do you diagnose these errors? Whenever you get such errors, use the '-v' (verbose) and '-H' (show include files) options when compiling to see where include files are coming from. Then use -v option when linking to see what libraries are being linked in. Another source of error is creating Mingw DLLs using dllwrap. The current version of dllwrap does not know the -mno-cygwin option and will incorrectly add Cygwin libraries when creating DLLs. The workaround is quite simple: add the --target=i386-mingw32 option instead. In the future, dllwrap will simply translate the -mno-cygwin option to the --target option and it will just work. $ dllwrap --target=i386-mingw32 -mno-cygwin [rest of options] ************ Cygwin-b20.1 related problems Cygwin b20.1 includes mingw includes and startup code that is a bit out of date with respect to my egcs-1.1.2 mingw32 releases and some of the fixes did not get into the Cygwin b20.1 release. One problem that you'll definitely run into is when building C++ code that uses STL; Mingw headers, as distributed with Cygwin b20.1, includes a file called alloc.h, which conflicts with STL's alloc.h and causes all sorts of bizarre compilation errors. The easiest fix is to the following: a. incorporate the .../i586-cygwin32/include/mingw32/alloc.h into malloc.h in the same directory. Just add the stuff in alloc.h to to malloc.h. b. delete mingw32 alloc.h. A typical symptom is when any code that uses C++ ``string'' fails to compile with a parse error in the runtime supplied bastring.h file (line 65 or so). These problems will hopefully be fixed in the next Cygwin release. You can of course always get my latest mingw headers and startup code from ftp://ftp.xraylith.wisc.edu/pub/khan/gnu-win32/mingw32/runtime/ and use those. ============ Where to get the "target" headers/libraries to create Mingw binaries/DLLs. When I release new development tools for Cygwin, I also package up the Mingw version of the headers and libraries in the same place where you got the Cygwin package. The latest version is now EGCS-1.1.1, and you can get the Mingw target libraries from: ftp://ftp.xraylith.wisc.edu/pub/khan/gnu-win32/cygwin/egcs-1.1.1/egcs-1.1.1-mingw-extra.tar.gz When newer versions of the compiler is available, replace egcs-1.1.1 with whatever the current version is. Get this file, and unpack in a directory, say /usr/local/mingw; when you compile with -mno-cygwin, add -I/usr/local/mingw/include, and when you link, add -L/usr/local/mingw/lib with the other options. You can of course alter the GCC specs file to do this automatically, but be careful when you do so. Any error in the specs file will render your compiler useless until you fix the error. After unpacking the egcs-1.1.1-mingw-extra.tar.gz, you'll have the following directory hierarchy: include/ _G_config.h -- System-specific definitions for C++ iostreams lib/ libm.a -- The math library (just a stub for Mingw32) libstdc++.a -- C++ runtime library libg2c.a -- FORTRAN (g77) runtime library. libobjc.a -- ObjC runtime library. libiberty.a -- various BSD'ish routines (random, getopt, etc) ============ THE END For more information about Cygwin, see Cygnus's cygwin project page: http://sourceware.cygnus.com/cygwin/ For more information about Mingw, see my Gnu-Win32 page below and also look at Colin Peters' web page reachable from mine (cf: "Related Sites"). Latest version of this documentation, and other information related to GNU tools on various types of windows32 system, is available from my gnu-win32 page: http://www.xraylith.wisc.edu/~khan/software/gnu-win32/ Last Modified: Mon Apr 5 13:16:08 CDT 1999 Mumit Khan