この記事について
以前、この記事(https://qiita.com/take-iwiw/items/46119bb7d41c6030d34f )で、お手軽にラズパイ用のC/C++開発環境の構築を行いました。この時は、ビルドやデバッグは全てラズパイ上で行いました。
今回は、Ubuntu上でのクロスコンパイルと、gdbserverを使用したリモートデバッグ方法について記します。最終的には、ホストPC上のVSCodeからGUI操作でラズパイのデバッグをできるようにします。デバッグはUbuntu, Windowsのどちらからもできるようにしました。
なお、本記事ではラズパイを対象に記載していますが、一般的な組み込みLinuxのクロス開発にも適用できると思います。
環境
- Target
- Raspberry Pi (IPアドレスなどは適宜読み替えてください)
- IPアドレスは192.168.1.89
- SSHは有効済み
- Raspberry Pi (IPアドレスなどは適宜読み替えてください)
- Host
- Ubuntu 16.04 on VirtualBox on Windows 10
- クロスコンパイル用
- デバッグ用
- MSYS2 64-bit
- デバッグ用 (デバッグをWindowsから行いたい人用)
- Ubuntu 16.04 on VirtualBox on Windows 10
クロスコンパイル (on Ubuntu)
クロスコンパイラの取得
基本的に1回だけやればOKです。
sudo apt-get update
sudo apt-get install build-essential libncurses-dev git git-core
mkdir ~/raspberry
cd ~/raspberry
git clone https://github.com/raspberrypi/tools
ビルド
下記のような~/work/pi/sample01/sample01.cppをビルドしてみます。
#include <stdio.h>
int main()
{
printf("Hello World\n");
for (int i = 0; i < 10; i++)
printf("i = %d\n", i);
return 0;
}
mkdir ~/work/pi/sample01 && cd ~/work/pi/sample01
code sample01.cpp &
ARCH=arm ~/raspberry/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-g++ sample01.cpp
# ARCH=arm ~/raspberry/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-g++ sample01.cpp
scp a.out pi@192.168.1.89:.
最後のscpコマンドで転送したa.outをラズパイ上で実行できます。
32-bit環境の場合は、raspberry/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin
の方がいいかもしれません。
リモートデバッグ
こちらの記事を大変参考にさせていただきました。(https://qiita.com/tetsu_koba/items/ebbac47e3fb43c86f412 )。ありがとうございます。
準備
基本的に1回だけやればOKです。
gdbserverのインストール (on ラズパイ)
sudo apt-get install gdbserver
ARM用gdbバイナリの作成 (on Ubuntu)
mkdir ~/temp && cd ~/temp
wget http://ftp.jaist.ac.jp/pub/GNU/gdb/gdb-8.0.1.tar.gz
tar xf gdb-8.0.1.tar.gz
cd gdb-8.0.1
mkdir build && cd build
sudo apt-get install libexpat1-dev expat
../configure --target=arm-buildroot-linux-gnueabi --with-expat
make -j4
sudo make install
リモートデバッグする
gdbserverの起動 (on ラズパイ)
gdbserver --multi :5555
gdb実行 (on Ubuntu)
デバッグしたい実行ファイルと同じところに、以下のようなファイル(~/work/pi/sample01/gdb_load)を作っておきます。
target extended-remote 192.168.1.89:5555
file ./a.out
remote put ./a.out /home/pi/a.out
set remote exec-file /home/pi/a.out
start
gdb_loadとa.outと同じパスで下記コマンドを実行すると、デバッグが始まります。
デバッグ情報はUbuntu側のターミナルに、printf等の出力はラズパイ側のターミナルに出力されます。
arm-buildroot-linux-gnueabi-gdb -x gdb_load
# ↓はgdb内のプロンプト
>>> n
デバッグをやり直すとき (on Ubuntu)
基本的にラズパイ側で起動したgdbserverは常時起動でOKです。そのため、ラズパイ側での操作は不要です。
Ubuntu側のgdbターミナルで、q
をして、再度gdbを実行させれば再起動します。
VSCodeからリモートデバッグする (on Ubuntu)
gdbコマンドによるデバッグでは、よっぽど慣れた人でないと効率が悪いと思います。VisualStudio CodeからGUIによってデバッグできるようにします。一般のアプリケーション開発と同様に、ステップ実行やブレークポインタの設定をGUIからできるようにして、スコープ内の変数なども自動で参照できるようにします。
VisualStudio Codeの設定 (on Ubuntu)
~/work/pi/sample01/
ディレクトリをVSCodeから開き、F5キーを押してデバッグしようとします。その後、デバッグ設定を作るように聞かれるので、C++(GDB/LLDB)を選択します。
launch.jsonが開かれるので、下記のように編集します。
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/a.out", // ★編集
"args": [],
"stopAtEntry": true, // ★編集(お好みで)
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "arm-buildroot-linux-gnueabi-gdb", // ★追加
"setupCommands": [ // ★追加
{"text": "target extended-remote 192.168.1.89:5555"},
{"text": "file a.out"},
{"text": "remote put a.out /home/pi/a.out"},
{"text": "set remote exec-file /home/pi/a.out"}
]
}
]
}
VisualStudio Codeからデバッグする (on Ubuntu)
再度F5キーを押すと、デバッグが始まります。以後、本ディレクトリのプロジェクトをデバッグするときはF5キーを押すだけでOKです。
printf等の出力はラズパイ側のターミナルに出力されます。
Windowsからリモートデバッグする
一般的に、ターゲットがLinuxの場合には開発用HOST環境もLinuxだと思います。しかし、何らかの理由でコードの編集やデバッグをWindowsPCで行いたいというのはよくあると思います。(例えば、ビルドはLinuxのビルドサーバーで行い、開発者のWindowsPCにビルドされたバイナリをダウンロードして、それをターゲットに書き込む、などはよくある運用だと思います)。
このような環境では、デバッグのためだけにUbuntuを入れるのが面倒だと思いますので、Windows上でもできるようにします。ターミナル操作のために、MSYS2を使用します。
ARM用gdbバイナリの作成 (on Windows(MSYS2))
下記コマンドでARM用のgdbバイナリを作成します。
mkdir ~/temp && cd ~/temp
wget http://ftp.jaist.ac.jp/pub/GNU/gdb/gdb-8.0.1.tar.gz
tar xf gdb-8.0.1.tar.gz
cd gdb-8.0.1
mkdir build && cd build
../configure --target=arm-buildroot-linux-gnueabi --with-expat
make -j4
make install
メモ
一度ビルドは成功したのですが、その後pythonのインストール(pacman -S python2
)をしたり色々してたら、再ビルドが出来なくなってしまいました。。。
VisualStudio Codeの設定 (on Windows)
基本的にはUbuntuでやったのと全く同じです。ソースコードとビルド済みARM用バイナリがC:/Users/tak/Desktop/win_share/sample01/
にあるとします。
launch.jsonを下記のように編集します。
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/a.out", // ★編集
"args": [],
"stopAtEntry": true, // ★編集(お好みで)
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "C:/msys64/mingw64/bin/arm-buildroot-linux-gnueabi-gdb.exe", // ★追加
"setupCommands": [ // ★追加
{"text": "target extended-remote 192.168.1.89:5555"},
{"text": "file C:/Users/tak/Desktop/win_share/sample01/a.out"},
{"text": "remote put C:/Users/tak/Desktop/win_share/sample01/a.out /home/pi/a.out"},
{"text": "set remote exec-file /home/pi/a.out"}
]
}
]
}
注意点として、自分でビルドしたARM用gdbにはWindows上でのパスを通していないので、フルパス指定する必要があります。また、ロードするバイナリファイルもフルパス指定する必要がありました。${workspaceFolder}
を使って省略できないか試したのですが、上手くいきませんでした。
VSCodeからリモートデバッグする (on Windows)
再度F5キーを押すことで、下記のようにデバッグできます。
ラズパイ用の僕の運用
僕はメインPCがWindowsなので、ビルドだけラズパイで行い、デバッグはWindows上のVSCodeでやっています。
- Windows上のVSCodeで、コードを書く
- Windows上のVSCodeで、sftpエクステンション機能でコードをラズパイにアップロード
- ラズパイ上で、ビルド(./a.outを作成)
g++ -O0 -g3 sample01.cpp
- Windows上のVSCodeで、sftpエクステンション機能でバイナリ(./a.out)をダウンロード
- Windows上のVSCodeで、デバッグ実行
その他
- gdbserverを終了するときは、ホスト側のgdbプロンプトから
monitor exit
- 共有ライブラリの場所を指定するときは、
set sysroot ./
- ビルド環境とgdb実行環境でソース構成やパスが異なるときは、
set substitute-path from-path to-path
- 環境が違っても、一応うまく動いてはくれた。相対パスがあっていたら多少は大丈夫そう。