のろのろとgcc 4.8.1を作ってみる(その4)

はぁーやっぱりOSとか言語のコンパイルは疲れますね。コンパイル長いし、makeバグが潜んでるしで…。ともあれ、なんとか無事にgcc 4.8.1(32bit版)が出来たので、次のverか64bit化の為に記録を残しておきます。

※ここに書いてあるのは、gcc 4.6.2(多分それ以前)からgcc 4.8.1を生成する方法です。gcc 4.7.xに上げている場合は、2013/6/30の記事を読んでください。

開発環境

MinGW(32bit版)
2013/6/2時点の最新。mingw-get-inst-20120426.exe内蔵カタログファイルで指定されたMinGW/MSYSのバージョン環境(※2013/6/30訂正)。C、C++、MSYS Basic System、MinGW Developer Toolkitを選択してインストールしてある。
binutils
上記MinGW環境で必要要件は満たしているが、2013/6/23にbinutilsをv2.22からv2.23.2に入れ替えている。
Ada(GNAT)
Adaを作りたい/使いたい人だけ。MinGW Shell上から「which gnatmake」と実行し、コマンドが見つかれば、それでOK。見つからない人は、「mingw-get install gcc-ada-bin」と実行してください。
スレッドモデル
オリジナルのgccがwin32スレッドなので、そのままwin32スレッドで行きます。他の選択肢にはPOSIXスレッドがありますが、困ったときに考えます。

入手物

必要要件の詳細は、gccを展開したディレクトリの下のINSTALL/prerequisites.htmlを読んでください。

gcc v4.8.1
http://ftp.gnu.org/gnu/gcc/gcc-4.8.1/gcc-4.8.1.tar.bz2
GMP v5.1.2
http://ftp.gnu.org/gnu/gmp/gmp-5.1.2.tar.xz
MPFR v3.1.2
http://ftp.gnu.org/gnu/mpfr/mpfr-3.1.2.tar.xz
MPC v1.0.1
http://ftp.gnu.org/gnu/mpc/mpc-1.0.1.tar.gz
ISL v0.11.1
ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-0.11.1.tar.bz2
CLooG v0.18.0
ftp://gcc.gnu.org/pub/gcc/infrastructure/cloog-0.18.0.tar.gz
zlib v1.2.8
http://www.zlib.net/ から http://prdownloads.sourceforge.net/libpng/zlib-1.2.8.tar.xz?download
gcc v4.8.1にzlib v1.2.7が入っているので、本当は必要ないけれども、v1.2.8でバグ修正が入っているので念のため。
libiconv v1.14
http://ftp.gnu.org/gnu/libiconv/libiconv-1.14.tar.gz
必要要件に入っていないけれども必要

gnu直リンだからgnuな人に怒られそうだな〜ってあれ?pplが要らなくなっちゃいましたね。

パッチ

configureが変だったり、折角の環境変数を生かしてなかったりしているので、対策してみた。

下のパッチファイルは所々タブが入っているでperlで修正します。添付ファイルが置けないのでスマンね。

$ perl -e 'while(<>) {
  $LAST=$_;
  if(/^\s+(and return it\.  \*\/)/) {
    print " \t $1\n";
  } elsif(/^\s+(\/\* If all.+\*\/)/) {
    print " \t$1\n";
  } elsif(/^\s+(.+xstrdup.+;)/) {
    print " \t$1\n";
  } else {
    if(/\r$/) {
      print "$`\n";
    } else {
      print;
    }
  }
}
END {
  if($LAST !~ /\n$/) {
    print "\n";
  }
  if($LAST !~ /^\r?\n$/) {
    print "\n";
  }
}' < patch.txt > diff-gcc-4.8.1-1.patch


patch.txt

diff -Nru gcc-4.8.1/gcc/configure gcc-4.8.1-1/gcc/configure
--- gcc-4.8.1/gcc/configure     2013-05-08 20:36:36 +0900
+++ gcc-4.8.1-1/gcc/configure   2013-06-27 22:17:38 +0900
@@ -27236,8 +27236,8 @@
 $as_echo_n "checking for exported symbols... " >&6; }
   if test "x$export_sym_check" != x; then
     echo "int main() {return 0;} int foobar() {return 0;}" > conftest.c
-    ${CC} ${CFLAGS} ${LDFLAGS} conftest.c -o conftest > /dev/null 2>&1
-    if $export_sym_check conftest | grep foobar > /dev/null; then
+    ${CC} ${CFLAGS} ${LDFLAGS} conftest.c -o conftest$ac_exeext > /dev/null 2>&1
+    if $export_sym_check conftest$ac_exeext | grep foobar > /dev/null; then
       : # No need to use a flag
       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
@@ -27246,8 +27246,8 @@
 $as_echo "yes" >&6; }
       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -rdynamic" >&5
 $as_echo_n "checking for -rdynamic... " >&6; }
-      ${CC} ${CFLAGS} ${LDFLAGS} -rdynamic conftest.c -o conftest > /dev/null 2>&1
-      if $export_sym_check conftest | grep foobar > /dev/null; then
+      ${CC} ${CFLAGS} ${LDFLAGS} -rdynamic conftest.c -o conftest$ac_exeext > /dev/null 2>&1
+      if $export_sym_check conftest$ac_exeext | grep foobar > /dev/null; then
         plugin_rdynamic=yes
         pluginlibs="-rdynamic"
       else
