SavvyCANをbuildするためにQt 5.15.2をbuild

# 概要
とある事情でCANから流れてくる情報をわかりやすく把握したかったため，SavvyCANをUbuntu20.04でbuildしようとしたものの，色々詰まった際のメモ．

https://www.savvycan.com/

![SavvyCAN V204](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438132/ebccb11e-af16-c301-0801-479e78710d25.jpeg)


## 諸情報
### 環境

- Ubuntu 20.04.2 LTS (amd64)

### 最終的にbuildしたもの

- Qt 5 : Qt 5.15.2
- SavvyCAN : V204 (Continuous Build) - 5 May 2021


## 経緯
PEAK-SystemのPCAN-USB

https://www.peak-system.com/PCAN-USB.199.0.html

経由でCAN通信をしたかったのだが，対象車の仕様がIDすら想定外だった．
諸々調べようと思い，`PCAN-View for Linux`を使おうとするも，これを動かすには`PCAN Driver for Linux`が必要であり，[SocketCANと併存できない](#pcan-usbにおけるsocketcanとpcan-driver)ことを思い出した．

そこで調べてみるとSavvyCANが良さそうだったので，buildを試みる．
が，普通に

```console
$ qmake CONFIG+=debug
$ make
```

すると

```console
dbc/dbchandler.cpp:1915:17: error: ‘class QList<DBCFile>’ has no member named ‘swapItemsAt’
 1915 |     loadedFiles.swapItemsAt(pos1, pos2);
```

というエラーに遭遇．
調べると，

https://github.com/collin80/SavvyCAN/issues/267

にあるようにQtが古い模様．（質問者はswapに変更して解決したとのこと）
[qtbase5-dev](https://packages.ubuntu.com/ja/focal/qtbase5-dev) ([qt5-qmake](https://packages.ubuntu.com/ja/focal/qt5-qmake))と思われる元々Ubuntu 20.04に入っているものは記事執筆時点で5.12.8だった．
一応コマンドでも確認．

```console
$ qmake -v
QMake version 3.1
Using Qt version 5.12.8 in /usr/lib/x86_64-linux-gnu
```

さらに調べると，↓の通り`This function was introduced in Qt 5.13.`らしい．

https://qthub.com/static/doc/qt5/qtcore/qlist.html#swapItemsAt

また，よく読むと[公式](https://github.com/collin80/SavvyCAN/)にちゃんと
`This project requires 5.14.0 or higher because of a dependency on QtSerialBus and other new additions to Qt.`
と書いてある．


というわけで，より新しいQt5を準備することに．

# Qt 5.15.2

SavvyCANをbuildするためのツールをbuildしていく．

## 参考情報群

[公式ドキュメント](https://doc.qt.io/qt-5/linux-building.html)や[公式Wiki](https://wiki.qt.io/Building_Qt_5_from_Git)，[Linux From Scratch](https://www.linuxfromscratch.org/blfs/view/svn/x/qt5.html)の情報が参考になる．

https://doc.qt.io/qt-5/linux-building.html

https://wiki.qt.io/Building_Qt_5_from_Git

https://www.linuxfromscratch.org/blfs/view/svn/x/qt5.html


## 下準備

とりあえず，↓からqt-everywhere-src-5.15.2.tar.xzを落とし，展開しておく．

https://download.qt.io/archive/qt/5.15/5.15.2/single/

### システム要件(Qt)

まず，Requirementsを満たしていく．
対象環境が[ROS Noetic](http://wiki.ros.org/noetic/Installation/Ubuntu)を入れてあるような環境だったので，build-essentialなどは既に入っていた．
が，xcb周りが不足していたので，[公式Wiki](https://wiki.qt.io/Building_Qt_5_from_Git#Linux.2FX11)にある通り

```console
$ sudo apt install '^libxcb.*-dev' libx11-xcb-dev libglu1-mesa-dev libxrender-dev libxi-dev libxkbcommon-dev libxkbcommon-x11-dev
```

として一式揃える．
（ちなみに[大ハマリ](#ハマった原因)した原因はココだった…）

### パッチ

[Linux From Scratch](https://www.linuxfromscratch.org/blfs/view/svn/x/qt5.html)の`Additional Downloads`に`Required patch`とやらがある．
`First apply a patch to fix an Out Of Bounds read in QtSVG`とのことなので，とりあえず適用しておく．

```console
$ cd xxx/qt-everywhere-src-5.15.2/
$ patch -Np1 -i ../qt-everywhere-src-5.15.2-CVE-2021-3481-1.patch
（↑xxx下にpatchファイルがある想定）
```

（適用が必須か否かは未確認）

さらに，

```sh
Project ERROR: Library 'assimp' is not defined.
```

と出てしまうので，

https://bugreports.qt.io/browse/QTBUG-84037

を参考に`qtquick3d-assimp.patch`を当てる．ただ，↑にあるURLは404になってしまうため，

https://github.com/qutebrowser/qt-debug-pkgbuild/blob/master/qt5-quick3d/qtquick3d-assimp.patch

を使う．

```console
$ cd xxx/qt-everywhere-src-5.15.2/qtquick3d
$ patch -Np1 -i ../../qt-debug-pkgbuild-master/qt5-quick3d/qtquick3d-assimp.patch
（↑xxx下にpatchファイルがある想定）
```

## ビルド＆インストール

[Linux From Scratch](https://www.linuxfromscratch.org/blfs/view/svn/x/qt5.html)のInstall Qt5 by running the following commandsを参考にbuildしていく．
なお，以下は`/opt/qt-5.15.2`にインストールする想定のコマンド．

```console
$ cd xxx/qt-everywhere-src-5.15.2
$ export QT5PREFIX=/opt/qt-5.15.2
$ ./configure -prefix $QT5PREFIX                        \
              -sysconfdir /etc/xdg                      \
              -confirm-license                          \
              -opensource                               \
              -dbus-linked                              \
              -openssl-linked                           \
              -system-harfbuzz                          \
              -system-sqlite                            \
              -nomake examples                          \
              -no-rpath                                 \
              -skip qtwebengine                         \
              -xcb-xlib                                 \
              -xcb
```

とし，

```terminal:good_result
Features used by QPA backends:
︙
  X11 specific:
    XLib ................................. yes
    XCB Xlib ............................. yes
    EGL on X11 ........................... yes
    xkbcommon-x11 ........................ yes
```

XCB Xlibとかxkbcommon-x11とかがyesになっていることを確認．
あとは普通に

```console
$ make
$ sudo make install
```

とすれば`/opt/qt-5.15.2`に入る．

なお，[参考記事](https://www.linuxfromscratch.org/blfs/view/svn/x/qt5.html)のTipsにバージョン有無間のシンボリックリンクに関する記述がある．
何故か`-prefix`で`/opt/qt5`を指定してインストールし，後から云々になっているが，自分は先の通り`/opt/qt-5.15.2`へ直接インストールした上で

```console
$ sudo ln -sfnv /opt/qt-5.15.2 /opt/qt5
```

とした．

## その他

[参考記事](https://www.linuxfromscratch.org/blfs/view/svn/x/qt5.html)の`Next fix some issues using gcc-11`にある`sed`連発はやらなくてもいけた…と思う．

パスは，qmake自体はダイレクトに叩けば良いので`/opt/qt5/bin`なんかは通さず，lib周りだけ

```shell:.bashrc
LD_LIBRARY_PATH=/opt/qt5/lib:$LD_LIBRARY_PATH
export LD_LIBRARY_PATH
export QT_PLUGIN_PATH=/opt/qt5/lib/plugins/
export QT_DEBUG_PLUGINS=1
```

とした．
（`QT_DEBUG_PLUGINS`を`1`にしているのは色々迷走した際の名残）


# SavvyCAN V204

用意した新しいQt5を使って本来の目的であるSavvyCANをbuildする．

## 参考情報群

日本語だと以下の情報くらいしか出てこなかったが，いずれも18.04向け，かつQt 5.12でいけた頃もしくはJetson向けなので本環境とは完全には合致せず．
とは言え[公式のREADME.md](https://github.com/collin80/SavvyCAN)で十分．
（最初は[経緯](#経緯)の通り`This project requires 5.14.0 or higher`を見てませんでしたが…）

https://www.shutingrz.com/post/can-training2/

https://tech.aptpod.co.jp/entry/2021/06/18/100000

なお，後者はデフォルトのQtのバージョンに合わせて`V199.1`を使うことにしているので，古いものを使ったり

https://github.com/collin80/SavvyCAN/issues/255

などを参考に書き換えて対応するのもありかも知れない．

## 下準備

とりあえず，↓からgit cloneするか，zipで落として展開しておく．

https://github.com/collin80/SavvyCAN

### システム要件(SavvyCAN)

[Dependencies](https://github.com/collin80/SavvyCAN#dependencies)にある`This project requires 5.14.0 or higher because of a dependency on QtSerialBus and other new additions to Qt.`に関しては5.15.2を用意したのでOK．

[What to do if qmake fails with error Project ERROR: Unknown module(s) in QT: qml serialbus help on Ubuntu?](https://github.com/collin80/SavvyCAN#what-to-do-if-qmake-fails-with-error-project-error-unknown-modules-in-qt-qml-serialbus-help-on-ubuntu-)にある通り

```console
$ sudo apt install libqt5serialbus5-dev libqt5serialport5-dev qttools5-dev
```

を入れておく．
（参考情報前者曰く18.04だと自前buildを要する模様．Qt 5.12でbuildしていて`QtSerialBusが5.14.0 or higherに依存してる`って話と矛盾するけど，おそらく5.12時代の話なのでしょう．）

なお，[後述](#pcan-view)の通りうまく動かない部分もあったので，必要なら5.15用にbuildするべきかも知れない．



## ビルド＆実行

↓でbuildし，

```console
$ cd xxx/SavvyCAN
$ /opt/qt5/bin/qmake CONFIG+=debug
$ make
（↑defaultの5.12.8ではなくbuildした新しいqmakeを呼ぶ）
```

↓普通に実行

```console
$ cd xxx/SavvyCAN
$ ./SavvyCAN
```

これで↓のようにちゃんとSocketCAN経由で動作した．

![SavvyCAN V204](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438132/ebccb11e-af16-c301-0801-479e78710d25.jpeg)


# PCAN-USBにおけるSocketCANとPCAN Driver

PEAK-Systemのアダプタを使ってSocketCANでSavvyCANを使う分にはココ以降の作業は不要．
ただ，PCAN Driverに関して以前別車両で使った頃のことを忘れていたので備忘録．
細かな説明は↓にある通り．

https://www.peak-system.com/fileadmin/media/linux/index.htm

## SocketCAN

[公式](https://www.peak-system.com/fileadmin/media/linux/index.htm)に`Many Linux distributions, or rather the used Linux Kernels, already contain the drivers for PEAK-System's CAN interfaces.`とある通り，Ubuntuには元々PEAK-System製CAN Interfacesのドライバが含まれているので，PCAN-USBは挿すだけで認識してくれる．
（多分16.04 LTS以降のKernel？）
なので，あとは以下のように起動してあげればSocketCANで通信できる．

```console
$ sudo ip link set can0 type can bitrate 500000
$ sudo ip link set can0 up
```

（`ifconfig -a`などで確認して`can0`として認識されていた場合）

なお，[Kvaser](https://www.kvaser.com/products-services/our-products/#?descriptors=product_groups&product_groups=usbcan)はドライバ入れないと駄目だったような気がする．
ちなみに[Vector](https://www.vector.com/jp/ja/products/products-a-z/hardware/network-interfaces/)はWindows専用．


## PCAN Driver

先の通りSocketCANで事足りる場合は何も入れなくても良いが，[公式](https://www.peak-system.com/fileadmin/media/linux/index.htm)に`in connection with the PCAN-Basic API, you need our PCAN Driver for Linux package and compile the driver yourself`とある通り，PCAN-ViewのようにPCAN-Basic APIを使用するソフトを使いたい場合は別途PCAN Driverをインストールする必要がある．


### 準備

[公式](https://www.peak-system.com/fileadmin/media/linux/index.htm)の`Download PCAN Driver Package`からドライバをダウンロードし，展開する．
なお，ドライバ本体の隣のリンクの`Documentation`に仕様などが書かれたPCAN DriverのUser Manualがある．
その中に`System Requirements`が書かれており，自身の環境では`libpopt-dev`が不足していたので

```console
$ sudo apt install libpopt-dev
```

を叩いた．

### ビルド＆インストール(chardev)

User Manual内の`3.1 Build Binaries`や`3.2 Install Package`にある通りで，

```console
$ cd xxx/peak-linux-driver-8.12.0/
$ make clean
$ make
```

とし，

```console
$ sudo make install
$ sudo modprobe pcan
```

でOK．
これで入るのはchardev版ドライバであり，一応，netdev版が必要な場合は次の通り．

### ビルド＆インストール(netdev)

[chardev版](#ビルドインストールchardev)のmakeの部分でにnetdev用のオプションを付け，

```console
$ make –C driver NET=NETDEV_SUPPORT
```

としてインストールすればOK．
（コッチの場合，普通は先の通り元々あるドライバで事足りるのだが，NVIDIA DRIVE AGXで使おうとした際に含まれておらずこうやってbuildとinstallをした…気がする．）



## PCAN-View

[公式](https://www.peak-system.com/fileadmin/media/linux/index.htm)の`How to install PCAN-View via repository`にある通り，

```console
$ wget -q http://www.peak-system.com/debian/dists/`lsb_release -cs`/peak-system.list -O- | sudo tee /etc/apt/sources.list.d/peak-system.list
$ wget -q http://www.peak-system.com/debian/peak-system-public-key.asc -O- | sudo apt-key add -
$ sudo apt update
$ sudo apt install pcanview-ncurses
```

とすれば入り，

```console
$ pcanview
```

で起動できる．
[chardev版ドライバ](#ビルドインストールchardev)が正常にインストールされていれば
![PCAN-View v0.9.0](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438132/f27a6be2-e844-5645-d9da-95863f1e0a18.jpeg)
のように表示され，Rxを確認したりTxしてみたりが可能．

冒頭で述べた自身の「CANから流れてくる情報をわかりやすく把握」に関してはコレで十分だったのだが，[chardev版](#ビルドインストールchardev)を入れると[netdev版](#ビルドインストールnetdev)もkernel内のドライバも使えなくなり，SocketCAN経由の通信ができなくなる．
逆にSocketCANを生かそうとすると
![PCAN-View UNKNOWN](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438132/9d45735c-5954-da51-a9e1-1a5511f71d4a.jpeg)
のようにPCAN-Viewが使えなくなる．
（これは[netdev版](#ビルドインストールnetdev)が入った状態なのでPCAN-USB自体は認識していてConnectedとなっているが，UNKNOWNと表示されて通信不可．なお，kernel内のドライバのみの場合はまずデバイス自体を認識できない．）

最終的にはROS上で[socketcan_interface](http://wiki.ros.org/socketcan_interface)経由の通信をするノードを作りたい状況なので，いちいちドライバを切り替える事になってしまう．
そのため，「SocketCANでキレイに可視化できそうなSavvyCANを使ってみよう」となった．

なお，SavvyCAN（というかQt Serial Bus）はchardev版PCAN Driverにも対応しているのだが，
![SavvyCAN PCAN Driver](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438132/4ad59c03-c0dc-e533-fca4-e6bfbc82d072.jpeg)
設定がおかしいのかどうしても250000になってしまいうまく通信できなかった．
ただし，[前述](#システム要件savvycan)の通りaptでQtSerialBusを入れるなどしたため

https://packages.ubuntu.com/focal/libqt5serialbus5-dev

`libqt5serialbus5 (= 5.12.8-0ubuntu1)`が入っている環境につき，5.15用に自前buildすればうまく動くのかも知れない．
（PCAN-Viewは使えたし，以前PCAN-Basic APIを使うWindows用プログラムを作ったこともあるので，PCAN Driver自体は悪くないはず．）


# ハマった原因

まず，元々色々入れてきていた環境だったので，xcb系が不足していると思わず，[Linux From Scratch](https://www.linuxfromscratch.org/blfs/view/svn/x/qt5.html)の`Install Qt5 by running the following commands`に書いてある

```console
$ ./configure -prefix $QT5PREFIX                        \
              -sysconfdir /etc/xdg                      \
              -confirm-license                          \
              -opensource                               \
              -dbus-linked                              \
              -openssl-linked                           \
              -system-harfbuzz                          \
              -system-sqlite                            \
              -nomake examples                          \
              -no-rpath                                 \
              -skip qtwebengine                         &&
  make
```

をそのまま叩いてしまった．
単にconfigureだけ叩くと<details><summary>色々選択しないといけない</summary><div>

```terminal
Selecting Qt Edition.

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

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
```
</div></details>ので確かに楽なのだが，このままだと一気にmakeまでやりきってしまうため，xcb系非対応のままSavvyCANのbuildへ進んでしまった．
しかもSavvyCANのbuild自体はできてしまい，実行時に

```terminal
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found.
```

となって理由を探す羽目になった．
パスが通っていないのか？などと延々迷走した後，libxcb等が不足していたことに気付き，個別にインストールした．
それでも無理だったため，`configure`時に`-xcb-xlib`や`-xcb`
を付けてみたところ，

```terminal
ERROR: Feature 'xcb' was enabled, but the pre-condition 'features.thread && libs.xcb && features.xkbcommon-x11' failed.
ERROR: Feature 'xcb-xlib' was enabled, but the pre-condition 'features.xlib && libs.xcb_xlib' failed.
```

となり，

```terminal:bad_result
Features used by QPA backends:
︙
  X11 specific:
    XLib ................................. yes
    XCB Xlib ............................. no
    EGL on X11 ........................... yes
    xkbcommon-x11 ........................ no
```

のままだった．

先の[一気に網羅](#システム要件qt)なコマンドを叩いても（そもそもその時点では全てinstalled），何度configureしてもこの状況から抜け出せず…

結局，一度

```sh
$ make clean
```
してあげないと最初に

```console
Checking for XCB >= 1.11... yes
Checking for XCB ICCCM >= 0.3.9... yes
Checking for XCB Util >= 0.3.9... yes
Checking for XCB SHM... yes
Checking for XCB Image >= 0.3.9... yes
Checking for XCB Keysyms >= 0.3.9... yes
Checking for XCB RandR... yes
Checking for XCB XRender... yes
Checking for XCB Renderutil >= 0.3.9... yes
Checking for XCB Shape... yes
Checking for XCB Sync... yes
Checking for XCB Xfixes... yes
Checking for XCB Xinerama... yes
Checking for XCB XKB... yes
Checking for XCB (extensions)... yes
Checking for xkbcommon >= 0.5.0... yes
Checking for xkbcommon-x11... yes
```

と判定される部分は更新されず，何度configure叩こうがライブラリの有無フラグは残ったままだったのが原因だった．

- libがすでに揃っている，無くともqmakeかmake段階でエラーが出るだろうと思い込んでいた
- 最初にmakeまで一気に叩くコマンドをコピペしてしまい，膨大なログでこの判定部分はすぐに流れてしまってこのログの存在も知らず，毎回libの判定をしていると思い込んでいた（二度目からのconfigureではChecking forが出てこない）
- そこそこ重いのでcleanを避けていた

というコンボで時間を熔かしてしまいました(T_T)