目次へ戻る §26へ戻る §28へ進む

27. Cygwin 64 と gcc 4.8.1

2013.8.13, 2013.8.23 (鈴)

27.1 はじめに

先月下旬 Cygwin の新時代を画するリリースがありました。 初の公式 64 ビット版リリース [cygwin.com] です。 いよいよ Cygwin プログラムでも 64 ビット版 Windows の広大なメモリ空間を利用できるようになりました。

32 ビット版 Cygwin の gcc がまだ 4.7.3 なのに対して 64 ビット版 Cygwin の gcc は最新の 4.8.1 を採用しています。 gcc 4.8.1 は Status of Experimental C++11 Support in GCC 4.8 [gnu.org] に

As of GCC 4.8.1, GCC's C++11 mode implements all of the major features of the C++11 standard produced by the ISO C++ committee.

と述べられているように C++11 の主要な新機能を一応仮にもすべて実装した初めての gcc のバージョンです。 手軽なインストールで簡単に C++11 の新世界を探検できます。

27.2 64 ビット版 Cygwin のインストール

64 ビット版 Cygwin をインストールするには,従来の setup.exe のかわりに Cygwin 本家ページ [cygwin.com] から

setup-x86_64.exe

をダウンロードして実行します。

ダウンロードしたパッケージのキャッシュとして従来と同じくダウンロード先の URL と同名のフォルダが作られますが,さらにその下に x86_64 フォルダが作られ,そこに setup.ini ファイルと release フォルダが置かれます。 インストール先は特に何も指定しなければデフォルトで

C:\cygwin64

になります。 スタート・メニューとデスクトップに作られる起動用ショートカットの名前は 32 ビット版の Cygwin Terminal と違えて Cygwin64 Terminal になります。

ちなみに 32 ビット版 Cygwin は setup-x86.exe を使うように改められました。 ダウンロードのキャッシュも上記の x86_64 にかえて x86 の下に置かれるようになりました。 32 ビットと 64 ビットのパッケージをそれぞれ同じ場所でダウンロードしても両者を混ぜてしまうおそれはありません。

つまり,従来からの 32 ビット版 Cygwin と 64 ビット版 Cygwin はデフォルトのままで同じマシンに共存できます。

下記は Windows 7 SP1 (64) での実行例です。

01:~$ cat /proc/version
CYGWIN_NT-6.1 version 1.7.24(0.269/5/3) (corinna@calimero.vinschen.de) (gcc vers
ion 4.8.1 20130531 (Fedora Cygwin 4.8.1-1) (GCC) ) 2013-08-15 11:59
01:~$ cygpath -w /
C:\cygwin64
01:~$  

~/.minttyrc~/.bashrc などの設定ファイルは §24. Cygwin 1.7.9 と NTEmacs JP 22.2 とその 付録 の内容がそのまま使えます。 NTEmacs JP もそのまま 64 ビット版 Cygwin から起動できます。

27.3 LP64 データモデル

Unix でも Windows でも 32 ビット版の C 言語では普通 int, long, void* はすべて 4 バイト (= 32 ビット) 長でした。 しかし 64 ビットの世界では Unix と Windows に不一致があります。 両者のあいだに立つ 64 ビット版の Cygwin ではどうなっているか確かめてみます。

NTEmacs などで下記のファイル size_test.c を作ります。

#include <stdio.h>

int main()
{
    printf("sizeof(short) = %lu\n", sizeof(short));
    printf("sizeof(int) = %lu\n", sizeof(int));
    printf("sizeof(long) = %lu\n", sizeof(long));
    printf("sizeof(long long) = %lu\n", sizeof(long long));
    printf("sizeof(void*) = %lu\n", sizeof(void*));
    return 0;
}

gcc-core パッケージ (執筆時現在のバージョンは 4.8.1-3) をインストールし,これをコンパイルして実行すると次のようになります。

01:~/tmp$ gcc -Wall size_test.c
01:~/tmp$ ./a.exe
sizeof(short) = 2
sizeof(int) = 4
sizeof(long) = 8
sizeof(long long) = 8
sizeof(void*) = 8
01:~/tmp$  

