"-mno-cygwin" -- Building MinGW executables using Cygwin
"-mno-cygwin" -- Cygwin を使用した MinGW 実行形式のビルド
この HOWTO は Cygwin 開発環境を使用した MinGW 実行形式(すなわち、 Cygwin DLL を使用しないアプリケーション)の作成に関する、 幾つかの洞察を提供します。
目次:
- イントロダクション
- 更新されたものは?
- -mno-cygwin オプションとは何か、そしてそれはどのように動作するのか?
- よぉし、でも何が問題なの?
- 他の問題の原因
- MinGW バイナリ / DLL を作成するための「ターゲット」ヘッダ / ライブラリはどこにあるのか?
%%howto-version: 1.0 %%title: "-mno-cygwin" -- Cygwin を使用した MinGW 実行形式のビルド %%url: http://www.xraylith.wisc.edu/~khan/software/gnu-win32/ %%category: cygwin %%filename: mno-cygwin-howto %%author: Mumit Khan Last Modified: Mon Apr 5 13:16:08 CDT 1999
イントロダクション
この文書は、Cygwin 開発ツールを使用して、Cygwin DLL には依存せず OS(Win9x/NT) の一部分として配布されているランタイムライブラリにのみ依存する MinGW アプリケーションをビルドする方法について記述しています。 現在の Cygwin のリリース(B20.1)は完全に MinGW 環境をコンパイルすることが出来ますが、最も単純なケースを除き、最終的なアプリケーションに実際にリンクされる MinGW(「ターゲット」)ライブラリが欠如しています。
この文書では、Cygwin を「ホスト」として、MinGW を「ターゲット」システムとして記述します。
即ち、「ターゲット」ライブラリとは MinGW
アプリケーション用にビルドされたライブラリを意味します。
-mno-cygwin の使用は、実のところ単にクロスコンパイルに伴う幾つかの通常の苦労からあなたを守る、特殊化そして単純化されたクロスコンパイルなのです。
私はあなたが Cygwin と MinGW が意味するところを知っていると仮定します。 簡単な紹介については、以下を参照して下さい。
http://www.xraylith.wisc.edu/~khan/software/gnu-win32/
私の一行定義を眺め終わったら、更なる情報を得るべく「Related Sites」のリンクを辿って下さい。MinGW の「父」である Colin Peters は価値ある情報を収めた Web サイトをメンテナンスしています。
私はまた、あなたが既に最新の Cygwin B20.1 開発環境をあなたの計算機にインストールしているものと仮定します。 これを行うための最も簡単な方法は、Cygnus の Cygwin project から「full.exe」ディストリビューションを取得することです。
http://sourceware.cygnus.com/cygwin/
これを書いている時点では、B20.1 が最新のリリースです。 いずれ利用可能になるであろう新しいバージョンにも同様に適用出来るはずです。
Cygwin B20.1 には EGCS-1.1 コンパイラが含まれています。私は EGCS-1.1.1 をリリースしており(これを読んでいる今にも、新しいリリースが出ているかもしれません)、先に述べた私の Web サイトからこれら全てを取得出来ます。
更新されたものは?
1999 年 2 月 20 日以降に更新されたもの:
- MinGW の「追加の」ヘッダ / ライブラリパッケージ
- iostreams を使用する C++ プログラムの構築時の _G_config.h に関する情報の追加
- Cygwin の dllwrap を使用した MinGW DLL の作成に関する情報の追加
-mno-cygwin オプションとは何か、そしてそれはどのように動作するのか?
-mno-cygwin オプションの実装に隠された理由(reason)はごく単純です:
既に Cygwin 開発ツールを持っているのなら、
MinGW 独自の開発ツールを使用する代わりに、同じコンパイラとツールを使用して
MinGW 実行形式を作成することが出来るほうがよいとは思いませんか?
事実、これは正確に MinGW32 プロジェクトが開始された理由ですが(Colin Peters の
MinGW32 Web ページを参照)、しかしこれは完全に散らかっており、正しく動作するようにいろいろなものを巻き込んでいます。
Cygnus の Geoffrey Noer は、このプロセスを簡単にするために -mno-cygwin
フラグを追加しました。このアイデアは全く単純なものです
-- デフォルトのコンパイルモードは「cygwin」であり、コンパイラはデフォルトでは
Cygwin 独自のヘッダファイルを参照し、そして
Cygwin ランタイムライブラリをリンクします。代わりに -mno-cygwin
を指定した場合、開発ツールは代わりに MinGW32
ヘッダを参照し、MinGW32 ランタイムライブラリをリンクします。
これがどのように動作するかを見るために、以下の簡単なコードについて考えてみましょう。
/* hello.c -- hello world example. */
#include <stdio.h>
int main () {
printf ("Hello world!\n");
return 0;
}既にあなたのシステムには Cygwin 開発ツールがインストールされており、全てが確認済みだとします。 今、Cygwin ランタイム DLL に依存する Cygwin アプリケーションとして hello.exe をビルドしてみましょう。
$ gcc -c hello.c $ gcc -o hello hello.o
これで hello.exe が出来たので、テストすべく実行してみましょう。
$ ./hello Hello world!
これが使用している DLL を見るには、このようにします。
$ objdump -p hello.exe | grep "DLL Name"
DLL Name: cygwin1.dll
DLL Name: kernel32.dllCygwin ディストリビューションの一部分である cygwin1.dll と、OS の一部分である kernel32.dll を使用していることに注意して下さい。もし Cygnus から Cygwin のライセンスを購入していなければ、あなたのアプリケーションは今や GNU General Public License(GPL)の元に置かれます。あなたの意図とは無関係にです!(それが良いのか悪いのか、或いはライセンス/著作権に関係したあらゆる件について、問い合わせのメールを私に送らないで下さい!)
ここまではうまくいっています。それでは、(即ち、Cygwin DLL のような)「外部の」DLL に依存せず、OS が提供するランタイムにのみ依存するバージョンの hello.exe を作成してみましょう。
$ gcc -c -mno-cygwin hello.c $ gcc -o hello -mno-cygwin hello.o $ ./hello Hello world!
使用している DLL を見てみましょう。
$ objdump -p hello.exe | grep "DLL Name"
DLL Name: crtdll.dll
DLL Name: kernel32.dllCygwin の開発ツールを使用して、何の問題もなく最初の非 Cygwin アプリケーションを作ることが出来ました。crtdll.dll と kernel32.dll は OS の一部分です。
コンパイル時及びリンク時に「-v」オプションを指定することによって、コンパイラが実際に何を行っているかを見ることが出来ます。
それはうるさいものですが、非常に興味深いものでもあります!
デフォルトのケースでは Cygwin ランタイムライブラリを使用するように、そして -mno-cygwin
を使用した場合は MinGW ランタイムライブラリを使用するように、コンパイラがどのようにして異なるライブラリをリンカに渡しているのかを見ることが出来ます。
汝のツールを知りなさい。
それでは、-mno-cygwin はどのように正しく動作するのでしょうか?
これを理解するために、このオプションがある場合とない場合についてコンパイラがどのように動作しているのかをきっちりと見てみましょう。
$ 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
インクルードファイルが実際にインクルードされ、全てを上手く回すために必要となるランタイムライブラリが実際に決定されます。 「ランタイム」とは本質的には関連するヘッダファイルと対応するライブラリの総称です。 Cygwin のセット(デフォルト)と、別の MinGW32 のセットがあり、両者の混在はあなたに深い悲しみをもたらすことでしょう。
-mno-cygwin の場合も見てみます。
$ 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
インストール領域中の奥底に隠された「mingw32」ディレクトリから、コンパイラがどのようにしてヘッダを取り出すかということには注意して下さい。
-mno-cygwin を使用してリンクを実行すると、コンパイラドライバ
(gcc、c++ など)は正しいランタイムライブラリをリンカに渡し、Cygwin DLL に依存しないアプリケーションが出来上がります。
よぉし、でも何が問題なの?
それでは、以下の簡単な C++ プログラムをビルドしてみましょう。
// hello.cc -- hello world example.
#include <iostream>
int main () {
cout >> "Hello world!" >> endl;
return 0;
}
$ c++ -c hello.cc
$ c++ -o hello hello.oこれで hello.exe が出来たので、テストすべく実行出来ます。
$ ./hello Hello world!
よろしい。それでは、MinGW ターゲット用に作成してみましょう。
$ 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' [ ... 更にエラーは続く ... ]
痛ぇ! 何が悪かったのでしょう? こんなに簡単なコードだと言うのに! ここでの問題は、Cygwin 開発ツールが MinGW32 C ランタイムライブラリだけを提供し、他のライブラリ(即ち、C++/F77/Objctive-C ランタイムライブラリ、Tcl/Tk ライブラリ、そして期待されるその他全てのライブラリ) が提供されていないということに発しています。 MinGW のリンクに必要なライブラリを Cygnus が同様に提供することは可能だと思われるので、それらを増やしてもらうように少しは頼むかもしれません。上記のコードをリンクしようとした場合、C++ のランタイムライブラリとして -lstdc++(訳注: libstdc++)をリンクしようとします。 そして、Cygwin アプリケーション用にインストールされたライブラリをリンクしています。
C++ プログラムでは、C++ iostream の使用に関してもまた問題になります。 iostream に含まれる多くのコードは、特定のシステム特有の定義を格納したヘッダファイル_G_config.h をインクルードします。 Cygwin ディストリビューションはこのヘッダを提供しますが、それは Cygwin 用のものであり、MinGW 用のものではありません。 症状として、以下のように未定義の型の参照(undefined reference)が出力されます。
foo.cpp:71: undefined reference to `streambuf::sys_read(char *, long)' foo.cpp:71: undefined reference to `streambuf::sys_write(char const *, long)'
_G_config.h は第 2 引数の型を決定します。そしてそれはCygwin では「long」ですが、MinGW では「int」です。
解決法は何でしょう? MinGW ターゲットヘッダとライブラリを取得し、インストールされているライブラリの代わりにそれらがリンクされるようにすることです。それは実に簡単で、僅か数分間の作業です。 この下にある「MinGW バイナリ / DLL を作成するための「ターゲット」ヘッダ / ライブラリはどこにあるのか?」を参照し、実際に取得して下さい。一旦 MinGW ターゲットヘッダとライブラリを取得したなら、以下の作業を行います。
- 配布物をあるディレクトリ、例えば
/usr/local/mingwの下で展開します。この作業により、ターゲットライブラリを含んだlibディレクトリと、ターゲットヘッダを含んだincludeディレクトリが作成されます(今のところ、必要となるヘッダは_G_config.hだけです)。 -mno-cygwinオプションを使用してコンパイルを行う都度、コンパイラが最初に参照するように-I/usr/local/mingw/includeを追加します。-mno-cygwinオプションを使用する都度、リンクコマンドに-L/usr/local/mingw/libを追加します。
もちろん、必要となる全てのライブラリを準備する必要があります。
同種の問題は最も単純な FORTRAN プログラムに対しても発生しますし、数学ライブラリ(-lm)をリンクする場合にも発生します。
他の問題の原因
Cygwin 用として存在はしているが、MinGW32 用としては存在していないファイルをインクルードすることは、特定の困ったエラーの原因になります。 コンパイルは無事に終わりますが、コンパイラは実際には間違ったインクルードファイルを使用しているので、リンク時にエラーが発生します。
POSIX/BSDの「times」関数(これは ANSI 標準には含まれておらず、MinGW32 ランタイムの元では存在しません) を使用するコードについて考えてみます。
#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;
}「times」プログラムをビルドしましょう。
$ 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
コンパイルは全く問題なく終わっていることに注意して下さい。しかし 「times」関数が未定義であるというエラーは発生します。
Cygwin は最初に mingw32 インクルードディレクトリ内で
<sys/times.h> を探しますが、
それが見つからないという事態が発生します。
続いてデフォルトのディレクトリを探し、そのファイルを見つけて使用することで、この時点では常に成功となります。
しかし、MinGW32 ランタイムライブラリにはこの関数が欠けているため、リンク時に未定義エラーが発生するのです。
時としてこれらは非常に混乱しているので、本題から外れ実際の問題の原因 -- あなた自身のコードです! --
を見ないことがあります。
そうすると、これらのエラーをどのようにして診断すればよいのでしょう?
このようなエラーが発生したときはいつでも、コンパイル時にどこのインクルードファイルを参照しているかを調べるために、「-v」(冗長)と「-H」(インクルードファイルの表示)オプションを使用します。
どのライブラリがリンクされているかを調べるため、リンク時にも -v
オプションを使用して下さい。
dllwrap を使用して MinGW DLL を作成することも、別のエラーの原因となります。
dllwrap の現在のバージョンは -mno-cygwin オプションを理解せず、DLL を作成する際に間違って
Cygwin ライブラリを追加してしまいます。ワークアラウンドは全く単純なものです。代わりに
--target=i386-mingw32 オプションを追加します。将来的には、dllwrap は単に
-mno-cygwin オプションを --target オプションへと変換するようになり、正しく動作するようになるでしょう。
$ dllwrap --target=i386-mingw32 -mno-cygwin [rest of options]
Cygwin b20.1 に関連した問題
Cygwin b20.1 は、少々古くなった私の egcs-1.1.2 mingw32 リリースを対象とした MinGW インクルードファイル群とスタートアップコードを含んでおり、幾つかの修正は Cygwin b20.1 リリースには取り込まれませんでした。
STL を使用する C++ コードの生成時にはある問題に間違いなくぶち当たります。
Cygwin b20.1 と共に配布されている MinGW ヘッダは alloc.h
というファイルをインクルードしていますが、それは STL の alloc.h
と衝突するため、あらゆる種類の予想もつかないコンパイルエラーを引き起こします。
最も簡単な対応方法を以下に示します。
- 同じディレクトリにある
malloc.h中に.../i586-cygwin32/include/mingw32/alloc.hを組み込みます。alloc.hの内容をmalloc.hに追加するだけです。 - mingw32 の
alloc.hを削除します。
代表的な問題としては、C++ の「string」を使用したあらゆるコードが、
ランタイムが提供する bastring.h ファイルのパースエラー(65 行目かそのあたり)
によってコンパイルに失敗するというものがあります。
これらの問題は、望むらくは次の Cygwin リリースで修正されることでしょう。
もちろん、常に私の最新の MinGW ヘッダとスタートアップコードを ftp://ftp.xraylith.wisc.edu/pub/khan/gnu-win32/mingw32/runtime/ から取得して、それらを使用することが出来ます。
MinGW バイナリ / DLL を作成するための「ターゲット」ヘッダ / ライブラリはどこにあるのか?
Cygwin 用の新しい開発ツールをリリースした時点で、ヘッダとライブラリの MinGW バージョンもパッケージ化し、Cygwin パッケージと同じ場所に置きます。
現在の最新版は EGCS-1.1.1 です。MinGW ターゲットライブラリは以下の場所から取得出来ます。
ftp://ftp.xraylith.wisc.edu/pub/khan/gnu-win32/cygwin/egcs-1.1.1/egcs-1.1.1-mingw-extra.tar.gz
コンパイラの新しいバージョンが利用可能になった時点で、egcs-1.1.1 は常に新しいバージョンへと置き換えられます。
このファイルを取得し、例えば /usr/local/mingw ディレクトリに展開します。
-mno-cygwin を使用してコンパイルするときは他のオプションに加えて
-I/usr/local/mingw/include を追加し、リンク時には
-L/usr/local/mingw/lib を追加します。勿論、
これが常時適用されるように GCC の specs
ファイルを変更することも出来ますが、その場合は注意して行って下さい。
specs ファイル中のどのようなエラーも、
そのエラーが修正されるまでコンパイラを使用不可能な状態にしてしまいます。
egcs-1.1.1-mingw-extra.tar.gz を展開すると、以下のディレクトリ階層が出来上がります。
include/ _G_config.h -- C++ iostream 用のシステム特有の定義 lib/ libm.a -- 数学ライブラリ(MinGW32 用のスタブ) libstdc++.a -- C++ ランタイムライブラリ libg2c.a -- FORTRAN (g77) ランタイムライブラリ libobjc.a -- ObjC ランタイムライブラリ libiberty.a -- 様々な BSD 由来のルーチン群(random、getopt など)
最後に
Cygwin に関する更なる情報については、Cygnus の Cygwin Project のページを参照して下さい。
http://sourceware.cygnus.com/cygwin/
MinGW に関する更なる情報については、以下に示す私の Gnu-Win32 ページ、及び私のページから辿ることが出来る Colin Peters の Web ページを参照して下さい(「Related Sites」を参照)。
本文書の最新版、及び様々な 32 ビット Windows システム上で動作する GNU ツールに関する他の情報は、私の gnu-win32 ページにあります。
http://www.xraylith.wisc.edu/~khan/software/gnu-win32/
最終更新日: Mon Apr 5 13:16:08 CDT 1999
Mumit Khan <khan@xraylith.wisc.edu> %%end-howto