いけむランド

はてダからやってきました

Mac OS X で動く cygwin クロスコンパイラを作成する

以前、試みてから 10 年以上経っていたため、あらためて最新のソースから作成してみることにしました。

環境

$ uname -v
Darwin Kernel Version 19.6.0: Thu Jun 18 20:49:00 PDT 2020; root:xnu-6153.141.1~1/RELEASE_X86_64
$ brew -v
Homebrew 2.4.12
Homebrew/homebrew-core (git revision e6b6; last commit 2020-08-17)
Homebrew/homebrew-cask (git revision 205fe; last commit 2020-08-18)
$

ディレクトリ準備

以下の構成とします。

  • /usr/local/cygwin
    • sys-root : cygwin 上のシステムルート
    • bin, lib, ... : ツールチェイン

ターゲットのヘッダとライブラリ

ターゲットのヘッダおよびライブラリとしては以下のパッケージが必要となります。

wget などでダウンロードして、sys-root に展開します。

$ cd ~/Downloads
$ wget http://ftp.iij.ad.jp/pub/cygwin/x86_64/release/cygwin/cygwin-3.1.6-1.tar.xz
$ wget http://ftp.iij.ad.jp/pub/cygwin/x86_64/release/cygwin/cygwin-devel/cygwin-devel-3.1.6-1.tar.xz
$ wget http://ftp.iij.ad.jp/pub/cygwin/x86_64/release/w32api-headers/w32api-headers-7.0.0-1.tar.xz
$ wget http://ftp.iij.ad.jp/pub/cygwin/x86_64/release/w32api-runtime/w32api-runtime-7.0.0-1.tar.xz
$ cd /usr/local/cygwin/sys-root
$ tar fx ~/Downloads/cygwin-3.1.6-1.tar.xz
$ tar fx ~/Downloads/cygwin-devel-3.1.6-1.tar.xz
$ tar fx ~/Downloads/w32api-headers-7.0.0-1.tar.xz
$ tar fx ~/Downloads/w32api-runtime-7.0.0-1.tar.xz
$

どうしても gcc のビルド時に sys-root/usr/lib/w32api を見に行かない問題があったため、 必要なライブラリを sys-root/usr/lib にシンボリックリンクして、誤魔化しておきます。

$ cd /usr/local/cygwin/sys-root/usr/lib
$ ln -s w32api/libadvapi32.a .
$ ln -s w32api/libkernel32.a .
$ ln -s w32api/libuser32.a .
$ ln -s w32api/libshell32.a .
$

ホストのヘッダとライブラリ

binutils および gcc をビルドするために必要なライブラリを homebrew でインストールしておきます。

$ brew install gcc gmp isl libmpc mpfr
$

ビルドには gcc を使いたい (clang 由来の問題を避けたい) ため、gcc のセルフコンパイラも追加しておきます。

binutils のビルド

binutils をダウンロードして、ビルドします。

$ cd ~/Downloads
$ wget http://ftp.iij.ad.jp/pub/gnu/binutils/binutils-2.35.tar.xz
$ tar fx binutils-2.35.tar.xz
$ cd binutils-2.35
$ mkdir build
$ cd build
$ ../configure --prefix=/usr/local/cygwin --target=x86_64-pc-cygwin --with-gmp=/usr/local --with-isl=/usr/local --with-mpc=/usr/local --with-mpfr=/usr/local --with-system-zlib CC=gcc-10 CXX=g++-10 CPP=cpp-10
$ make
$ make install
$

gcc のビルド前に binutils のインストール先をパスに追加しておきます。

$ export PATH=/usr/local/cygwin/bin:${PATH}
$

gcc のビルド

gcc をダウンロードして、ビルドします。

$ cd ~/Downloads
$ wget http://ftp.iij.ad.jp/pub/gnu/gcc/gcc-10.2.0/gcc-10.2.0.tar.xz
$ tar fx gcc-10.2.0.tar.xz
$ cd gcc-10.2.0
$ mkdir build
$ ../configure --prefix=/usr/local/cygwin --target=x86_64-pc-cygwin --with-gmp=/usr/local --with-isl=/usr/local --with-mpc=/usr/local --with-mpfr=/usr/local --with-system-zlib --disable-multilib --with-sysroot=/usr/local/cygwin/sys-root --enable-threads=posix --enable-languages=c,c++ CC=gcc-10 CXX=g++-10 CPP=cpp-10
$ make
$ make install
$

クロスコンパイル

さっそくクロスコンパイラを使ってみます。

$ cd /tmp
$ vi main.c
$ cat main.c
#include <stdio.h>
int main(int argc, char** argv)
{
  printf("Hello, world!\n");
}
$ x86_64-pc-cygwin-gcc main.c -v
Using built-in specs.
COLLECT_GCC=x86_64-pc-cygwin-gcc
COLLECT_LTO_WRAPPER=/usr/local/cygwin/libexec/gcc/x86_64-pc-cygwin/10.2.0/lto-wrapper
Target: x86_64-pc-cygwin
Configured with: ../configure --prefix=/usr/local/cygwin --target=x86_64-pc-cygwin --with-gmp=/usr/local --with-isl=/usr/local --with-mpc=/usr/local --with-mpfr=/usr/local --with-system-zlib --disable-multilib --with-sysroot=/usr/local/cygwin/sys-root --enable-threads=posix --enable-languages=c,c++ CC=gcc-10 CXX=g++-10 CPP=cpp-10
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 10.2.0 (GCC)
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
 /usr/local/cygwin/libexec/gcc/x86_64-pc-cygwin/10.2.0/cc1 -quiet -v -Dunix -idirafter /usr/local/cygwin/sys-root/usr/lib/../lib/../include/w32api -idirafter ../../include/w32api main.c -quiet -dumpbase main.c -mtune=generic -march=x86-64 -auxbase main -version -o /var/folders/mw/zppx91z12_1342n6c9l7jpm00000gn/T//cc9jLDrX.s
