Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
在 Ubuntu 16.04 為 Raspbian Jessie 交叉編譯 Qt 5.6 桌面版

在 Ubuntu 16.04 為 Raspbian Jessie 交叉編譯 Qt 5.6 桌面版

筆記

Qt 在 Raspberry Pi 上可以跑兩種版本:

  • 桌面版。你平常在 Linux 發行版裡看到的會是這個,包含 Raspbian 在內。通常基於 X11,就是個普通的 GUI 框架。
  • 嵌入版。這個版本不需要鐘面系統,通常是直接走 framebuffer 直接把東西畫到螢幕上,適合一些嵌入式設備的應用。

這個教學會編譯桌面版,因為我對這個版本比較熟。我上次試的時候 OpenGL 在 embedded 版還有些問題,不過 Qt 在那之後有很多更新,狀況應該會好很多。Qt 官方 wiki 也有個相關的教學:

https://wiki.qt.io/RaspberryPi2EGLFS

我是用虛擬機裝 Ubuntu 來編譯,如果你想做類似的事情,可能也會碰到這些問題,順便題一下。預設的虛擬機設定不太夠,我第一次編沒多久硬碟空間就用完了,double 重來結果在 linker 遇到記憶體不足直接 crash。

我最後成功的設定是 50 GB 空間與 2 GB RAM。應該是不用這麼多啦,不過編 Qt 實在很麻煩,安全至上。

編譯步驟

我主要是參考 Qt wiki 裡的教學來做,然後不需要的略過,出問題再小改。原本的文章:

https://wiki.qt.io/RaspberryPi_Beginners_Guide

前置

更新系統,然後安裝 Git,之後用來抓工具和 Qt 源碼會用到。

sudo apt update
sudo apt upgrade
sudo apt install git

我這裡把所有東西裝在 ~/rpi,當然你可以改,把環境變數換掉就好了。

export RPIROOT=$HOME/rpi
export RPIIMG=$RPIROOT/rasp-pi-rootfs
export RPIQT=$RPIROOT/qt5pi
mkdir $RPIROOT
cd $RPIROOT

我這裡只有把 PATH 加到 active shell session。如果你希望預設就讀入,就要把它寫入 ~/.bashrc 之類的。我個人是習慣寫到 .env 之類的檔案,只在需要的時候 source。

交叉編譯工具

這個可能有人早已經有了,就可以跳過。可以參考 Sosorry 的教學:

https://www.raspberrypi.com.tw/405/using-a-cross-compiler-for-raspberry-pi/

git clone https://github.com/raspberrypi/tools.git
export PATH=$PATH:$RPIROOT/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin

注意 cross compiler 有分 32- 和 64-bit。這年頭大部分人都裝 64-bit OS,你應該也是。如果你的作業系統是 32-bit,就把 PATH 路徑裡的 -x64 拿掉。

取得作業系統發行版

wget http://downloads.raspberrypi.org/raspbian_latest -O jessie-raspbian-latest.zip
unzip jessie-raspbian-latest.zip
mkdir $RPIIMG
sudo mount -t ext4 -o loop,offset=70254592 2016-05-27-raspbian-jessie.img $RPIIMG

注意:根據你的 image 版本不同,mount 的參數也要改變。其他的應該很容易理解,只有 offset 比較麻煩。如果你直接看這個 image 的 filesystem 結構:

$ fdisk -l 2016-05-27-raspbian-jessie.img
Disk 2016-05-27-raspbian-jessie.img: 3.8 GiB, 4019191808 bytes, 7849984 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: 0x14c20151

Device                          Boot  Start     End Sectors  Size Id Type
2016-05-27-raspbian-jessie.img1        8192  137215  129024   63M  c W95 FAT32 (LBA)
2016-05-27-raspbian-jessie.img2      137216 7849983 7712768  3.7G 83 Linux

會看到這個 image 包含兩個分割。第一個分割是 bootloader,後面的則是 foot filesystem。我們要 mount 的是第二個,所以必須找到它的 offset。根據上面的資訊,一個 sector 是 512 bytes,所以這個 image 的 offset 是 $512 \times 137216 = 70254592$。其他版本會不一樣,需要自己計算。

修復連結

我們會需要修復一些 relative links。比較方便的辦法是用別人提供的工具,但很可惜似乎沒有官方來源,只有一些口耳相傳的載點。

確認你有安裝好前面的 cross-compiling toolchain,並把它加入 PATH。可以用

which arm-linux-gnueabihf-gcc

檢查。

下載並執行 symlink 修復工具

wget https://raw.githubusercontent.com/riscv/riscv-poky/master/scripts/sysroot-relativelinks.py
sudo python sysroot-relativelinks.py $RPIIMG

取得 Qt 原碼

git clone https://code.qt.io/qt/qt5.git

有些教學會用 git://,不過官方現在似乎是建議用 HTTPS。如果你連不上 code.qt.io(我有時候會),他們在 GitHub 上也有 mirror:https://github.com/qt/qt5.git

cd qt5
git checkout v5.6.1

