MinGW に GCC 4.4.0 を導入する このエントリーをはてなブックマークに追加

otoco のコアデータの仕様がだいぶ形になってきたので、いよいよ実装を開始しました。本当はメインマシンに Linux 環境を整え直してそっちで開発を進めたいのですが、現状お金をもらってメインでやらせて頂いている仕事が Windows 環境での開発なので、並行して作業を行いやすいよう、 Windows 向けのバイナリを生成する環境として検討している MinGW を導入し、とりあえずはこちらで開発を進めてみることにしました。

まだビルドが通る状態ですらないので、とりあえずミニマムケースでテストコードを書きながら、手探り状態で実装を進めているのですが、はて、 int32_t などの型の typedef が定義されている stdint.h の C++ 版である <cstdint> を使う場合、これらの型名は std::int32_t になるのやら、それとも ::int32_t になるのやら、どっちだったかなぁと思い、テストプログラムに

#include <cstdint>

と書いてみたものの、これがさっぱり通らない。おおそうか、そもそも <cstdint> なんて存在しないのか、などと Twitter でつぶやいてみましたところ、ご親切な方から VC10 (Visual Studio 2010 の C/C++ コンパイラのことですね) にはありますよ、とのお返事が。

さらにもう一つ気がかりなことに、 hashmap 的なものってもう標準化されていなかったかなぁと思いつつ調べてみたところ、 C++0x であれば std::unordered_map が使えると言うことが分かったので、早速これも試してみようとテストプログラムに

#include <unordered_map>

と書いてみたところ、やっぱりこれもさっぱり通らない。で、どちらも MinGW のインストールディレクトリ以下にヘッダファイルが存在するのか検索してみると、なるほど確かにファイル自体が存在しない。

そもそも GCC は C++0x に対応しているのか? と調べてみると、軽くぐぐってみた限りでもバージョン 4.4 および 4.5 で C++0x への対応を改善したとのニュース記事が見つかるので、おそらくは 4.x 系であれば対応を進めてはいるんだろうなぁと言うことは伺えるわけです。

MinGW は割と最近導入したので、まさか古い GCC が採用されているなどとは疑いもしていなかったのですが、ここで念のためにとバージョンを確かめてみると、なんとデフォルトでインストールされている GCC のバージョンは 3.4.5 だというじゃないですか。

まさか MinGW 版の GCC が 3.4.5 で開発が止まっているなどとはさすがに思えなかったので、早速 4.x 系にバージョンアップする方法はないかと調べてみたところ、なんのことはない、 MinGW のダウンロードサイトに普通に用意されていて、それを展開して上書きインストールすれば済む話だったのでした (やり方の詳細は技術メモをご参照のこと)。

これでいよいよ <cstdint><unordered_map> も使える! ということで、早速以下のようなテストプログラムを書いてみました。

#include <iostream>
#include <string>
#include <unordered_map>
#include <cstdint>

int main()
{
	std::unordered_map<std::string, std::string> murachi;
	murachi["name"] = "Toshiyuki Murayama";
	murachi["handle"] = "T.MURACHI";
	murachi["age"] = "32";
	
	std::cout << "I'm " << murachi["handle"] << "(" << murachi["name"] << "), " <<
		murachi["age"] << " years old." << std::endl;
	
	std::int32_t hoge = 12345;
	std::cout << "hoge = " << hoge << std::endl;
	
	return 0;
}

これを test.cpp という名前で保存し、コンパイルを試みますが…

murachi@YUMA ~
$ g++ -o test test.cpp
c:\mingw\bin\../lib/gcc/mingw32/4.4.0/include/c++/unordered_map:35 、ォ、・include
、オ、・ソ・ユ・。・、・・・ツソスナ include 、ォ、鬢ホハンク釥ャヘュアラ、ネ、ハ、・ヌ、キ、遉ヲ:
,
                 test.cpp:3 、ォ、・ISO C 、ヌ、マフセチー、ト、ュイトハムー惞゙・ッ・惕キ、゙、サ、・IS
O C99 、マサネヘム、オ、・・ル、ュサト、熙ホ、ホー惞ラオ皃キ、゙、ケ:
c:\mingw\bin\../lib/gcc/mingw32/4.4.0/include/c++/c++0x_warning.h:31:2: error: #
error This file requires compiler and library support for the upcoming ISO C++ s
tandard, C++0x. This support is currently experimental, and must be enabled with
 the -std=c++0x or -std=gnu++0x compiler options.
test.cpp: In function 'int main()':
test.cpp:8: error: 'unordered_map' is not a member of 'std'
test.cpp:8: error: expected primary-expression before ',' token
test.cpp:8: error: expected primary-expression before '>' token
test.cpp:8: error: 'murachi' was not declared in this scope

