A/I #28
未完了開発 次郎 さんが23日前に更新
構築メモ¶
MSVCRT を使いながら long double=80bit を実現することは “不可能”
れは GCC の制限ではなく、MSVCRT(Microsoft の C ランタイム)の仕様そのものが原因。
だから --with-default-msvcrt=ucrt を使う必要があるのではなく、
MSVCRT を選んだ瞬間に long double=64bit が確定してしまうという構造にする。
MSVCRT の long double は double と同じ 64bit で実装されている。
MSVCRT の ABI
→ long double = 64bit
MinGW-w64 の MSVCRT CRT
→ long double = 64bit
GCC の configure
→ long double のビット幅を変更できない
→ CRT の ABI に従うだけ
つまり:
MSVCRT を選ぶ = long double は 64bit に固定される
GCC 側でどう頑張っても変えられない。
UCRT は long double を 80bit として扱える ABI を持っている。
だから Rocky9 の mingw-w64 は UCRT + 80bit long double の構成になっていた。
つまり:
MSVCRT → 64bit long double(固定)
UCRT → 80bit long double(可能)
UCRT は Windows 7 以降で動作する。
Windows Update や VC++ 再頒布パッケージで配布されている。
✔️ MSVCRT より新しいが、互換性は高い
MSVCRT は古いが、
MSVCRT を使う理由は “古い Windows 互換性” ではなく “MinGW の歴史的理由”。
今は UCRT が標準。
開発 次郎 さんが21日前に更新
UCRT64 用 GCC 8.4.0 完全構築手順(最終版・Textile)¶
MSYS2 UCRT64 上で、UCRT 対応の x86_64-w64-mingw32 向け GCC 8.4.0 を、
stage1 → CRT → 最終 GCC の順で再構築するための完全版手順。
以下は Redmine Textile 用。コードブロックは指定どおりの形式を使う。
0. 前提パッケージ(MSYS2 UCRT64)¶
UCRT64 シェルで、必要なパッケージをインストールする。
pacman -S \
mingw-w64-ucrt-x86_64-gcc \
mingw-w64-ucrt-x86_64-gmp \
mingw-w64-ucrt-x86_64-mpfr \
mingw-w64-ucrt-x86_64-mpc \
mingw-w64-ucrt-x86_64-crt \
mingw-w64-ucrt-x86_64-headers
注意:
/ucrt64/include を削除しない(ホスト g++ の標準ヘッダが入っている)
1. ソース配置¶
前提とするディレクトリ構成:
/d/work/gcc8/
├ gcc-8.4.0/
└ mingw-w64/
├ mingw-w64-headers/
└ mingw-w64-crt/
2. mingw-w64 headers(ターゲット用)インストール¶
ターゲット用ヘッダを /ucrt64/x86_64-w64-mingw32 配下にインストールし、
古い GCC が期待する /ucrt64/mingw/include もシンボリックリンクで用意する。
cd /d/work/gcc8
rm -rf build-headers
mkdir build-headers
cd build-headers
../mingw-w64/mingw-w64-headers/configure \
--host=x86_64-w64-mingw32 \
--prefix=/ucrt64/x86_64-w64-mingw32
make -j1
make install
mkdir -p /ucrt64/mingw
ln -s /ucrt64/x86_64-w64-mingw32/include /ucrt64/mingw/include
3. stage1 GCC(C コンパイラ + libgcc)構築¶
C のみ・libgcc のみをビルドする stage1 を構築する。
ここでは all-stage1-gcc と all-stage1-target-libgcc のみに絞る。
cd /d/work/gcc8
rm -rf build-gcc-stage1
mkdir build-gcc-stage1
cd build-gcc-stage1
../gcc-8.4.0/configure \
--target=x86_64-w64-mingw32 \
--prefix=/ucrt64 \
--with-sysroot=/ucrt64 \
--enable-languages=c \
--disable-multilib \
--disable-nls
make -j1 all-stage1-gcc all-stage1-target-libgcc
動作確認(コンパイルだけ通ればよい。生成 exe の実行は失敗しても問題なし):
cd /d/work/gcc8/build-gcc-stage1/gcc
./xgcc -v
echo "int main(){return 0;}" > t.c
./xgcc t.c -c
4. mingw-w64 CRT(ターゲット用)を stage1 でビルド¶
CRT は stage1 の xgcc を使ってビルドする。
CC に -B オプションを付けて、stage1 の libgcc / crt を見せることが重要。
cd /d/work/gcc8
rm -rf build-crt
mkdir build-crt
cd build-crt
../mingw-w64/mingw-w64-crt/configure \
--host=x86_64-w64-mingw32 \
--prefix=/ucrt64 \
CC="/d/work/gcc8/build-gcc-stage1/gcc/xgcc -B/d/work/gcc8/build-gcc-stage1/gcc"
make -j1
make install
dllcrt2.o が見つからない場合は、MSYS2 の dllcrt2.o を GCC が期待する場所にリンクする。
find /ucrt64 -name dllcrt2.o
例: /ucrt64/lib/dllcrt2.o にある場合
mkdir -p /ucrt64/x86_64-w64-mingw32/lib
ln -s /ucrt64/lib/dllcrt2.o /ucrt64/x86_64-w64-mingw32/lib/dllcrt2.o
5. UCRT 対応のための libgcc リンクライン修正¶
GCC 8.4.0 の mingw 用設定は MSVCRT 前提になっており、
UCRT CRT(dllcrt2.o)が必要とする ucrtbase.dll がリンクされないため、
_initterm_e の未定義参照が発生する。
これを解決するために、config/i386/t-mingw32 の SHLIB_LC を修正する。
対象ファイル:
/d/work/gcc8/gcc-8.4.0/libgcc/config/i386/t-mingw32
修正前(例):
MinGW-specific parts of LIB_SPEC
SHLIB_LC = -lmingwthrd -lmingw32 -lmingwex -lmoldname -lmsvcrt -ladvapi32 -lshell32 -luser32 -lkernel32
修正後(UCRT 対応版・推奨):
MinGW-specific parts of LIB_SPEC
SHLIB_LC = -lmingwthrd -lmingw32 -lmingwex -lmoldname -lucrtbase -lmsvcrt -ladvapi32 -lshell32 -luser32 -lkernel32
あるいは、MSVCRT を完全に外して UCRT のみに寄せる場合:
MinGW-specific parts of LIB_SPEC
SHLIB_LC = -lmingwthrd -lmingw32 -lmingwex -lmoldname -lucrtbase -ladvapi32 -lshell32 -luser32 -lkernel32
6. 最終 GCC(C/C++)構築¶
CRT とヘッダ、libgcc のリンクライン修正が完了したら、
最終的な GCC 8.4.0(C/C++)を構築する。
cd /d/work/gcc8
rm -rf build-gcc-final
mkdir build-gcc-final
cd build-gcc-final
../gcc-8.4.0/configure \
--target=x86_64-w64-mingw32 \
--prefix=/ucrt64 \
--with-sysroot=/ucrt64 \
--enable-languages=c,c++ \
--disable-multilib \
--disable-nls
make -j1
make install
LTO 周りでトラブルが出る場合は、configure に --disable-lto を追加してもよい。
../gcc-8.4.0/configure \
--target=x86_64-w64-mingw32 \
--prefix=/ucrt64 \
--with-sysroot=/ucrt64 \
--enable-languages=c,c++ \
--disable-multilib \
--disable-nls \
--disable-lto
7. 完成したツールチェーンの確認¶
UCRT64 シェルで、インストールされた GCC を確認する。
/ucrt64/bin/x86_64-w64-mingw32-gcc -v
/ucrt64/bin/x86_64-w64-mingw32-g++ -v
簡単な C/C++ プログラムをビルド・実行して、
UCRT ベースの exe が正常に動作することを確認する。
cat > hello.c <<EOF
#include <stdio.h>
int main(void) {
printf("hello from UCRT GCC 8.4.0\n");
return 0;
}
EOF
/ucrt64/bin/x86_64-w64-mingw32-gcc hello.c -o hello.exe
./hello.exe
8. この手順で避けられるハマりポイント¶
/ucrt64/include を消してしまい、<algorithm> などが消える問題
gmp/mpfr/mpc 未インストールによる configure 失敗
dllcrt2.o が /ucrt64/x86_64-w64-mingw32/lib に無くて libgcc_s.dll のリンクに失敗
stage1 xgcc でリンクテストを行い、"cannot compute suffix of object files" で落ちる問題
→ CC に -B build-gcc-stage1/gcc を付けて解決
UCRT CRT と MSVCRT の混在により、_initterm_e 未定義で libgcc_s.dll のリンクが失敗
→ config/i386/t-mingw32 の SHLIB_LC に -lucrtbase を追加して解決
開発 次郎 さんが21日前に更新
UCRT64 用 GCC 8.4.0 完全構築手順(最終版・LTO 無効)¶
MSYS2 UCRT64 上で、UCRT 対応の x86_64-w64-mingw32 向け GCC 8.4.0 を
stage1 → CRT → 最終 GCC の順で構築するための、現時点での安定版手順。
LTO まわりのトラブルを避けるため、最終 GCC は LTO 無効 (--disable-lto) とする。
0. 前提パッケージ(MSYS2 UCRT64)¶
UCRT64 シェルで、必要なパッケージをインストールする。
pacman -S \
mingw-w64-ucrt-x86_64-gcc \
mingw-w64-ucrt-x86_64-gmp \
mingw-w64-ucrt-x86_64-mpfr \
mingw-w64-ucrt-x86_64-mpc \
mingw-w64-ucrt-x86_64-crt \
mingw-w64-ucrt-x86_64-headers
注意:
/ucrt64/include を削除しない(ホスト g++ の標準ヘッダが入っている)
1. ソース配置¶
前提とするディレクトリ構成:
/d/work/gcc8/
├ gcc-8.4.0/
└ mingw-w64/
├ mingw-w64-headers/
└ mingw-w64-crt/
2. mingw-w64 headers(ターゲット用)インストール¶
ターゲット用ヘッダを /ucrt64/x86_64-w64-mingw32 配下にインストールし、
古い GCC が期待する /ucrt64/mingw/include もシンボリックリンクで用意する。
cd /d/work/gcc8
rm -rf build-headers
mkdir build-headers
cd build-headers
../mingw-w64/mingw-w64-headers/configure \
--host=x86_64-w64-mingw32 \
--prefix=/ucrt64/x86_64-w64-mingw32
make -j1
make install
mkdir -p /ucrt64/mingw
ln -s /ucrt64/x86_64-w64-mingw32/include /ucrt64/mingw/include
3. stage1 GCC(C コンパイラ + libgcc)構築¶
C のみ・libgcc のみをビルドする stage1 を構築する。
ここでは all-stage1-gcc と all-stage1-target-libgcc のみに絞る。
cd /d/work/gcc8
rm -rf build-gcc-stage1
mkdir build-gcc-stage1
cd build-gcc-stage1
../gcc-8.4.0/configure \
--target=x86_64-w64-mingw32 \
--prefix=/ucrt64 \
--with-sysroot=/ucrt64 \
--enable-languages=c \
--disable-multilib \
--disable-nls
make -j1 all-stage1-gcc all-stage1-target-libgcc
動作確認(コンパイルだけ通ればよい。生成 exe の実行は失敗しても問題なし):
cd /d/work/gcc8/build-gcc-stage1/gcc
./xgcc -v
echo "int main(){return 0;}" > t.c
./xgcc t.c -c
4. mingw-w64 CRT(ターゲット用)を stage1 でビルド¶
CRT は stage1 の xgcc を使ってビルドする。
CC に -B オプションを付けて、stage1 の libgcc / crt を見せることが重要。
cd /d/work/gcc8
rm -rf build-crt
mkdir build-crt
cd build-crt
../mingw-w64/mingw-w64-crt/configure \
--host=x86_64-w64-mingw32 \
--prefix=/ucrt64 \
CC="/d/work/gcc8/build-gcc-stage1/gcc/xgcc -B/d/work/gcc8/build-gcc-stage1/gcc"
make -j1
make install
dllcrt2.o が見つからない場合は、MSYS2 の dllcrt2.o を GCC が期待する場所にリンクする。
find /ucrt64 -name dllcrt2.o
例: /ucrt64/lib/dllcrt2.o にある場合
mkdir -p /ucrt64/x86_64-w64-mingw32/lib
ln -s /ucrt64/lib/dllcrt2.o /ucrt64/x86_64-w64-mingw32/lib/dllcrt2.o
5. UCRT 対応のための libgcc リンクライン修正¶
GCC 8.4.0 の mingw 用設定は MSVCRT 前提になっており、
UCRT CRT(dllcrt2.o)が必要とする ucrtbase.dll がリンクされないため、
_initterm_e の未定義参照が発生する。
これを解決するために、config/i386/t-mingw32 の SHLIB_LC を修正する。
対象ファイル:
/d/work/gcc8/gcc-8.4.0/libgcc/config/i386/t-mingw32
修正前(例):
MinGW-specific parts of LIB_SPEC
SHLIB_LC = -lmingwthrd -lmingw32 -lmingwex -lmoldname -lmsvcrt -ladvapi32 -lshell32 -luser32 -lkernel32
修正後(UCRT 対応版・推奨):
MinGW-specific parts of LIB_SPEC
SHLIB_LC = -lmingwthrd -lmingw32 -lmingwex -lmoldname -lucrtbase -lmsvcrt -ladvapi32 -lshell32 -luser32 -lkernel32
(MSVCRT を完全に外すなら、-lmsvcrt を削除してもよい)
6. 最終 GCC(C/C++、LTO 無効)構築¶
CRT とヘッダ、libgcc のリンクライン修正が完了したら、
最終的な GCC 8.4.0(C/C++)を構築する。
LTO まわりのホスト側トラブルを避けるため、--disable-lto を付ける。
cd /d/work/gcc8
rm -rf build-gcc-final
mkdir build-gcc-final
cd build-gcc-final
../gcc-8.4.0/configure \
--target=x86_64-w64-mingw32 \
--prefix=/ucrt64 \
--with-sysroot=/ucrt64 \
--enable-languages=c,c++ \
--disable-multilib \
--disable-nls \
--disable-lto
make -j1
make install
これにより、ホスト側 gcc 16 がビルドする lto-plugin がビルド対象から外れ、
dllcrt2.o + _initterm_e まわりの LTO 特有のエラーを回避できる。
7. 完成したツールチェーンの確認¶
UCRT64 シェルで、インストールされた GCC を確認する。
/ucrt64/bin/x86_64-w64-mingw32-gcc -v
/ucrt64/bin/x86_64-w64-mingw32-g++ -v
簡単な C プログラムをビルド・実行して、
UCRT ベースの exe が正常に動作することを確認する。
cat > hello.c <<EOF
#include <stdio.h>
int main(void) {
printf("hello from UCRT GCC 8.4.0\n");
return 0;
}
EOF
/ucrt64/bin/x86_64-w64-mingw32-gcc hello.c -o hello.exe
./hello.exe
8. この手順で避けられるハマりポイント¶
/ucrt64/include を消してしまい、<algorithm> などが消える問題
gmp/mpfr/mpc 未インストールによる configure 失敗
dllcrt2.o が /ucrt64/x86_64-w64-mingw32/lib に無くて libgcc_s.dll のリンクに失敗
stage1 xgcc でリンクテストを行い、"cannot compute suffix of object files" で落ちる問題
→ CC に -B build-gcc-stage1/gcc を付けて解決
UCRT CRT と MSVCRT の混在により、_initterm_e 未定義で libgcc_s.dll のリンクが失敗
→ config/i386/t-mingw32 の SHLIB_LC に -lucrtbase を追加して解決
ホスト側 gcc 16 がビルドする lto-plugin で、dllcrt2.o + _initterm_e で落ちる問題
→ 最終 GCC では --disable-lto を指定して LTO 自体を無効化