Build Qt5.12.0 for RaspberryPi

# 各種条件
Long Term Support の Qt5.12.0 が出ているので、それを Raspberry Pi (以降RPi) 用にビルドする手順を残します。
(ARMv6 も含めた全シリーズ向けのビルドになり、ARMv7 以降の最適化は適用していません)
作業環境は、Ubuntu16.04(x86-64) で行っていますが、debian 系であれば差異はないと思います。
また、本記事で対象とした Raspbian は 2018-11-13-raspbian-stretch です。

まず、必要なファイル群の置き場とその環境変数を下記として作業を進めます。

|項目|環境変数|設定値|
|:--|:---|:--|
| 作業場 | WORK_PATH | /home/user/work |
| RPi ルートファイルシステム | RPI_ROOTFS | /home/user/work/raspbian |
| クロスコンパイラの保管場所 | CROSS_TOOLS | /home/user/work/tools |
| 作業用パス | QT_SOURCE | /home/user/work/qt5.12.0/src |
| インストール先(Raspbian内の) | QT_TARGET_INSTALL_PATH | /opt/qt/Qt5.12.0 |

それぞれ、設定方法は下記の通り。設定は好みによります(実際のところ私も下記PATHは使っていません)。

```shell:環境変数の設定
$ export WORK_PATH=/home/user/work

$ export RPI_ROOTFS=${WORK_PATH}/raspbian
$ export CROSS_TOOLS=${WORK_PATH}/tools
$ export QT_SOURCE=${WORK_PATH}/qt5.12.0/src
$ export QT_TARGET_INSTALL_PATH=/opt/qt/Qt5.12.0
```

# 必要なファイル群の準備

## RPi 用クロスコンパイラの準備

汎用的なARM向けのコンパイラも使えるとは思いますが、RPi向けとしてコンパイラも提供されているのでそちらを使う。

```shell:クロスコンパイラの取得
$ cd ${WORK_PATH}
$ git clone https://github.com/raspberrypi/tools.git
$ ls tools/
arm-bcm2708  build-qt.sh  mkimage  sysidk     usbboot
armstubs     configs      pkg      test_code
```

実際に利用するのは下記のファイル群(x86/x64は環境にあわせて)。

```shell:1行目=x86,2行目=x86-64
tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-*
tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-*
```

## 対象のRPiイメージファイルを取得

下記で、現時点で最新のイメージファイルを取得。

```shell:Raspbianのイメージファイルを取得
$ cd ${WORK_PATH}
$ wget https://downloads.raspberrypi.org/raspbian_lite_latest
$ ls
tools wheezy-raspbian-latest.zip
```

## イメージファイル内へアクセスするためにマウント

何はともあれ、まずは解凍。

```shell:イメージファイルの解凍
$ cd ${WORK_PATH}
$ mkdir ${RPI_ROOTFS}
$ unzip wheezy-raspbian-latest.zip
$ ls
tools wheezy-raspbian-latest.zip 2018-11-13-raspbian-stretch.img
```

Raspbian は FAT32 の boot パーティションと ext4 の rootfs パーティションに分かれている。

```shell:イメージファイル内のパーティション情報を確認
$ fdisk -l 2018-11-13-raspbian-stretch.img
Disk 2018-11-13-raspbian-stretch.img: 3.2 GiB, 3405774848 bytes, 6651904 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x025ce4e3

デバイス                         起動 Start 最後から セクタ  Size Id タイプ
2018-11-13-raspbian-stretch.img1       8192    98045   89854 43.9M  c W95 FA
2018-11-13-raspbian-stretch.img2      98304  6651903 6553600  3.1G 83 Linux
```

それぞれのパーティションの開始位置を算出してマウント。

```shell:セクタサイズとセクタ番号から各パーティションのoffset位置を算出してマウント
$ sudo mount -o loop,offset=$((512*98304)) 2018-11-13-raspbian-stretch.img ${RPI_ROOTFS}
$ sudo mount -o loop,offset=$((512*8192)) 2018-11-13-raspbian-stretch.img ${RPI_ROOTFS}/boot
```

```shell:マウントされていることを確認
$ ls ${RPI_ROOTFS}
bin   dev  home  lost+found  mnt  proc  run   srv  tmp  var
boot  etc  lib   media       opt  root  sbin  sys  usr
```

## Qemu の準備

Raspbian は当然 ARM 向けのバイナリで、作業環境が x86 系の場合、ファイルにアクセスできても直接実行できない。
そこで、ホスト側に CPU エミュレータである Qemu をインストールして x86 上でも実行できるように準備する。

```shell:qemu-user-staticのインストール
$ sudo apt-get -y install qemu-user-static
$ sudo cp /usr/bin/qemu-arm-static ${RPI_ROOTFS}/usr/bin
```

## Raspbian 内からネットワークにアクセスするための準備

上記 Qemu の準備で、${RPI_ROOTFS} へ chroot すれば作業できるようにはなっている。
ただ、そのままでは Raspbian 内からネットワーク等へのアクセスはできないため、ホストの環境を共有させる。