GNU C17 (GCC) version 10.2.0 (x86_64-pc-cygwin)
    compiled by GNU C version 10.2.0, GMP version 6.2.0, MPFR version 4.1.0, MPC version 1.1.0, isl version isl-0.22.1-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/cygwin/sys-root/usr/local/include"
ignoring nonexistent directory "../../include/w32api"
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/cygwin/lib/gcc/x86_64-pc-cygwin/10.2.0/include
 /usr/local/cygwin/lib/gcc/x86_64-pc-cygwin/10.2.0/include-fixed
 /usr/local/cygwin/lib/gcc/x86_64-pc-cygwin/10.2.0/../../../../x86_64-pc-cygwin/include
 /usr/local/cygwin/sys-root/usr/include
 /usr/local/cygwin/sys-root/usr/lib/../lib/../include/w32api
End of search list.
GNU C17 (GCC) version 10.2.0 (x86_64-pc-cygwin)
    compiled by GNU C version 10.2.0, GMP version 6.2.0, MPFR version 4.1.0, MPC version 1.1.0, isl version isl-0.22.1-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: fd3e9e33e076cf33c516e98e96dcaa66
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
 /usr/local/cygwin/lib/gcc/x86_64-pc-cygwin/10.2.0/../../../../x86_64-pc-cygwin/bin/as -o /var/folders/mw/zppx91z12_1342n6c9l7jpm00000gn/T//ccRTXdxk.o /var/folders/mw/zppx91z12_1342n6c9l7jpm00000gn/T//cc9jLDrX.s
COMPILER_PATH=/usr/local/cygwin/libexec/gcc/x86_64-pc-cygwin/10.2.0/:/usr/local/cygwin/libexec/gcc/x86_64-pc-cygwin/10.2.0/:/usr/local/cygwin/libexec/gcc/x86_64-pc-cygwin/:/usr/local/cygwin/lib/gcc/x86_64-pc-cygwin/10.2.0/:/usr/local/cygwin/lib/gcc/x86_64-pc-cygwin/:/usr/local/cygwin/lib/gcc/x86_64-pc-cygwin/10.2.0/../../../../x86_64-pc-cygwin/bin/
LIBRARY_PATH=/usr/local/cygwin/lib/gcc/x86_64-pc-cygwin/10.2.0/:/usr/local/cygwin/lib/gcc/x86_64-pc-cygwin/10.2.0/../../../../x86_64-pc-cygwin/lib/../lib/:/usr/local/cygwin/sys-root/usr/lib/../lib/:/usr/local/cygwin/lib/gcc/x86_64-pc-cygwin/10.2.0/../../../../x86_64-pc-cygwin/lib/:/usr/local/cygwin/sys-root/usr/lib/
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
 /usr/local/cygwin/libexec/gcc/x86_64-pc-cygwin/10.2.0/collect2 -plugin /usr/local/cygwin/libexec/gcc/x86_64-pc-cygwin/10.2.0/liblto_plugin.so -plugin-opt=/usr/local/cygwin/libexec/gcc/x86_64-pc-cygwin/10.2.0/lto-wrapper -plugin-opt=-fresolution=/var/folders/mw/zppx91z12_1342n6c9l7jpm00000gn/T//cc3vONWl.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lcygwin -plugin-opt=-pass-through=-ladvapi32 -plugin-opt=-pass-through=-lshell32 -plugin-opt=-pass-through=-luser32 -plugin-opt=-pass-through=-lkernel32 -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --sysroot=/usr/local/cygwin/sys-root -m i386pep --wrap _Znwm --wrap _Znam --wrap _ZdlPv --wrap _ZdaPv --wrap _ZnwmRKSt9nothrow_t --wrap _ZnamRKSt9nothrow_t --wrap _ZdlPvRKSt9nothrow_t --wrap _ZdaPvRKSt9nothrow_t -Bdynamic --dll-search-prefix=cyg --tsaware /usr/local/cygwin/sys-root/usr/lib/../lib/crt0.o /usr/local/cygwin/lib/gcc/x86_64-pc-cygwin/10.2.0/crtbegin.o -L/usr/local/cygwin/lib/gcc/x86_64-pc-cygwin/10.2.0 -L/usr/local/cygwin/lib/gcc/x86_64-pc-cygwin/10.2.0/../../../../x86_64-pc-cygwin/lib/../lib -L/usr/local/cygwin/sys-root/usr/lib/../lib -L/usr/local/cygwin/lib/gcc/x86_64-pc-cygwin/10.2.0/../../../../x86_64-pc-cygwin/lib -L/usr/local/cygwin/sys-root/usr/lib /var/folders/mw/zppx91z12_1342n6c9l7jpm00000gn/T//ccRTXdxk.o -lgcc_s -lgcc -lcygwin -ladvapi32 -lshell32 -luser32 -lkernel32 -lgcc_s -lgcc /usr/local/cygwin/lib/gcc/x86_64-pc-cygwin/10.2.0/crtend.o
COLLECT_GCC_OPTIONS='-v' '-mtune=generic' '-march=x86-64'
$ file a.exe
a.exe: PE32+ executable (console) x86-64, for MS Windows
$

実行

Windows 環境に a.exe を持っていき、実行してみます。

$ uname -mrs
CYGWIN_NT-10.0 3.1.6(0.340/5/3) x86_64
$ ./a.exe
Hello, world!
$