Mac上で動作するVirtualBoxのUbuntu上でGccクロスコンパイル環境をDockerで構築

# Mac上で動作するVirtualBoxのUbuntu上でGccクロスコンパイル環境をDockerで構築
Gccのクロスコンパイル環境をMacOSで起動したVirtualbox上のUbuntuのDockerで構築しました。

なんでこんな複雑な構成にしているかというと、環境／作業によるかと思いますが、体感的にはMacOSのDockerより早い気がしているため。

## 構成

| レイヤー | 動作環境     | OS                   |
|:------:|:----------:|:---------------------:|
| ↓      | Docker     | Ubuntu18.04(ここに構築)  |
| ↓      | VirtualBox | Ubuntu18.04           |
| ↓      | Macboo     | MacOS                 |


## Docker環境のインストール
リンク先を参照ください。
[MacOS の VirtualBox Ubntu上にDocker環境を構築](https://qiita.com/tagucchan/items/3ed620a5f8e4c728f5fa)

## VirtualBox上のUbuntu18.4環境

```
tagucchan@tagvbbuntugcc:~$ uname -a
Linux tagvbbuntugcc 5.3.0-42-generic #34~18.04.1-Ubuntu SMP Fri Feb 28 13:42:26 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
tagucchan@tagvbbuntugcc:~$ lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 18.04.4 LTS
Release:	18.04
Codename:	bionic
tagucchan@tagvbbuntugcc:~$ sudo docker version
Client: Docker Engine - Community
 Version:           19.03.8
 API version:       1.40
 Go version:        go1.12.17
 Git commit:        afacb8b7f0
 Built:             Wed Mar 11 01:25:46 2020
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.8
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.17
  Git commit:       afacb8b7f0
  Built:            Wed Mar 11 01:24:19 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.2.13
  GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683
```

## Ubuntu18.04イメージをプル

```
tagucchan@tagvbbuntugcc:~$ sudo docker pull ubuntu:18.04
18.04: Pulling from library/ubuntu
5bed26d33875: Pull complete 
f11b29a9c730: Pull complete 
930bda195c84: Pull complete 
78bf9a5ad49e: Pull complete 
Digest: sha256:bec5a2727be7fff3d308193cfde3491f8fba1a2ba392b7546b43a051853a341d
Status: Downloaded newer image for ubuntu:18.04
docker.io/library/ubuntu:18.04
```

```
tagucchan@tagvbbuntugcc:~$ sudo docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              18.04               4e5021d210f6        7 days ago          64.2MB
hello-world         latest              fce289e99eb9        15 months ago       1.84kB
```

## Dockerでubuntu 18.04のコンテナを作成
```
tagucchan@tagvbbuntugcc:~$ sudo docker run -it -d --name gcc-ubuntu ubuntu:18.04 
af48c1a975a26096ca8b0df01bd33f1c083604916f23c562607635f03548deb0

tagucchan@tagvbbuntugcc:~$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
af48c1a975a2        ubuntu:18.04        "/bin/bash"         2 minutes ago       Up 2 minutes                            gcc-ubuntu
```

### "/bin/bash”を起動

```
tagucchan@tagvbbuntugcc:~$ sudo docker exec -it gcc-ubuntu /bin/bash
root@af48c1a975a2:/# 

```

## Dockerの基本的な使い方

```
docker ps -a
docker start <CONTAINER IDまたはNAME> # コンテナの起動
docker stop <CONTAINER IDまたはNAME> # コンテナの停止
```

## クロスコンパイラのビルドに必要なパッケージをインストール

```
root@af48c1a975a2:/# apt-get update
root@af48c1a975a2:/# apt-get upgrade
root@af48c1a975a2:/# apt-get install build-essential texinfo gawk
root@af48c1a975a2:/# apt-get install vim-tiny less wget rsync
```

## bisonをインストール

```
root@af48c1a975a2:/# mkdir ~/dev
root@af48c1a975a2:/# mkdir ~/dev/bison
root@af48c1a975a2:/# cd ~/dev/bison
```

### GUN M4をインストール

```
root@af48c1a975a2:/# wget https://ftp.gnu.org/gnu/m4/m4-1.4.18.tar.gz
root@af48c1a975a2:/# tar xf m4-1.4.18.tar.gz
root@af48c1a975a2:/# cd m4-1.4.18
root@af48c1a975a2:/# ./configure --prefix=/usr/local
root@af48c1a975a2:/# make
root@af48c1a975a2:/# make install
root@af48c1a975a2:/# cd ..
```

### bisonをインストール

```
root@af48c1a975a2:/# wget https://ftp.gnu.org/gnu/bison/bison-3.5.tar.gz
root@af48c1a975a2:/# tar xf bison-3.5.tar.gz
root@af48c1a975a2:/# cd bison-3.5
root@af48c1a975a2:/# ./configure --prefix=/usr/local
root@af48c1a975a2:/# make
root@af48c1a975a2:/# make install
```

## VirtualBoxのUbuntu内Dockerの情報

```
root@af48c1a975a2:/# gcc --version
gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
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.

root@af48c1a975a2:/# uname -a
Linux af48c1a975a2 5.3.0-42-generic #34~18.04.1-Ubuntu SMP Fri Feb 28 13:42:26 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

root@af48c1a975a2:/# lsb_release -a
bash: lsb_release: command not found
root@af48c1a975a2:/# apt-get install lsb-release
root@af48c1a975a2:/# lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 18.04.4 LTS
Release:	18.04
Codename:	bionic

root@af48c1a975a2:/# /lib/x86_64-linux-gnu/libc
libc-2.27.so  libc.so.6     
root@af48c1a975a2:/# /lib/x86_64-linux-gnu/libc.so.6
GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1) stable release version 2.27.
Copyright (C) 2018 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.
Compiled by GNU CC version 7.3.0.
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.

``` 

## 物理 CPU、CPU コア、および論理 CPU の数を確認

```
root@af48c1a975a2:~/dev/xgcc# grep physical.id /proc/cpuinfo | sort -u | wc -l
1
```

## シェルスクリプトを作成

```
root@af48c1a975a2:/# mkdir ~/dev/xgcc
root@af48c1a975a2:/# cd ~/dev/xgcc
```

### シェルスクリプト(ソースコードをダウンロード)

```
root@af48c1a975a2:~/dev/xgcc# vi ~/dev/xgcc/xgcc_download.sh
```

```Bash:xgcc_download.sh
#!/bin/bash

set -e

BINUTILS_VERSION=binutils-2.34
GCC_VERSION=gcc-7.3.0
LINUX_KERNEL_VERSION=linux-5.3
GLIBC_VERSION=glibc-2.27

wget -nc http://ftpmirror.gnu.org/binutils/$BINUTILS_VERSION.tar.gz
wget -nc http://ftpmirror.gnu.org/gcc/gcc-7.3.0/$GCC_VERSION.tar.gz
wget -nc https://www.kernel.org/pub/linux/kernel/v5.x/$LINUX_KERNEL_VERSION.tar.xz
wget -nc http://ftpmirror.gnu.org/glibc/$GLIBC_VERSION.tar.xz

for f in *.tar*; do
    tar xfk $f
done

cd $GCC_VERSION
./contrib/download_prerequisites
```

### シェルスクリプト(ソースコードをビルド)

```
root@af48c1a975a2:~/dev/xgcc# vi ~/dev/xgcc/xgcc_build.sh
```

```Bash:xgcc_build.sh
#!/bin/bash

set -e

PREFIX=/usr/local
# CPU 1
PARALLEL_MAKE=
#CONFIGURATION_OPTIONS="--disable-multilib --disable-nls"
CONFIGURATION_OPTIONS="--disable-multilib --disable-nls --disable-libmpx"

BINUTILS_VERSION=binutils-2.34
GCC_VERSION=gcc-7.3.0
LINUX_KERNEL_VERSION=linux-5.3
GLIBC_VERSION=glibc-2.27

build() {
    local TARGET="$1"
    local LINUX_ARCH="$2"

    # Step 1. Binutils
    mkdir -p build-binutils-$TARGET
    cd build-binutils-$TARGET
    ../$BINUTILS_VERSION/configure --prefix=$PREFIX --target=$TARGET $CONFIGURATION_OPTIONS
    make $PARALLEL_MAKE
    make install
    cd ..

    # Step 2. Linux Kernel Headers
    cd $LINUX_KERNEL_VERSION
    make ARCH=$LINUX_ARCH INSTALL_HDR_PATH=$PREFIX/$TARGET headers_install
    cd ..

    # Step 3. C/C++ Compilers
    mkdir -p build-gcc-$TARGET
    cd build-gcc-$TARGET
    ../$GCC_VERSION/configure --prefix=$PREFIX --target=$TARGET --enable-languages=c,c++ $CONFIGURATION_OPTIONS
    make $PARALLEL_MAKE gcc_cv_libc_provides_ssp=yes all-gcc
    make install-gcc
    cd ..

    # Step 4. Standard C Library Headers and Startup Files
    mkdir -p build-glibc-$TARGET
    cd build-glibc-$TARGET
    ../$GLIBC_VERSION/configure --prefix=$PREFIX/$TARGET --build=$MACHTYPE --host=$TARGET --target=$TARGET --with-headers=$PREFIX/$TARGET/include $CONFIGURATION_OPTIONS libc_cv_forced_unwind=yes
    make install-bootstrap-headers=yes install-headers
    make $PARALLEL_MAKE csu/subdir_lib
    install csu/crt1.o csu/crti.o csu/crtn.o $PREFIX/$TARGET/lib
    $TARGET-gcc -nostdlib -nostartfiles -shared -x c /dev/null -o $PREFIX/$TARGET/lib/libc.so
    touch $PREFIX/$TARGET/include/gnu/stubs.h
    cd ..

    # Step 5. Compiler Support Library
    cd build-gcc-$TARGET
    make $PARALLEL_MAKE all-target-libgcc
    make install-target-libgcc
    cd ..

    # Step 6. Standard C Library & the rest of Glibc
    cd build-glibc-$TARGET
    make $PARALLEL_MAKE
    make install
    cd ..

    # Step 7. Standard C++ Library & the rest of GCC
    cd build-gcc-$TARGET
    make $PARALLEL_MAKE all
    make install
    cd ..

    rm -rf build-binutils-$TARGET build-gcc-$TARGET build-glibc-$TARGET
}

build i686-linux-gnu x86
build arm-linux-gnueabi arm
build arm-linux-gnueabihf arm
build aarch64-linux-gnu arm64
build mips-linux-gnu mips
build mipsel-linux-gnu mips
build mips64el-linux-gnuabi64 mips

# 以下は私の環境ではエラーが出て駄目でした。
#build powerpc-linux-gnu powerpc
#build powerpc64le-linux-gnu powerpc
#build alpha-linux-gnu alpha
#build s390x-linux-gnu s390
#build m68k-linux-gnu m68k

# 以下は不要のため試していません
#build x86_64-linux-gnu x86
#build sparc-linux-gnu sparc
#build sparc64-linux-gnu sparc
#build cris-linux-gnu cris
#build sh4-linux-gnu sh
```

### シェルスクリプト(各アーキテクチャのbinutilsをビルド)

```
root@af48c1a975a2:~/dev/xgcc# vi ~/dev/xgcc/xgcc_build_all_binutils.sh
```

```Bash:xgcc_build_all_binutils.sh
#!/bin/bash
# build-binutils-all.sh

set -e

PREFIX=/usr/local
# cpu 1
PARALLEL_MAKE=
CONFIGURATION_OPTIONS="--disable-multilib --disable-nls"

BINUTILS_VERSION=binutils-2.34

mkdir -p build_all_binutils
cd build_all_binutils
../$BINUTILS_VERSION/configure --prefix=$PREFIX --enable-targets=all --enable-64-bit-bfd --program-prefix=all- $CONFIGURATION_OPTIONS
make $PARALLEL_MAKE
make install
cd ..

rm -rf build_all_binutils
```

## スクリプトを実行
要:かなりの時間とディスク容量

```
root@af48c1a975a2:~/dev/xgcc# cd ~/dev/xgcc
root@af48c1a975a2:~/dev/xgcc# bash xgcc_download.sh
root@af48c1a975a2:~/dev/xgcc# nohup bash xgcc_build.sh &
root@af48c1a975a2:~/dev/xgcc# nohup bash xgcc_build_all_binutils.sh &
```

## 動作テスト（MIPS向けのアセンブリ出力）
```
root@af48c1a975a2:~/dev/xgcc#  mkdir test
root@af48c1a975a2:~/dev/xgcc# cd test
root@af48c1a975a2:~/dev/xgcc/test# vi main.c
```

```C:main.c
#include <stdio.h>
int main(void) {
   printf("Hellow");
   return 0;
}
```

### 実行例

```
root@af48c1a975a2:~/dev/xgcc/test# mips-linux-gnu-gcc -S main.c
root@af48c1a975a2:~/dev/xgcc/test# cat main.s 
	.file	1 "main.c"
	.section .mdebug.abi32
	.previous
	.nan	legacy
	.module	fp=32
	.module	nooddspreg
	.abicalls
	.text
	.rdata
	.align	2
$LC0:
	.ascii	"Hellow\000"
	.text
	.align	2
	.globl	main
	.set	nomips16
	.set	nomicromips
	.ent	main
	.type	main, @function
main:
	.frame	$fp,32,$31		# vars= 0, regs= 2/0, args= 16, gp= 8
	.mask	0xc0000000,-4
	.fmask	0x00000000,0
	.set	noreorder
	.set	nomacro
	addiu	$sp,$sp,-32
	sw	$31,28($sp)
	sw	$fp,24($sp)
	move	$fp,$sp
	lui	$28,%hi(__gnu_local_gp)
	addiu	$28,$28,%lo(__gnu_local_gp)
	.cprestore	16
	lui	$2,%hi($LC0)
	addiu	$4,$2,%lo($LC0)
	lw	$2,%call16(printf)($28)
	nop
	move	$25,$2
	.reloc	1f,R_MIPS_JALR,printf
1:	jalr	$25
	nop

	lw	$28,16($fp)
	move	$2,$0
	move	$sp,$fp
	lw	$31,28($sp)
	lw	$fp,24($sp)
	addiu	$sp,$sp,32
	jr	$31
	nop

	.set	macro
	.set	reorder
	.end	main
	.size	main, .-main
	.ident	"GCC: (GNU) 7.3.0"
root@af48c1a975a2:~/dev/xgcc/test# 
```

## Dockerコンテナを停止

```
exit  # Ubuntuのshellから抜ける
docker stop gcc-ubuntu # コンテナが停止
docker ps -a # 停止確認
```