diff -Nru gcc-4.8.1/libiberty/make-temp-file.c gcc-4.8.1-1/libiberty/make-temp-file.c
--- gcc-4.8.1/libiberty/make-temp-file.c        2011-01-04 05:52:22 +0900
+++ gcc-4.8.1-1/libiberty/make-temp-file.c      2013-06-27 22:17:38 +0900
@@ -55,12 +55,18 @@
 #define DIR_SEPARATOR '/'
 #endif

+#ifndef DIR_SEPARATOR_2
+#define DIR_SEPARATOR_2 '\\'
+#define IS_DIR_SEPARATOR(ch) \
+    (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif
+
 /* Name of temporary file.
    mktemp requires 6 trailing X's.  */
 #define TEMP_FILE "ccXXXXXX"
 #define TEMP_FILE_LEN (sizeof(TEMP_FILE) - 1)

-#if !defined(_WIN32) || defined(__CYGWIN__)
+#if !defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)

 /* Subroutine of choose_tmpdir.
    If BASE is non-NULL, return it.
@@ -107,7 +113,7 @@
 {
   if (!memoized_tmpdir)
     {
-#if !defined(_WIN32) || defined(__CYGWIN__)
+#if !defined(_WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
       const char *base = 0;
       char *tmpdir;
       unsigned int len;
@@ -141,12 +147,18 @@
       /* Append DIR_SEPARATOR to the directory we've chosen
         and return it.  */
       len = strlen (base);
-      tmpdir = XNEWVEC (char, len + 2);
-      strcpy (tmpdir, base);
-      tmpdir[len] = DIR_SEPARATOR;
-      tmpdir[len+1] = '\0';
+      if(IS_DIR_SEPARATOR(base[len-1])) {
+          tmpdir = XNEWVEC (char, len + 1);
+          strcpy (tmpdir, base);
+      } else {
+          tmpdir = XNEWVEC (char, len + 2);
+          strcpy (tmpdir, base);
+          tmpdir[len] = DIR_SEPARATOR;
+          ++len;
+      }
+      tmpdir[len] = '\0';
       memoized_tmpdir = tmpdir;
-#else /* defined(_WIN32) && !defined(__CYGWIN__) */
+#else /* defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__) */
       DWORD len;

       /* Figure out how much space we need.  */
@@ -163,7 +175,7 @@
       if (!memoized_tmpdir)
        /* If all else fails, use the current directory.  */
        memoized_tmpdir = xstrdup (".\\");
-#endif /* defined(_WIN32) && !defined(__CYGWIN__) */
+#endif /* defined(_WIN32) && !defined(__CYGWIN__) && !defined(__MINGW32__) */
     }

   return memoized_tmpdir;
diff -Nru gcc-4.8.1/libstdc++-v3/configure gcc-4.8.1-1/libstdc++-v3/configure
--- gcc-4.8.1/libstdc++-v3/configure    2013-05-25 03:10:37 +0900
+++ gcc-4.8.1-1/libstdc++-v3/configure  2013-06-27 22:17:38 +0900
@@ -19375,6 +19375,10 @@

   ac_has_clock_monotonic=no
   ac_has_clock_realtime=no
+  ac_has_nanosleep=no
+  ac_has_clock_monotonic_syscall=no
+  ac_has_sleep=no
+  ac_has_usleep=no
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_libstdcxx_time" >&5
 $as_echo "$enable_libstdcxx_time" >&6; }

前準備

セキュリティソフトが誤って、生成オブジェクトをウイルスだとして、自動隔離する場合があります。私の環境のESET SMART SECURITY5が、まさにそれでした。自動隔離されると正しくコンパイルされないので、自動隔離しないように設定を変えるか、PCをスタンドアローンにしてセキュリティソフトを一時的に停止させてください。

準備

/usr/local/src(C:\MinGW\msys\1.0\local\src)配下を作業ディレクトリに使用した例なので、別のディレクトリが良い人は読み替えてください。

$ mkdir -p /usr/local/src/gcc_build /usr/local/src/gcc_alt
$ cd ダウンロード物のあるディレクトリ
$ tar xf gcc-4.8.1.tar.bz2 -C /usr/local/src
$ mv /usr/local/src/gcc-4.8.1 /usr/local/src/gcc-4.8.1-1
$ tar xf gmp-5.1.2.tar.xz -C /usr/local/src/gcc-4.8.1-1
$ tar xf mpfr-3.1.2.tar.xz -C /usr/local/src/gcc-4.8.1-1
$ tar xf mpc-1.0.1.tar.gz -C /usr/local/src/gcc-4.8.1-1
$ tar xf isl-0.11.1.tar.bz2 -C /usr/local/src/gcc-4.8.1-1
$ tar xf cloog-0.18.0.tar.gz -C /usr/local/src/gcc-4.8.1-1
$ tar xf zlib-1.2.8.tar.xz -C /usr/local/src/gcc-4.8.1-1
$ tar xf libiconv-1.14.tar.gz -C /usr/local/src/gcc-4.8.1-1
$ cd /usr/local/src/gcc-4.8.1-1
$ mv gmp-5.1.2 gmp
$ mv mpfr-3.1.2 mpfr
$ mv mpc-1.0.1 mpc
$ mv isl-0.11.1 isl
$ mv cloog-0.18.0 cloog
$ cd zlib-1.2.8
$ rm Makefile* configure
$ mv ../zlib/Makefile* ../zlib/configure* .
$ cd ..
$ rm -fr zlib
$ mv zlib-1.2.8 zlib
$ mv libiconv-1.14 libiconv
$ patch -p1 <  パッチを置いたディレクトリ/diff-gcc-4.8.1-1.patch

