delorie.com/howto/cygwin/mno-cygwin-howto.html
|
search
|
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. */
#include <stdio.h>
int 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 <iostream>
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 <stdio.h>
#include <sys/times.h>
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 <sys/times.h> 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 <khan@xraylith.wisc.edu>