最新のgccでWindows用にコンパイルしたいので、MinGW-w64クロスコンパイラ（64bit）をソースコードからビルドした

# 記事の内容

自作プログラムをWindows用にgccでコンパイルしたいとします。
Cygwin等、何種類かソリューションがありますが、本記事ではMinGW-w64クロスコンパイラを使用します。

MinGW-w64クロスコンパイラは、Ubuntuで「sudo apt install mingw-w64」でインストールできますので、試したところgccのバージョンが7.3でした。

```bash

$ x86_64-w64-mingw32-gcc --version
x86_64-w64-mingw32-gcc (GCC) 7.3-win32 20180312
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```

C++を使う場合は、言語の進化に追随して新しいコンパイラを使いたいことが多いと思います。
そこで本記事では、パッケージからインストールしたクロスコンパイラを使用せず、新しいバージョンのソースコードからMinGW-w64クロスコンパイラをビルドしました。

# クロスコンパイラのビルド手順

ビルド作業は、Windows10のWSL（Ubuntu 18.04）で行いました。
「/opt」の下に各ソフトウェア毎にサブディレクトリを作成して、インストール先とします。

## 事前準備

以下のように、ビルドに必要なUbuntuパッケージをインストールします。

```bash

sudo apt install gcc g++ m4 make texinfo
```

以下のように、ビルド作業で使用するディレクトリを作成しておきます。
ターボールのダウンロード先、ソースコードの展開先、ビルド作業ディレクトリです。

```bash

mkdir -p $HOME/Downloads $HOME/src $HOME/build
```

## ターボールのダウンロードとソースコードの展開

以下のサイトで、インストールするソフトウェアの新しいバージョンを調査します。

- gmp入手先：http://gmplib.org/
- mpfr入手先：http://www.mpfr.org/mpfr-current/
- mpc入手先：http://www.multiprecision.org/mpc/download.html
- binutils入手先：http://ftp.gnu.org/gnu/binutils/
- mingw-w64 toolchain入手先：https://sourceforge.net/projects/mingw-w64/files/mingw-w64/mingw-w64-release/
- gcc入手先：https://gcc.gnu.org/

以下のように、使用するバージョンを環境変数に設定しました。
本記事でインストールするgccのバージョンは9.2.0です。

```bash

export VERSION_GMP=6.2.0

export VERSION_MPFR=4.0.2

export VERSION_MPC=1.1.0

export VERSION_BINUTILS=2.34

export VERSION_MINGW_W64=v7.0.0

export VERSION_GCC=9.2.0
```

以下のように、ターボールをダウンロードします。

```bash

cd $HOME/Downloads

wget https://gmplib.org/download/gmp/gmp-${VERSION_GMP}.tar.xz

wget https://www.mpfr.org/mpfr-current/mpfr-${VERSION_MPFR}.tar.xz

wget https://ftp.gnu.org/gnu/mpc/mpc-${VERSION_MPC}.tar.gz

wget http://ftp.gnu.org/gnu/binutils/binutils-${VERSION_BINUTILS}.tar.bz2

wget https://sourceforge.net/projects/mingw-w64/files/mingw-w64/mingw-w64-release/mingw-w64-${VERSION_MINGW_W64}.tar.bz2

wget http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-${VERSION_GCC}/gcc-${VERSION_GCC}.tar.xz
```

以下のように、ソースコードを展開します。

```bash

cd $HOME/src

tar xf $HOME/Downloads/gmp-${VERSION_GMP}.tar.xz

tar xf $HOME/Downloads/mpfr-${VERSION_MPFR}.tar.xz

tar xf $HOME/Downloads/mpc-${VERSION_MPC}.tar.gz

tar xf $HOME/Downloads/binutils-${VERSION_BINUTILS}.tar.bz2

tar xf $HOME/Downloads/mingw-w64-${VERSION_MINGW_W64}.tar.bz2

tar xf $HOME/Downloads/gcc-${VERSION_GCC}.tar.xz
```

## gmpのビルド＆インストール

以下の手順でインストールまで行います。