もはや intlong は同じではありません。 long はポインタ型と同じく 8 バイト (= 64 ビット) 長です。 また long long 型は long 型と同じです。 つまり,64 ビット版 Cygwin の gcc は一般的な 64 ビット版 Unix の C 言語と同じく LP64 データモデルを採用しています。

名前の由来は Long と Pointer が 64 ビット長だからです。 ちなみに Microsoft 製の 64 ビット版 C コンパイラは intlong が 4 バイト長であり,long long とポインタが 8 バイト長である LLP64 データモデルを採用しています。

27.4 gcc 4.8.1 による C++11

NTEmacs などで下記のファイル powers_of_two.cxx を作ります。

#include <array>
#include <iostream>
using namespace std;

int main()
{
    array<int, 11> a;
    int i = 1;
    for (auto& e: a) {
        e = i;
        i *= 2;
    }

    for (auto e: a)
        cout << e << endl;

    return 0;
}

gcc-g++ パッケージでこれをコンパイルして実行してみます。 C++11 独自の機能を使うときは陽に -std=c++11 オプションを付けます。

01:~/tmp$ g++ -std=c++11 -Wall powers_of_two.cxx
01:~/tmp$ ./a.exe
1
2
4
8
16
32
64
128
256
512
1024
01:~/tmp$  

27.5 gcc 4.8.1 による Fortran 95

ついでですから gcc-fortran パッケージも使ってみましょう。 デフォルトで Fortran 95 の言語仕様が使われるようにファイルの接尾辞を .f95 にします。

program Powers
  implicit none
  integer:: i, j
  integer, dimension(10, 5):: a

  do i = 1, 10
     a(i, 1) = i
  end do

  do j = 2, 5
     a(:, j) = a(:, j - 1) * a(:, 1)
  end do

  do i = 1, 10
     write(*, *) a(i, :)
  end do
end program Powers

次のようにコンパイルして実行できます。

01:~/tmp$ gfortran powers.f95
01:~/tmp$ ./a.exe
           1           1           1           1           1
           2           4           8          16          32
           3           9          27          81         243
           4          16          64         256        1024
           5          25         125         625        3125
           6          36         216        1296        7776
           7          49         343        2401       16807
           8          64         512        4096       32768
           9          81         729        6561       59049
          10         100        1000       10000      100000
01:~/tmp$  

27.6 MinGW gcc と libstdc++, libgfortran を探して

cygwin1.dll から独立した,ある意味,真にネイティブな実行ファイルを作るために MinGW gcc を使うこともできます。 右図のように

のパッケージをインストールします。

27.3 節の C 言語プログラムは次のように実行できます。

01:~/tmp$ x86_64-w64-mingw32-gcc size_test.c
01:~/tmp$ ./a.exe
sizeof(short) = 2
sizeof(int) = 4
sizeof(long) = 4
sizeof(long long) = 8
sizeof(void*) = 8
01:~/tmp$  

依存する動的ライブラリを ldd コマンドで見ると,確かに cygwin1.dll から独立しています。

01:~/tmp$ ldd ./a.exe
        ntdll.dll => /cygdrive/c/Windows/SYSTEM32/ntdll.dll (0x770b0000)
        kernel32.dll => /cygdrive/c/Windows/system32/kernel32.dll (0x76e90000)
        KERNELBASE.dll => /cygdrive/c/Windows/system32/KERNELBASE.dll (0x7fefd17
0000)
        msvcrt.dll => /cygdrive/c/Windows/system32/msvcrt.dll (0x7fefeb30000)
01:~/tmp$  

ここで MinGW gcc による size_test.c の実行結果にも注意してください。 27.3 節で見たような Unix 流儀の LP64 データモデルではなく,Windows 流儀の LLP64 データモデル (Long Long と Pointer だけが 64 ビット長) になっています。 Microsoft 製コンパイラに代わって Windows のネイティブ・アプリケーションを作る MinGW gcc の位置付けを反映しています。

さて次に 27.4 節の C++ プログラムと 27.5 節の Fortran プログラムをコンパイルして実行してみると,残念ながらこれらは動きません。

