Qtクロスコンパイル開発環境の構築（Jetson TX1向け）

# ホスト環境
Linux (Ubuntu 16.04 LTS) ※Jetpack導入済

追記: Ubuntu 20.04でも動作確認済

# デバイス(Jetson)側の準備

依存パッケージのインストールをしておく。

```bash
sudo apt-get install '.*libxcb.*' libxrender-dev libxi-dev libfontconfig1-dev libudev-dev

# EGLFSが有効にならない場合
sudo apt install libgles2-mesa-dev -y

# Gstreamerを有効にする場合
sudo apt install gstreamer1.0-tools gstreamer1.0-plugins-* libgstreamer-plugins-base1.0-dev
```

Qt5.12でQtWebEngineを使う場合は以下のパッケージもインストールしておく。

```bash
sudo apt-get install gperf bison flex
```

# ホスト(Ubuntu)側の準備

ホストPCのLinux_for_Tegraのrootfs/usrディレクトリに移動する。
rsyncを使いJetsonからincやlibをコピーする。（IPアドレスはJetsonのIPアドレスを指定する）

```bash
cd ~/64_TX1/Linux_for_Tegra/rootfs/usr
sudo rsync -e ssh -avz nvidia@192.168.11.4:/usr/include .
sudo rsync -e ssh -avz nvidia@192.168.11.4:/usr/lib .
```

以下のスクリプトを利用し、ホスト側にコピーしたシンボリックリンクをホスト向けに修正する。
https://github.com/alpqr/fixsymlinks_tx1

```bash
chmod +x fixsymlinks.sh
sudo ./fixsymlinks.sh ~/64_TX1/Linux_for_Tegra/rootfs
```

# Qtソースの入手

Qt（オープンソース版）をダウンロードして展開する。
インストールするバージョンはLTSの5.9.6にした（現時点で最新LTS）。
https://download.qt.io/official_releases/qt/5.9/5.9.6/single/qt-everywhere-opensource-src-5.9.6.zip.mirrorlist

※5.12.10でも動作確認済

```bash
xz -dc qt-everywhere-opensource-src-5.9.6.tar.xz | tar xfv -
mv qt-everywhere-opensource-src-5.9.6 ~/
```

# ツールチェーンのダウンロード

以下からlinaroをダウンロードする。現在最新版は7.3.1。展開して移動する。
https://releases.linaro.org/components/toolchain/binaries/latest/aarch64-linux-gnu/

```bash
xz -dc gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu.tar.xz | tar xfv -
mv gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu ~/64_TX1/
```
# Qtをビルド