```bash

cd $HOME/build

mkdir gmp-${VERSION_GMP}

cd gmp-${VERSION_GMP}

$HOME/src/gmp-${VERSION_GMP}/configure ABI=64 --prefix=/opt/gmp-${VERSION_GMP} --enable-cxx

make

sudo make install
```

以下のように、インストールされたことを確認しました。

```bash

username:~/build/gmp-6.2.0$ ls /opt
gmp-6.2.0
```

## mpfrのビルド＆インストール

以下の手順でインストールまで行います。

```bash

cd $HOME/build

mkdir mpfr-${VERSION_MPFR}

cd mpfr-${VERSION_MPFR}

$HOME/src/mpfr-${VERSION_MPFR}/configure ABI=64 --prefix=/opt/mpfr-${VERSION_MPFR} --with-gmp=/opt/gmp-${VERSION_GMP}

make

sudo make install

```

以下のように、インストールされたことを確認しました。

```bash

username:~/build/mpfr-4.0.2$ ls /opt
gmp-6.2.0
mpfr-4.0.2
```

## mpcのビルド＆インストール

以下の手順でインストールまで行います。

```bash

cd $HOME/build

mkdir mpc-${VERSION_MPC}

cd mpc-${VERSION_MPC}

$HOME/src/mpc-${VERSION_MPC}/configure ABI=64 --prefix=/opt/mpc-${VERSION_MPC} --with-gmp=/opt/gmp-${VERSION_GMP} --with-mpfr=/opt/mpfr-${VERSION_MPFR}

make

sudo make install
```

以下のように、インストールされたことを確認しました。

```bash

username:~/build/mpc-1.1.0$ ls /opt
gmp-6.2.0
mpc-1.1.0
mpfr-4.0.2
```

## binutilsのビルド＆インストール

クロスコンパイラのビルドですので、targetとしてx86_64-w64-mingw32を指定します。
以下の手順でインストールまで行います。

```bash

cd $HOME/build

mkdir binutils-${VERSION_BINUTILS}

cd binutils-${VERSION_BINUTILS}

$HOME/src/binutils-${VERSION_BINUTILS}/configure --target=x86_64-w64-mingw32 --disable-multilib --with-sysroot=/opt/mingw-w64-${VERSION_MINGW_W64}-gcc-${VERSION_GCC} --prefix=/opt/mingw-w64-${VERSION_MINGW_W64}-gcc-${VERSION_GCC} --with-windres --with-windmc

make

sudo make install
```

以下のように、インストールされたことを確認しました。

```bash

username:~/build/binutils-2.34$ ls /opt
gmp-6.2.0
mingw-w64-v7.0.0-gcc-9.2.0
mpc-1.1.0
mpfr-4.0.2
```

インストール先にcdして中を見てみます。

```bash

username:~/build/binutils-2.34$ cd /opt/mingw-w64-${VERSION_MINGW_W64}-gcc-${VERSION_GCC}/
```

```bash

username:/opt/mingw-w64-v7.0.0-gcc-9.2.0$ ls
bin
share
x86_64-w64-mingw32
```

```bash

username:/opt/mingw-w64-v7.0.0-gcc-9.2.0$ ls bin
x86_64-w64-mingw32-addr2line
x86_64-w64-mingw32-ar
x86_64-w64-mingw32-as
x86_64-w64-mingw32-c++filt
x86_64-w64-mingw32-dlltool
x86_64-w64-mingw32-dllwrap
x86_64-w64-mingw32-elfedit
x86_64-w64-mingw32-gprof
x86_64-w64-mingw32-ld
x86_64-w64-mingw32-ld.bfd
x86_64-w64-mingw32-nm
x86_64-w64-mingw32-objcopy
x86_64-w64-mingw32-objdump
x86_64-w64-mingw32-ranlib
x86_64-w64-mingw32-readelf
x86_64-w64-mingw32-size
x86_64-w64-mingw32-strings
x86_64-w64-mingw32-strip
x86_64-w64-mingw32-windmc
x86_64-w64-mingw32-windres
```

```bash

username:/opt/mingw-w64-v7.0.0-gcc-9.2.0$ ls x86_64-w64-mingw32/
bin
lib
```

```bash

username:/opt/mingw-w64-v7.0.0-gcc-9.2.0$ ls x86_64-w64-mingw32/bin
ar
as
dlltool
ld
ld.bfd
nm
objcopy
objdump
ranlib
readelf
strip
```