murachi@YUMA ~
$

なんだか文字化けしたエラーが出てきてしまいました。新しいバージョンの GCC はエラーを日本語で出してくれるのか? 何はともあれ、そのすぐ後ろに GCC のオプションに関するヒントが綴られていたので、「そうか C++0x 固有の機能を利用するには -std=c++0x オプションか -std=gnu++0x オプションのどっちかを指定してあげる必要があるんだな」と気づくことができました。

で、なんとなく -std=c++0x オプションの方がまだ標準っぽい感じがしたので、それを試してみたのですが、

murachi@YUMA ~
$ g++ -std=c++0x -o test test.cpp
In file included from c:\mingw\bin\../lib/gcc/mingw32/4.4.0/include/c++/bits/pos
types.h:42,
                 from c:\mingw\bin\../lib/gcc/mingw32/4.4.0/include/c++/iosfwd:4
2,
                 from c:\mingw\bin\../lib/gcc/mingw32/4.4.0/include/c++/ios:39,
                 from c:\mingw\bin\../lib/gcc/mingw32/4.4.0/include/c++/ostream:
40,
                 from c:\mingw\bin\../lib/gcc/mingw32/4.4.0/include/c++/iostream
:40,
                 from test.cpp:1:
c:\mingw\bin\../lib/gcc/mingw32/4.4.0/include/c++/cwchar:159: error: '::swprintf
' has not been declared
c:\mingw\bin\../lib/gcc/mingw32/4.4.0/include/c++/cwchar:166: error: '::vswprint
f' has not been declared

murachi@YUMA ~
$

今度は <iostream> から巡り巡って参照されている <cwchar> の中で、存在しないシンボルが参照されようとしている、と怒られてしまいました。 cwchar ファイルの中も一応覗いてみましたが、これを書き換えてしまうのもよくないので、とりあえず一か八かでもう一つのオプション -std=gnu++0x を試してみることに。すると…

murachi@YUMA ~
$ g++ -std=gnu++0x -o test test.cpp

murachi@YUMA ~
$ ./test
I'm T.MURACHI(Toshiyuki Murayama), 32 years old.
hoge = 12345

murachi@YUMA ~
$

こんどはちゃんとコンパイルが通り、プログラムも期待したとおりに動作しました。

と、いうわけで、おさらいです。

  • GCC のバージョンはちゃんと確認しよう。
    • 特に、C++0x 固有の機能を用いるのであれば、 GCC 4.x 以降が必要になる。
    • クロスプラットフォーム対応を前提とする場合、対応予定の全ての環境で確認し、開発に用いる GCC のバージョンをプロジェクト内で決めてしまい、それを用いるよう徹底してしまった方がよいかも…。
  • GCC で <unordered_map> などの C++0x 固有の機能を用いる場合、 g++ コマンドにオプション -std=gnu++0x を付加する必要がある。
    • おそらく GCC 固有のオプションなので、 GCC 固有の機能を許可してしまっている可能性もある。 GCC 以外のコンパイラにも対応させたいのであれば、可搬性には特に注意する必要がある、かも知れない。

ちなみに、先ほどのサンプルプログラムは <unordered_map><cstdint> の両方をテストしていて、特に後者については以下のような記述で利用しているのですが、

	std::int32_t hoge = 12345;  // int32_t は std 名前空間に存在する

実際のところ、この記述は下記のように書き換えてもコンパイルは通ります。

	::int32_t hoge = 12345; // int32_t はグローバル名前空間にも存在する…!?

C++0x の仕様についてはまだちゃんと目を通していないので、どちらがより推奨されているのかは分かりません。この辺は後でちゃんと確認しておかねば…。

それから、そもそも C++0x には初期化リストなどの構文糖や型推論、ラムダ、Unicode 用の文字型と Unicode リテラル (UTF-32 リテラルと libiconv の UCS-4-INTERNAL って互換性あるのかなぁ…これも後で調べなきゃ…)、そしてタプルや正規表現 (std::basic_regex!!) などの追加ライブラリ群などなど…さまざまな機能の追加がなされているので、それらについても一通りさらうなり有用な書籍を探す (日本語の文献は…無いかなぁ…) なりしておかないとなぁとか思ったりするわけです (こうやってブログ記事にする為にちょっと Wikipedia に目を通してみただけでもまぁいろいろと…また実装方針を考え直さないといけない部分も結構出てきてるなぁ… ^_^;)。

2010 年 8 月 31 日 by 村山 俊之

タグ: , , , ,

コメントをどうぞ