qt-everywhere-opensource-src-5.9.6フォルダ配下で、以下を実行する。
※ QMAKE_CFLAGS_ISYSTEM=は、GCCの仕様変更に対応するために追加した。詳細は[こちら](https://bugreports.qt.io/browse/QTBUG-53367?focusedCommentId=370122&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-370122)のバグレポートを参照。

```bash
cd ~/qt-everywhere-opensource-src-5.9.6
./configure -device linux-jetson-tx1-g++ -device-option CROSS_COMPILE=$HOME/64_TX1/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- -sysroot $HOME/64_TX1/Linux_for_Tegra/rootfs -nomake examples -nomake tests -prefix /usr/local/qt5 -extprefix $HOME/64_TX1/qt5 -hostprefix $HOME/64_TX1/qt5-host -opengl es2 QMAKE_CFLAGS_ISYSTEM=
```

追記: 以下の方法でコンパイルオプションを変更することでもビルド可能（この場合はQMAKE_CFLAGS_ISYSTEM指定は不要）
https://forums.developer.nvidia.com/t/xavier-qt-cross-compile/154215/3?u=otomon

```
# コンパイルオプションを変更
edit $HOME/qt-everywhere-src-5.12.10/qtbase/mkspecs/common/gcc-base.conf
Change QMAKE_CFLAGS_ISYSTEM = -isystem to QMAKE_CFLAGS_ISYSTEM = -I

Also, insert the following lines in the qmake.conf of the device:
QMAKE_CXXFLAGS += -std=gnu++11
QMAKE_CFLAGS_ISYSTEM=-I
(qtbase/mkspecs/devices/linux-jetson-tx1-g++/qmake.conf)

# configure
./configure -opensource -confirm-license -device linux-jetson-tx1-g++ -device-option CROSS_COMPILE=$HOME/64_TX1/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- -sysroot $HOME/64_TX1/Linux_for_Tegra/rootfs -nomake examples -nomake tests -prefix /usr/local/qt5 -extprefix $HOME/64_TX1/qt5 -hostprefix $HOME/64_TX1/qt5-host -opengl es2
```

商用版かオープンソース版かを聞かれるので、オープンソース版を選択する。oを入力する。

```bash
Type 'c' if you want to use the Commercial Edition.
Type 'o' if you want to use the Open Source Edition.

Which edition of Qt do you want to use? o
```

yを押してライセンスに受領する。

```bash
This is the Qt Open Source Edition.
 
You are licensed to use this software under the terms of
the GNU Lesser General Public License (LGPL) version 3
or the GNU General Public License (GPL) version 2.
 
Type 'L' to view the GNU Lesser General Public License version 3 (LGPLv3).
Type 'G' to view the GNU General Public License version 2 (GPLv2).
Type 'y' to accept this license offer.
Type 'n' to decline this license offer.
 
Do you accept the terms of either license? y
```

QPA backendsのEGLFSとEGL on X11に依存するので、これらがyesになっていることを確認する。

```bash
Qt Gui:
  Accessibility .......................... yes
  FreeType ............................... yes
    Using system FreeType ................ yes
  HarfBuzz ............................... yes
    Using system HarfBuzz ................ no
  Fontconfig ............................. yes
  Image formats:
    GIF .................................. yes
    ICO .................................. yes
    JPEG ................................. yes
      Using system libjpeg ............... no
    PNG .................................. yes
      Using system libpng ................ yes
  EGL .................................... yes
  OpenVG ................................. no
  OpenGL:
    Desktop OpenGL ....................... no
    OpenGL ES 2.0 ........................ yes
    OpenGL ES 3.0 ........................ yes
    OpenGL ES 3.1 ........................ yes
  Session Management ..................... yes
Features used by QPA backends:
  evdev .................................. yes
  libinput ............................... no
  INTEGRITY HID .......................... no
  mtdev .................................. no
  tslib .................................. no
  xkbcommon-evdev ........................ no
QPA backends:
  DirectFB ............................... no
  EGLFS .................................. yes
  EGLFS details:
    EGLFS OpenWFD ........................ no
    EGLFS i.Mx6 .......................... no
    EGLFS i.Mx6 Wayland .................. no
    EGLFS RCAR ........................... no
    EGLFS EGLDevice ...................... yes
    EGLFS GBM ............................ no
    EGLFS Mali ........................... no
    EGLFS Raspberry Pi ................... no
    EGL on X11 ........................... yes
  LinuxFB ................................ yes
  VNC .................................... yes
  Mir client ............................. no
  X11:
    Using system-provided XCB libraries .. yes
    EGL on X11 ........................... yes
    Xinput2 .............................. yes
    XCB XKB .............................. yes
    XLib ................................. yes
    XCB render ........................... yes
    XCB GLX .............................. yes
    XCB Xlib ............................. yes
    Using system-provided xkbcommon ...... no
Qt Widgets:
  GTK+ ................................... no
  Styles ................................. Fusion Windows
```

ビルドして、インストールする。（一時間程度かかる）

```bash
make -j8
make install
```

installすると、
`$HOME/64_TX1/qt5`配下に、デバイス側(Jetson)と同期させるディレクトリが作られる。
`$HOME/64_TX1/qt5-host`配下に、ホスト向けのツールのディレクトリが作られる。

デバイス側(Jetson)で、同期させる`/usr/local/qt5`ディレクトリを作成する。

```bash
sudo mkdir /usr/local/qt5
sudo chown nvidia:nvidia /usr/local/qt5
```

ホスト側で以下のコマンドを入力し、qt5ディレクトリを同期する。

```bash
cd ~/64_TX1
rsync -e ssh -avz qt5 nvidia@192.168.11.4:/usr/local
```

（参考）
上記ではすべてのQtモジュールを追加しているが、一部のみ追加する場合は追加したいモジュールのディレクトリでqmake、make、make installし、qt5フォルダをrsyncすれば良い。
QtMultimediaを追加する場合は以下の通り。

```bash
cd ~/qt-everywhere-opensource-src-5.9.6/qtmultimedia
~/64_TX1/qt5-host/bin/qmake
make -j8
make install

cd ~/64_TX1
rsync -e ssh -avz qt5 nvidia@192.168.11.4:/usr/local
```

# Qtアプリケーションのビルド

Qtのサンプルアプリケーションをビルドする。qmakeでMakefileを作成してmakeする。

```bash
cd ~/qt-everywhere-opensource-src-5.9.6/qtbase/examples/opengl/qopenglwidget
~/64_TX1/qt5-host/bin/qmake
make
```

scpを利用してJetsonに実行ファイルをコピーする。

```bash
scp qopenglwidget nvidia@192.168.11.4:/home/nvidia
```

# Qtアプリケーションの実行

マウスやキーボードは/dev/inputを通して利用するが、権限がないのでそのままでは使えない。
一時的に権限を追加する場合は以下のコマンドを打つ。

```bash
sudo chmod a+rwx /dev/input/event*
```

恒久的な対処を行う場合は、udevルールを追加する。

```bash
sudo vi /etc/udev/rules.d/99-input.rules

KERNEL=="event*", NAME="input/%k", MODE="666"
を書いて保存する
```

ライブラリのパスを設定し、実行する。

```bash
export LD_LIBRARY_PATH=/usr/local/qt5/lib
cd ~
./qopenglwidget
```

![Screenshot from 2018-08-17 10-55-00.png](https://qiita-image-store.s3.amazonaws.com/0/266169/4c0f3d8a-c129-fd92-cacd-a4486080f2f2.png)

マウスカーソルがQtとX11とで2つ表示されてしまう。
X11側のマウスを非表示にする場合は、以下の通り対処する。（注意：恒久的に非表示にされる）

```bash
sudo vi /usr/share/lightdm/lightdm.conf.d/50-xserver-command.conf

xserver-command=X -core
を
xserver-command=X -core -nocursor
に変更する。
```

# Qt Creatorの設定

コマンドラインで毎回操作するのは面倒なので、Qt Creatorを使ってクロスビルド、リモートデバッグができるようにする。
以下よりQt Creatorをダウンロードする。現在最新版は4.7.0。
https://download.qt.io/official_releases/qtcreator/4.7/4.7.0/qt-creator-opensource-linux-x86_64-4.7.0.run.mirrorlist

インストーラーを実行する。
インストールディレクトリはデフォルトの`/home/ubuntu/qtcreator-4.7.0`とした。

```bash
chmod +x qt-creator-opensource-linux-x86_64-4.7.0.run
./qt-creator-opensource-linux-x86_64-4.7.0.run
```

ホストPCでQt Creatorを起動する。
場所は`home/ubuntu/qtcreator-4.7.0/bin/qtcreator`にある。

まずは、クロスコンパイラを設定する。
ツールバーから、Tools＞Optionsを選択してオプションメニューを表示する。
KitsメニューのCompilersタブを選択する。
Addボタンを押し、GCCのC++を追加する。
Nameを適宜設定し、コンパイラパスにg++を指定する。今回の手順の場合、以下のパスになる。
`/home/ubuntu/64_TX1/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-g++`
同様に、GCCのCも追加する。
`/home/ubuntu/64_TX1/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc`
ABIが自動設定されるので、変更せずにApplyを押す。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/c99ea5cf-f6e4-a4d1-9ed3-e28118c0cb05.png)

同様にデバッガも設定する。Debuggersタブを選択する。
Addボタンを押し、gdbのパスを設定してApplyを押す。今回の手順の場合、以下のパスになる。
`/home/ubuntu/64_TX1/gcc-linaro-7.3.1-2018.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gdb`
![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/9704a61f-50a5-0bb2-3edf-b3fec49e816d.png)

Qtバージョン(qmake)を設定する。Qt Versionsタブを選択する。
Addボタンを押し、qmakeパスを設定してApplyを押す。今回の手順の場合、以下のパスになる。
`/home/ubuntu/64_TX1/qt5-host/bin/qmake`
![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/aa6851f3-1509-0606-181e-63621d9fce38.png)

キットを設定する。Kitsタブを選択する。Addボタンを押し、以下のとおりに設定する。
Name: TX1
Device type: Generic Linux Device
Sysroot: /home/ubuntu/64_TX1/Linux_for_Tegra/rootfs
Compiler: TX1-GCCおよびTX1-G++
Debugger: TX1-GDB
Qt Version:Qt 5.9.6 (qt5-host)
※デバイス設定をしていないため警告アイコンが出るが問題ない（下記手順後に消える）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/bc8aa75f-f6a1-2bcb-9117-85b5663a2cbf.png)