```bash

username:/opt/mingw-w64-v7.0.0-gcc-9.2.0$ ls x86_64-w64-mingw32/lib
ldscripts
```

以下のように、シンボリックリンクを作ります（その1）。

```bash

cd /opt/mingw-w64-${VERSION_MINGW_W64}-gcc-${VERSION_GCC}

sudo ln -s x86_64-w64-mingw32 mingw
```

シンボリックリンクが作られたか確認：

```bash

username:/opt/mingw-w64-v7.0.0-gcc-9.2.0$ ll
bin
mingw -> x86_64-w64-mingw32
share
x86_64-w64-mingw32
```

以下のように、シンボリックリンクを作ります（その2）。

```bash

cd mingw

sudo ln -s lib lib64
```

シンボリックリンクが作られたか確認：

```bash

username:/opt/mingw-w64-v7.0.0-gcc-9.2.0/mingw$ ll
bin/
lib/
lib64 -> lib/
```

以下のように、シンボリックリンクを作ります（その3）。

```bash

cd bin

sudo ln -s ../../bin/x86_64-w64-mingw32-windres windres

sudo ln -s ../../bin/x86_64-w64-mingw32-windmc windmc
```

シンボリックリンクが作られたか確認：

```bash

username:/opt/mingw-w64-v7.0.0-gcc-9.2.0/mingw/bin$ ll wind*
windmc -> ../../bin/x86_64-w64-mingw32-windmc*
windres -> ../../bin/x86_64-w64-mingw32-windres*
```

## 「mingw-w64 toolchain」の中の、headerをインストール

binutilsではtargetにx86_64-w64-mingw32を指定しましたが、headerでは以下のようにhostにx86_64-w64-mingw32を指定してインストールします。
理屈はわかりませんが、試行錯誤の結果これでうまくいきました。


```bash

cd $HOME/build

mkdir -p mingw-w64-${VERSION_MINGW_W64}/mingw-w64-headers

cd mingw-w64-${VERSION_MINGW_W64}/mingw-w64-headers

$HOME/src/mingw-w64-${VERSION_MINGW_W64}/mingw-w64-headers/configure --host=x86_64-w64-mingw32 --prefix=/opt/mingw-w64-${VERSION_MINGW_W64}-gcc-${VERSION_GCC}/x86_64-w64-mingw32

sudo make install
```

インストール先にcdして中を見てみます。

```bash

cd /opt/mingw-w64-${VERSION_MINGW_W64}-gcc-${VERSION_GCC}
```

```bash

username:/opt/mingw-w64-v7.0.0-gcc-9.2.0$ ls
bin
mingw
share
x86_64-w64-mingw32
```

```bash

username:/opt/mingw-w64-v7.0.0-gcc-9.2.0$ ls mingw
bin
include
lib
lib64
```

```bash

username:/opt/mingw-w64-v7.0.0-gcc-9.2.0$ ls mingw/include
GL
KHR
_bsd_types.h
_cygwin.h
_dbdao.h
_mingw.h
_mingw_dxhelper.h
_mingw_mac.h
_mingw_off_t.h
_mingw_secapi.h
_mingw_stat64.h
_mingw_stdarg.h
_mingw_unicode.h
_timeval.h
accctrl.h
aclapi.h
（以下略）
```

## gcc（クロスコンパイラ）のコア部分のコンパイル／インストール

以下の手順でインストールまで行います。
targetにx86_64-w64-mingw32を指定します。
コンパイラの言語はc、c++、fortranを指定しましたが、お好みの言語をどうぞ。