01:~/tmp$ x86_64-w64-mingw32-g++ -std=c++11 powers_of_two.cxx
01:~/tmp$ ./a.exe
/home/suzuki/tmp/a.exe: error while loading shared libraries: libstdc++-6.dll: c
annot open shared object file: No such file or directory
1271:~/tmp$ x86_64-w64-mingw32-gfortran -o powers powers.f95
01:~/tmp$ ./powers.exe
/home/suzuki/tmp/powers.exe: error while loading shared libraries: libgfortran-3
.dll: cannot open shared object file: No such file or directory
1271:~/tmp$  

C++ には libstdc++-6.dll が,Fortran には libgfortran-3.dll が足りないようです。

現在の ldd コマンドでは PATH にない動的ライブラリが表示されませんから,直接確かめるには cygcheck ./a.exe を使います。煩雑な出力の末尾に下記の表示を見ることができます。
cygcheck: track_down: could not find libgcc_s_seh-1.dll

cygcheck: track_down: could not find libstdc++-6.dll

実はこれらのライブラリは下記のように /usr/x86_64-w64-mingw32/sys-root/mingw/bin/ に置かれています。

01:~/tmp$ ls /usr/x86_64-w64-mingw32/sys-root/mingw/bin/
libgcc_s_seh-1.dll*  libgomp-1.dll*      libssp-0.dll*     libwinpthread-1.dll*
libgfortran-3.dll*   libquadmath-0.dll*  libstdc++-6.dll*
01:~/tmp$  

したがって,ここに PATH を通してやれば無事 Cygwin から実行できます。

01:~/tmp$ PATH=$PATH:/usr/x86_64-w64-mingw32/sys-root/mingw/bin ./a.exe
1
2
4
8
16
32
64
128
256
512
1024
01:~/tmp$ PATH=$PATH:/usr/x86_64-w64-mingw32/sys-root/mingw/bin ./powers.exe
           1           1           1           1           1
           2           4           8          16          32
           3           9          27          81         243
           4          16          64         256        1024
           5          25         125         625        3125
           6          36         216        1296        7776
           7          49         343        2401       16807
           8          64         512        4096       32768
           9          81         729        6561       59049
          10         100        1000       10000      100000
01:~/tmp$  

もちろん,これらのライブラリと共にすることで,MinGW gcc の元々の意図どおりネイティブな Windows プログラムとして実行できます。



27.7 おわりに

本章では 64 ビット版 Cygwin とその上で動く gcc 4.8.1 およびその MinGW 版コンパイラを紹介しました。 64 ビット版 Cygwin は従来の 32 ビット版 Cygwin と干渉することなく共存します。 インストールしたら従来の環境が壊れてしまうのではないかと心配する必要はありません。 また従来の NTEmacs 等とも問題なく共存します。 試してみる価値のある興味深い操作環境でありプログラミング環境です。

うるさく言えば,64 ビット版と 32 ビット版の Cygwin で干渉しあって共存できないものがあります。 個々のパッケージがスタート・メニューに作るショートカットです。 具体的には X11 カテゴリの xinit パッケージがインストールされたときスタート・メニューに作る Cygwin-X フォルダの XWin Server ショートカットです。



これが共存できないのは xinit パッケージがインストール時に自動実行する /etc/postinstall のスクリプトの内容が両者で同一だからです。 スクリプトは実行に成功した後 .done 接尾辞を付けて残されますから,下記のように後から内容を確かめることができます。
01:~$ cat /etc/postinstall/xinit.sh.done
/usr/bin/mkdir -p "$(/usr/bin/cygpath $CYGWINFORALL -P)/Cygwin-X"
/usr/bin/mkshortcut $CYGWINFORALL -P -i /usr/bin/XWin.exe -n "Cygwin-X/XWin Serv
er" -a "/usr/bin/bash.exe -l -c /usr/bin/startxwin.exe" /usr/bin/run.exe
01:~$  
これだけのことですから,もしも実体だけでなくショートカットも含めて共存させたい場合は二つめの xinit パッケージをインストールする前に一つめの XWin Server のショートカットを別の名前にしておきます。

Cygwin 自身のショートカットは 32 ビット版の Cygwin Terminal と共存できるように 64 ビット版は Cygwin64 Terminal と名前を変えて作られます。 しかし,個々のパッケージが作るショートカットにはその方針が及んでいないというわけです。

Copyright (c) 2013 OKI Software Co., Ltd.