次に、デバイス設定を追加する。
DevicesメニューのDevicesタブを選択し、Addボタンを押す。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/c96ce0fe-cc3a-2271-8c86-ab1ffe287037.png)

Genelic Linux Deviceを選択して、Start Wizardボタンを押す。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/5492a2bd-96f4-256a-557b-bb3312adb5bb.png)

JetsonのIPアドレス、ログインID、パスワードを入力し、Nextボタンを押す。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/af817be2-fe00-a7e0-6276-6b70b59ec387.png)

正常な場合、以下のメッセージ表示になる。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/52202b04-5f9b-1c50-940b-8e9b4cd38533.png)

# Qt Creatorからリモート実行・デバッグ

ツールバーのFile＞Open File or Projectを選択し、サンプルプロジェクトを開く。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/955d2089-bf12-ce0b-d0d1-8c0aae610b82.png)

TX1キットのDebugとReleaseを選択し、Configure Projectボタンを押す。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/9d807a83-21ca-5c1c-8dca-e11a31a33fe6.png)

ここで左下の緑色矢印を押してRunする。
Application Outputにて"Could not open display"と表示され実行できない場合は、Qt CreatorのProjecs、Run、Run Environment設定で、`DISPLAY`変数を追加し、値を`:0`として設定する。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/f8367c94-0bda-3a52-3df1-863a8e7acb71.png)

再度実行する。
リモート実行できた。（RemminaでVNC接続して確認）
![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/83fe1dd1-43df-3e90-87c3-0ce8e7961820.png)

ブレークポイントを貼ってデバッグ実行、ちゃんとブレークする。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/266169/f0ebb89d-22dc-cb6b-b94c-d66f22cf46e2.png)

# 参考
http://blog.qt.io/blog/2016/11/10/qt-nvidia-jetson-tx1-device-creation-style/