また、std::threadでのコンパイルエラーを避けるために、Thread modelにposixを指定しました。
参考：[Ubuntu 16.04 で MinGW を使い C++11 プログラムの Windows バイナリをクロスコンパイルする](https://qiita.com/syoyo/items/678f9c3c82d5f6f5607c)

```bash

cd $HOME/build

mkdir mingw-w64-gcc-${VERSION_GCC}

cd mingw-w64-gcc-${VERSION_GCC}

$HOME/src/gcc-${VERSION_GCC}/configure --target=x86_64-w64-mingw32 --disable-multilib --prefix=/opt/mingw-w64-${VERSION_MINGW_W64}-gcc-${VERSION_GCC} --with-sysroot=/opt/mingw-w64-${VERSION_MINGW_W64}-gcc-${VERSION_GCC} --with-gmp=/opt/gmp-${VERSION_GMP} --with-mpfr=/opt/mpfr-${VERSION_MPFR} --with-mpc=/opt/mpc-${VERSION_MPC} --with-headers=/opt/mingw-w64-${VERSION_MINGW_W64}-gcc-${VERSION_GCC}/mingw/include --with-libs=/opt/mingw-w64-${VERSION_MINGW_W64}-gcc-${VERSION_GCC}/mingw/lib --with-threads=posix --enable-languages=c,c++,fortran --enable-__cxa_atexit --enable-libstdcxx-allocator=new

make all-gcc

sudo make install-gcc
```

以下のように、インストール先のbinサブディレクトリ配下のファイルを確認しました。
binutilsをインストールした時と比べると、gcc、g++、gfortran等のクロスコンパイラが加わって、ファイルが増えています。

```bash

username:~/build/mingw-w64-gcc-9.2.0$ ls /opt/mingw-w64-${VERSION_MINGW_W64}-gcc-${VERSION_GCC}/bin
x86_64-w64-mingw32-addr2line
x86_64-w64-mingw32-ar
x86_64-w64-mingw32-as
x86_64-w64-mingw32-c++
x86_64-w64-mingw32-c++filt
x86_64-w64-mingw32-cpp
x86_64-w64-mingw32-dlltool
x86_64-w64-mingw32-dllwrap
x86_64-w64-mingw32-elfedit
x86_64-w64-mingw32-g++
x86_64-w64-mingw32-gcc
x86_64-w64-mingw32-gcc-9.2.0
x86_64-w64-mingw32-gcc-ar
x86_64-w64-mingw32-gcc-nm
x86_64-w64-mingw32-gcc-ranlib
x86_64-w64-mingw32-gcov
x86_64-w64-mingw32-gcov-dump
x86_64-w64-mingw32-gcov-tool
x86_64-w64-mingw32-gfortran
x86_64-w64-mingw32-gprof
x86_64-w64-mingw32-ld
x86_64-w64-mingw32-ld.bfd
x86_64-w64-mingw32-nm
x86_64-w64-mingw32-objcopy
x86_64-w64-mingw32-objdump
x86_64-w64-mingw32-ranlib
x86_64-w64-mingw32-readelf
x86_64-w64-mingw32-size
x86_64-w64-mingw32-strings
x86_64-w64-mingw32-strip
x86_64-w64-mingw32-windmc
x86_64-w64-mingw32-windres
```

以下のように、上で確認したbinサブディレクトリにPATHを通します。
.bashrcにも追加しておくと良いでしょう（ \${VERSION_MINGW_W64} と \${VERSION_GCC} は実際の値で書き直してください）。

```bash

export PATH=/opt/mingw-w64-${VERSION_MINGW_W64}-gcc-${VERSION_GCC}/bin:$PATH
```

クロスコンパイラにPATHが通ったか、以下のようにwhichコマンドで確認しました。

```bash

username:~/build/mingw-w64-gcc-9.2.0$ which x86_64-w64-mingw32-g++
/opt/mingw-w64-v7.0.0-gcc-9.2.0/bin/x86_64-w64-mingw32-g++
```

以下のように、クロスコンパイラのバージョンを表示させてみました。
9.2.0と表示されました。

```bash

username:~/build/mingw-w64-gcc-9.2.0$ x86_64-w64-mingw32-g++ --version
x86_64-w64-mingw32-g++ (GCC) 9.2.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```

## 「mingw-w64 toolchain」の中の、crt関連をインストール

以下の手順でインストールまで行います。
hostにx86_64-w64-mingw32を指定します。

```bash

cd $HOME/build

mkdir -p mingw-w64-${VERSION_MINGW_W64}/mingw-w64-crt

cd mingw-w64-${VERSION_MINGW_W64}/mingw-w64-crt

$HOME/src/mingw-w64-${VERSION_MINGW_W64}/mingw-w64-crt/configure --host=x86_64-w64-mingw32 --prefix=/opt/mingw-w64-${VERSION_MINGW_W64}-gcc-${VERSION_GCC}/x86_64-w64-mingw32 --with-sysroot=/opt/mingw-w64-${VERSION_MINGW_W64}-gcc-${VERSION_GCC}

make

sudo -s

make install

exit
```

インストール先にcdして中を見てみます。

```bash

username:/opt/mingw-w64-v7.0.0-gcc-9.2.0/mingw/lib$ cd /opt/mingw-w64-${VERSION_MINGW_W64}-gcc-${VERSION_GCC}/mingw
```

```bash

gcc-9.2.0/mingw$ ls lib
CRT_fp10.o
CRT_fp8.o
CRT_glob.o
CRT_noglob.o
binmode.o
crt1.o
crt1u.o
crt2.o
crt2u.o
crtbegin.o
crtend.o
dllcrt1.o
dllcrt2.o
gcrt0.o
gcrt1.o
gcrt2.o
ldscripts
libCINTIME.a
libPS5UI.a
（以下略）
```

```bash

gcc-9.2.0/mingw$ ls lib32
CRT_fp10.o
CRT_fp8.o
CRT_glob.o
CRT_noglob.o
binmode.o
crt1.o
crt1u.o
crt2.o
crt2u.o
crtbegin.o
crtend.o
dllcrt1.o
dllcrt2.o
gcrt0.o
gcrt1.o
gcrt2.o
libaclui.a
libactiveds.a
（以下略）
```

## gcc（クロスコンパイラ）の残りをコンパイル／インストール

以下の手順で、残り全てをインストールします。

```bash

cd $HOME/build/mingw-w64-gcc-${VERSION_GCC}

make

sudo make install
```

以上でクロスコンパイラのインストールは完了です。

# サンプルプログラムで確認

適当なディレクトリでサンプルプログラムを作ってコンパイルしてみます。

```bash

cd

editor hello.cpp
```

サンプルプログラムのソースコード：

```hello.cpp

// x86_64-w64-mingw32-g++ -o hello_d.exe hello.cpp
// x86_64-w64-mingw32-g++ -o hello_s.exe hello.cpp -static
#include <iostream>

int main()
{
    std::cout << "Hello world!" << std::endl;
}
```

以下のようにクロスコンパイルします。
「-static」オプションを与えると、スタティックリンクされます。
ダイナミックリンクとスタティックリンクの両方でコンパイルしてみます。

```bash

x86_64-w64-mingw32-g++ -o hello_d.exe hello.cpp

x86_64-w64-mingw32-g++ -o hello_s.exe hello.cpp -static
```

以下のように、ファイルサイズを確認してみます。
スタティックリンク版はでかいです。

```bash

username:~$ ll hello*
     193 hello.cpp
  331661 hello_d.exe*
14729708 hello_s.exe*
```

実行ファイルをWindows側に転送して動かしてみます。
スタティックリンク版は、以下のように動きました。

```

>hello_s.exe
Hello world!
```

ダイナミックリンク版を動かすと、以下のようにdllが見つからないと叱られました。

```

>hello_d.exe
```

![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327312/b319eec8-ee5b-6257-a332-4d5683e84c0b.png)

![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327312/b2f1c0a7-f216-539c-f77c-6def5d21d350.png)

以下のように、必要なdllをUbuntu側で探して、Windows側に転送します。

```bash

username:~/build/mingw-w64-gcc-9.2.0$ cd /opt/mingw-w64-${VERSION_MINGW_W64}-gcc-${VERSION_GCC}
```

```bash

username:/opt/mingw-w64-v7.0.0-gcc-9.2.0$ find . -name 'libstdc++*.dll'
./x86_64-w64-mingw32/lib/libstdc++-6.dll
```

```bash

username:/opt/mingw-w64-v7.0.0-gcc-9.2.0$ find . -name 'libgcc_s_*.dll'
./x86_64-w64-mingw32/lib/libgcc_s_seh-1.dll
```

dllがあると、以下のようにダイナミックリンク版も動きました。

```

>hello_d.exe
Hello world!
```