你可以在這個階段選擇想要 compile 的版本。如果沒有 checkout 會編譯 dev HEAD,如果想要尖端科技可以試試,不過通常是會爆炸,別說我沒警告你。

可以用 git tag 看看有什麼版本可以用。

BTW 上週出了 Qt 5.7 不過我還沒試。

./init-repository

這個指令會自動載入這個版本的 Qt 元件源碼。注意這會需要一段時間,而且需要穩定網路連線

如果有東西載到一半失敗,可能會讓你的 repository 處在一個很奇怪的狀態。這時候可以強迫重載:

./init-repository -f

編譯 Qt Base

cd $RPIROOT/qt5
./configure -opengl es2 -device linux-rasp-pi-g++ -device-option CROSS_COMPILE=$(which arm-linux-gnueabihf-gcc | sed 's/.\{3\}$//') -sysroot $RPIIMG -opensource -confirm-license -optimized-qmake -reduce-exports -release -no-qml-debug -make libs -make examples -prefix /usr/local/qt5pi -hostprefix $RPIQT

如果你用 Raspberry Pi 2,把 device 改成 linux-rasp-pi2-g++。我在編譯時發現 QML 的 debug class 有用到 RPi 不支援的功能,所以用 -no-qml-debug 把它關了,幸好不重要。

這個指令裡面很多路徑是要對應到你自己 host machine 的設定。我這裡是根據前面設定的 $RPIROOT 變數,你的需求可能不同。唯一例外是 -prefix 參數,這是對應到 RPi 上的路徑,當然也是可以改,不過如果你沒有經驗,建議就用這個設定。

如果你要自己改設定,記得把 -opengl es2 設定加上去,才會有合適的 OpenGL backend 可用。有些時候你可能會想額外 compile 其他東西,就自己加吧。例如如果你想要 PostgreSQL plugin,就加上 -plugin-sql-psql。下面的指令可以查看能用的選項:

./configure -help

我在這裡為了示範,所以編譯了 Qt 內建的範例程式。你之後自己編譯的時候應該不會用到,就把 -make examples 拿掉即可。

注意這裡我們選擇了開源版,並且同意了 Qt 的版權宣告。如果你想用商業版,請自己把選項換掉。

Configure 完成之後會出現一個表格,可以用來檢查你將要什麼。想修改的話,必須先清理 repository:

git submodule foreach --recursive "git clean -dfx"

再重新 configure。

接著就是正式開始 compile:

make

這個指令會跑非常非常久,如果你是在晚上做這件事情,直接去睡覺會是個好主意。想平行編譯的話可以試試 make -j4 之類的,不過我實測好像會踩到 GCC 的 bug 然後 crash。反正單純 make 應該不會有問題。

如果 make 到一半掛了想重來,可以先 make clean 清除原本 build 到一半的狀態。

安裝編譯結果

make install

這樣就會把編譯完成的 Qt 安裝到 host machine 與 RPi image。這會裝到 -hostprefix 以及 image 的 filesystem root 加上 -prefix 指定的地方,例如上面的指令就是 ~/rpi/qt5pi(host)與 ~/rpi/rasp-pi-rootfs/usr/local/qt5pi。視情況根據權限加上 sudo 執行。

編譯其他模組

Qt 除了基本的模組之外,還有一些額外的選用元件。不過滿多在上面都已經一起編好了。為了你未來可能需要:

  1. cd 進去元件的目錄
  2. $RPIQT/bin/qmake .
  3. make
  4. sudo make install

要注意的是有些元件會有 dependency,例如 Qt Declarative 會需要 QT JS Backend。有些元件會需要 OpenGL 的 header files,在這種狀況就會需要你先在 image 上先裝好,才能正確編譯。

拷貝 image 到 SD 卡

這個大家應該都很熟了?

cd $RPIROOT
sudo umount rasp-pi-rootfs
sudo dd bs=1M if=2016-05-27-raspbian-jessie.img of=/dev/sdb

記得改 of 的 device name。

@bobhsiao

This comment has been minimized.

Copy link

commented Jul 11, 2016

回報一下我編譯的結果(Ubuntu 12.04.5 LTS, x86_64 / VMware Workstation 12 player)

  1. 可以用 make -j 8 編譯完成
  2. 「安裝編譯結果」需加 sudo 才能 make install
@seanlaii

This comment has been minimized.

Copy link

commented Jul 18, 2018

謝謝您的tutorial!!
不過我在編譯Qt Base的部份時,完成編譯後得到了以下的error:
The OpenGL ES 2.0 functionality test failed!
You might need to modify the include and library search paths by editing
QMAKE_INCDIR_OPENGL_ES2, QMAKE_LIBDIR_OPENGL_ES2 and QMAKE_LIBS_OPENGL_ES2 in
/home/seanlai/rpi/qt5/qtbase/mkspecs/devices/linux-rasp-pi2-g++
我是使用ubuntu 16.04 交叉編譯的pi 為raspberry pi2, 請問有什麼方法可以解決呢?
謝謝您.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.