```shell:ホスト環境の共有
$ sudo mount --bind /dev ${RPI_ROOTFS}/dev
$ sudo mount --bind /sys ${RPI_ROOTFS}/sys
$ sudo mount --bind /proc ${RPI_ROOTFS}/proc
```

## Raspbian 内の環境準備
ここまでで、Raspbian 内で作業するための準備が整ったので、引き続き、Raspbian 内の環境を構築していく。

```shell:Raspbian内でlibglu1-mesa-devをインストール
$ sudo chroot ${RPI_ROOTFS}
# apt-get -y update
# apt-get -y upgrade
# apt-get -y install libglu1-mesa-dev gperf bison flex
```

Qt の Configure 時、OpenGL 系のライブラリが一部アクセスできなかったため、シンボリックリンクを張って補う。
Raspbian 内での作業はこれで終わりなので、exit で chroot から抜けておく。

```shell:汎用的な名称でリンクを作成しておき、アクセスできるようにする
# cd /opt/vc/lib
# ln -s libbrcmEGL.so libEGL.so
# ln -s libbrcmGLESv2.so libGLESv2.so
# ln -s libbrcmOpenVG.so libOpenVG.so
# ln -s libbrcmWFC.so libWFC.so
# exit
```

共有したホストの環境(とboot)のマウントを解除しておく。

```shell:bindやbootパーティションのマウントを解除(手抜き)
$ sudo umount ${RPI_ROOTFS}/*
```

さらに、Raspbian を外部(今作業しているPC)からアクセスして使うために、一部の絶対パスで張られているシンボリックリンクを相対パスに置き換えておく。

```shell:絶対パスから相対パスへの書き換え
$ cd ${RPI_ROOTFS}/usr/lib/arm-linux-gnueabihf
$ find . -maxdepth 1 -type l | while read i; do qualifies=$(file $i | sed -e "s/.*link to \(.*\)/\1/g" | grep ^/lib); if [ -n "$qualifies" ]; then echo $qualifies; newPath=$(file $i | sed -e "s/.*link to \(.*\)/\1/g" | sed -e "s,\`,,g" | sed -e "s,',,g" | sed -e "s,^/lib,../../../lib,g"); sudo rm $i; sudo ln -s $newPath $i; fi done
```

以上で、ターゲットとなる Raspbian の準備は完了。

## Qt の最新のソースコードを取得
```shell:code.qt.ioからソースをclone
$ git clone git://code.qt.io/qt/qt5.git ${QT_SOURCE}
$ cd ${QT_SOURCE}
$ git branch
* 5.12
```

なお、ビルドに使用したリビジョンは下記。

```shell:リビジョンチェック
$ git log -n 1
commit f95cd8d3f148ce6c5892a73b343f4889ca04762c
Author: Qt Submodule Update Bot <qt_submodule_update_bot@qt-project.org>
Date:   Wed Dec 26 22:30:43 2018 +0100

    Update submodules on '5.12' in qt5
    
    Change-Id: I4b4259963187eeeb8a4914c5581f3b4c69d70aa5
    Reviewed-by: Qt Submodule Update Bot <qt_submodule_update_bot@qt-project.org>
```

## リポジトリの初期設定

clone 後の環境には、初期設定を行うためのスクリプトが用意されている。
これを使って、適宜必要な追加ファイルを取得しておく。

```shell
$ cd ${QT_SOURCE}
$ ./init-repository
```

## configure の実行

clone した Qt5.12.0 のソースコードを、必要に応じて設定を変えて configure 実行。下記はexampleをコンパイルせず、ARMv6も含めたコンパイル指定。
-prefix によるインストール先の指定は Raspbian から見た絶対パスで、ホスト基準だと \${RPI_ROOTFS}/\${QT_TARGET_INSTALL_PATH} 以下に配置される。
(未指定だと \${RPI_ROOTFS}/usr/local/Qt-5.12.0 以下)

```shell:各種設定例(サンプル以外フルビルド)
./configure -opensource -confirm-license -device linux-rasp-pi-g++ -device-option \
CROSS_COMPILE=${CROSS_TOOLS}/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf- \
-sysroot /opt/raspbian -make libs -no-compile-examples -prefix ${QT_TARGET_INSTALL_PATH}
```

## ビルドの実施

ビルドの実施。make の後の -j は、物理コア数(Hyper Thread による増分はカウントしない) +1 がベター。
その後、ビルドが正常に完了したことを確認できれば、上記 -prefix で指定したパスへインストール実施。

```shell:make
$ cd ${QT_SOURCE}
$ make -j3
$ make install
```

# 謝辞
下記が大変参考になりました。違いは、
・Qemu の 完全仮想化を用いたエミュレーションではなく、chroot での作業方法に置き換え
・tar.xz で固められているソースからではビルドが通らず、git から取得して実施
[Qt5.11.2のRaspberry Pi 3 クロスコンパイル環境（まだ実験中）] https://qiita.com/muratamuu/items/66199590b54da5b2c59b