Makefileの作成(configureの実行)

  • 「-O3 -pipe」は私の趣味ですので「-O2」とかでも構いません(と、言うか始めから-O2付いてるし、CFLAGSとCXXFLAGSの変更は限られたソースにしか効かないし…makeで変更しても大差ないし…本気でconfigureをHACKしてやろうかと考えたぐらい駄目駄目)。愚痴はともかく、「-D* -W*」は消さないでくださいね。
  • 必要の無い言語がある場合「--enable-languages=」から消してください。例えばCとC++しか必要が無い場合は「--enable-languages=c,c++」となります。
  • 母国語ファイルが必要な(つまり日本語メッセージが欲しい)場合、「--disable-nls」を消してください。
  • Adaが必要な場合「--with-arch=i586 --with-tune=generic」は、i586以上ならば好きな値に変えても構いません。
  • Adaが必要ない場合「--with-arch=i586 --with-tune=generic」を消してください。この場合、作られたコンパイラが生成するコードはi386ベースになります。また、消さずに好きな値に変えても構いません。
  • Javaが欲しい方は「--enable-languages=」にjavaを加えてください。例えば「--enable-languages=c,c++,java」の様に変更してください。また、「--with-arch=i586 --with-tune=generic」の削除、変更も自由です。
$ cd /usr/local/src/gcc_build
$ CFLAGS='-O3 -pipe -D__USE_MINGW_ACCESS -Wno-pedantic-ms-format' \
CXXFLAGS='-O3 -pipe -D__USE_MINGW_ACCESS -Wno-pedantic-ms-format' \
../gcc-4.8.1-1/configure --enable-languages=c,c++,ada,fortran,objc,obj-c++ \
--disable-nls --disable-sjlj-exceptions --with-dwaft2 --enable-shared \
--enable-libgomp --disable-win32-registry \
--enable-libstdcxx-debug --enable-version-specific-runtime-libs \
--build=mingw32 --with-arch=i586 --with-tune=generic \
--prefix=/mingw

オブジェクトの生成(makeの実行)

  • 「-j*」を付けない場合、シリアルコンパイルになるため、基本的にコンパイル問題は発生しなくなります。ただし、コンパイル時間が長くなります。Core i5クラスで4時間程度掛かります。
  • 「-j*」を付けた場合、パラレルコンパイルになるため、希にコンパイルの途中でハングすることがあります。ただし、「-j*」を付けることによって、コンパイル時間を減らすことが可能です。
    • 「-j*」の数値は、ご使用のPCの「Core数×Core当たりのスレッド数」を基本にして指定してください。私の場合は、Core i5-2430Mなので、Core数=2、Core当たりのスレッド数=2なので、基本は4になります。私の環境で「-j4」を付けてコンパイルした場合、コンパイル時間は2時間になりました。
      • 少ない値を指定する分には問題ありませんが、あまりにも大きい値を指定するとコンテキストスイッチが多発して、逆にコンパイル時間が長くなる可能性があります。また、大量にメモリを消費しますので、メモリが少ない方は要注意です。
$ cd /usr/local/src/gcc_build
$ make -j4

実行ファイルの配布

DESTDIRの付いている方は保険です。付けていない方のinstall-stripが失敗した場合、環境が直せなくなってしまうので、/usr/local/src/gcc_alt(C:\MinGW\msys\1.0\local\src\gcc_alt)にバックアップを用意しておきます。
「make install-strip」に失敗したら(と言うか、大抵失敗するんですけどね〜なめてんですかね(笑)「make DESTDIR=c: install-strip」で成功する場合もあるよ〜ネタ?)、/usr/local/src/gcc_alt配下に「mingw/〜」として新しいgccの環境がありますので、/mingw(C:\MinGW)に上書きしてください。
gcc -vを実行し、バージョンが4.8.1になっていれば成功です。

$ cd /usr/local/src/gcc_build
$ make DESTDIR=/usr/local/src/gcc_alt install-strip
$ make install-strip

後片付け

何かあったときのため、コンパイル環境を残しておきましょう。ただ、正直gcc_altさえあれば良いんじゃないかなと思う今日この頃

$ cd /usr/local/src
$ tar --xz -cf gcc-4.8.1-1.tar.xz ./gcc-4.8.1-1 ./gcc_build
$ rm -fr gcc-4.8.1-1 gcc_alt gcc_build