8
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-02-10

記事の内容

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

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


$ 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パッケージをインストールします。


sudo apt install gcc g++ m4 make texinfo

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


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

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

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

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


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

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


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

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


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のビルド&インストール

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


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

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


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

mpfrのビルド&インストール

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


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

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


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

mpcのビルド&インストール

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


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

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


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を指定します。
以下の手順でインストールまで行います。


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

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


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して中を見てみます。


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

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

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

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

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

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

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


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

sudo ln -s x86_64-w64-mingw32 mingw

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


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

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


cd mingw

sudo ln -s lib lib64

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


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

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


cd bin

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

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

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


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を指定してインストールします。
理屈はわかりませんが、試行錯誤の結果これでうまくいきました。


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して中を見てみます。


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

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

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

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 バイナリをクロスコンパイルする


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等のクロスコンパイラが加わって、ファイルが増えています。


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} は実際の値で書き直してください)。


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

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


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と表示されました。


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を指定します。


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して中を見てみます。


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

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
(以下略)

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(クロスコンパイラ)の残りをコンパイル/インストール

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


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

make

sudo make install

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

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

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


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」オプションを与えると、スタティックリンクされます。
ダイナミックリンクとスタティックリンクの両方でコンパイルしてみます。


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

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

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


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

02.png

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


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

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

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!
8
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?