Skip to content

Instantly share code, notes, and snippets.

@uranusjr
Last active May 7, 2019 14:35
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save uranusjr/91c0086109e6c35bbbe48a0b6a405f78 to your computer and use it in GitHub Desktop.
Save uranusjr/91c0086109e6c35bbbe48a0b6a405f78 to your computer and use it in GitHub Desktop.
在 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。

@ychsiao168
Copy link

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

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

@seanlaii
Copy link

seanlaii 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