前言
1. 我已將本文所述的配置文件上傳到Apollo項(xiàng)目的GitHub倉庫,大家直接下載使用即可。
2. 我之前已寫過一篇博客《使用Visual Studio Code編譯Apollo項(xiàng)目》(https://blog.csdn.net/davidhopper/article/details/79349927),這篇文章內(nèi)容不夠全面,這里給出更為詳細(xì)的闡述。
Apollo項(xiàng)目以其優(yōu)異的系統(tǒng)架構(gòu)、完整的模塊功能、良好的開源生態(tài)及規(guī)范的代碼風(fēng)格,受到眾多開發(fā)者的喜愛和好評。然而,該項(xiàng)目使用命令行編譯和調(diào)試,不能使用IDE開發(fā),既不直觀,也不利于提高效率。我有點(diǎn)追求完美,必須想辦法讓Apollo項(xiàng)目能在IDE中編譯、調(diào)試。
Visual Studio Code(以下簡稱VSCode)是微軟第一款支持Linux的輕量級代碼編輯器,其功能介于編輯器與IDE之間,但更傾向于一個編輯器。優(yōu)點(diǎn)是運(yùn)行速度快,占用內(nèi)存少,使用方法與Visual Stuio類似。缺點(diǎn)在于,與Visual Studio、QT等IDE相比,功能還不夠強(qiáng)大。我認(rèn)為,Windows中最強(qiáng)大的C++ IDE為Visual Studio,Linux中最強(qiáng)大的C++ IDE為QT。
Apollo項(xiàng)目目前只支持Ubuntu系統(tǒng)(Mac OS系統(tǒng)部分支持),Windows系統(tǒng)中的Visual Studio自然排除在外;此外,Apollo項(xiàng)目使用Bazel編譯,而QT目前只支持QMake和CMake工程,因此只能忍痛割愛。在無法使用上述兩種IDE的前提下,退而求次選用VSCode。
我寫了幾個配置文件,允許使用VSCode編譯、調(diào)試Apollo項(xiàng)目,下面對其進(jìn)行具體闡述,希望能給廣大開發(fā)者帶來一定的幫助。
{ 一 }
使用VSCode編譯Apollo項(xiàng)目
首先從GitHub網(wǎng)站(https://github.com/ApolloAuto/apollo)下載Apollo源代碼,可以使用git命令下載,也可以直接通過網(wǎng)頁下載壓縮包。源代碼下載完成后,將其放置到合適的目錄。使用VSCode編譯Apollo項(xiàng)目有一個前提,就是在你的機(jī)器上已經(jīng)順利安裝了Docker。Apollo之前版本提供了一個“install_docker.sh”腳本文件,因?yàn)楹芏嚅_發(fā)者反映可能出錯,Apollo項(xiàng)目組已將該文件移除。現(xiàn)在要安裝Docker就只能參考Docker官方網(wǎng)站(https://www.docker.com/)的幫助文檔了。
1.1編譯方法
打開“Visual Studio Code”,執(zhí)行菜單命令“文件->打開文件夾”,在彈出的對話框中,選擇“Apollo”項(xiàng)目源文件夾,點(diǎn)擊“確定”,如下圖所示:
之后,執(zhí)行菜單命令“任務(wù)->運(yùn)行生成任務(wù)”或直接按快捷鍵“Ctrl+Shift+B”(與Visual Studio和QT的快捷鍵一致)構(gòu)建工程,若之前沒有啟動過Docker,則編譯時會啟動Docker,需在底部終端窗口輸入超級用戶密碼,如下圖所示:
命令執(zhí)行完畢,若在底部終端窗口出現(xiàn)“終端將被任務(wù)重用,按任意鍵關(guān)閉?!?a target="_blank">信息(如下圖所示),則表示構(gòu)建成功。整個過程一定要保持網(wǎng)絡(luò)暢通,否則無法下載依賴包。
1.2配置文件解析
我在.vscode/tasks.json文件中總共配置了四個常見的任務(wù):build the apollo project(構(gòu)建Apollo項(xiàng)目)、run all unit tests for the apollo project(運(yùn)行Apollo項(xiàng)目的所有單元測試)、code style check for the apollo project(Apollo項(xiàng)目的代碼風(fēng)格檢查)、clean the apollo project(清理Apollo項(xiàng)目)。其中第一個任務(wù)是默認(rèn)生成任務(wù),可以直接按快捷鍵“Ctr+Shift+B”調(diào)用,其他任務(wù)可通過執(zhí)行菜單命令:任務(wù)->運(yùn)行任務(wù)(R)…,在彈出的窗口中,選擇對應(yīng)選項(xiàng)即可,如下圖所示:
下面是具體的配置內(nèi)容,請參考里面的注釋來調(diào)整編譯任務(wù)以滿足你的構(gòu)建需求:
{ “version”: “2.0.0”,
“tasks”: [
{
“l(fā)abel”: “build the apollo project”,
“type”: “shell”,
// 可根據(jù)“apollo.sh”提供的選項(xiàng)來調(diào)整編譯任務(wù),例如:build_gpu
“command”: “bash apollo_docker.sh build”,
“group”: {
“kind”: “build”,
“isDefault”: true // default building task invoked by “Ctrl+Shift+B”
},
// 格式化錯誤信息
“problemMatcher”: {
“owner”: “cc”,
“fileLocation”: [
“relative”,
“${workspaceFolder}”
],
“pattern”: {
“regexp”: “^(.*):(\d+):(\d+):\s+(warning|error):\s+(.*)$”,
“file”: 1,
“l(fā)ine”: 2,
“column”: 3,
“severity”: 4,
“message”: 5
}
}
},
{
“l(fā)abel”: “run all unit tests for the apollo project”,
“type”: “shell”,
“command”: “bash apollo_docker.sh test”,
“problemMatcher”: {
“owner”: “cc”,
“fileLocation”: [
“relative”,
“${workspaceFolder}”
],
“pattern”: {
“regexp”: “^(.*):(\d+):(\d+):\s+(warning|error):\s+(.*)$”,
“file”: 1,
“l(fā)ine”: 2,
“column”: 3,
“severity”: 4,
“message”: 5
}
}
},
{
“l(fā)abel”: “code style check for the apollo project”,
“type”: “shell”,
“command”: “bash apollo_docker.sh lint”,
“problemMatcher”: {
“owner”: “cc”,
“fileLocation”: [
“relative”,
“${workspaceFolder}”
],
“pattern”: {
“regexp”: “^(.*):(\d+):(\d+):\s+(warning|error):\s+(.*)$”,
“file”: 1,
“l(fā)ine”: 2,
“column”: 3,
“severity”: 4,
“message”: 5
}
}
},
{
“l(fā)abel”: “clean the apollo project”,
“type”: “shell”,
“command”: “bash apollo_docker.sh clean”,
“problemMatcher”: {
“owner”: “cc”,
“fileLocation”: [
“relative”,
“${workspaceFolder}”
],
“pattern”: {
“regexp”: “^(.*):(\d+):(\d+):\s+(warning|error):\s+(.*)$”,
“file”: 1,
“l(fā)ine”: 2,
“column”: 3,
“severity”: 4,
“message”: 5
}
}
}
]}
1.3可能存在的問題及解決方法1.3.1 編譯時遇到“ERROR: query interrupted”錯誤
這是由于bazel內(nèi)部緩存不一致造成的。
解決方法:
按任意鍵退出編譯過程,在VSCode的命令終端窗口(如果未打開,按快捷鍵“Ctrl + `”開啟)執(zhí)行如下命令進(jìn)入Docker環(huán)境:
1 | bash docker/scripts/dev_into.sh |
在Docker環(huán)境中輸入如下命令,執(zhí)行bazel的清理緩存任務(wù)(一定要保持網(wǎng)絡(luò)暢通,以便成功下載依賴包,否則該命令即使執(zhí)行一萬次也不會奏效):
1 | bazel query //... |
最后輸入exit命令退出Docker環(huán)境,按快捷鍵“Ctrl+Shift+B”,重新執(zhí)行構(gòu)建任務(wù)。
1.3.2 編譯時長時間停留在“Building: no action running”界面
這是由于當(dāng)前系統(tǒng)中存在多個不同版本的Docker或者是bazel內(nèi)部緩存不一致造成的。
解決方法:
按快捷鍵“Ctrl+C”鍵終止當(dāng)前構(gòu)建過程,在VSCode的命令終端窗口(如果未打開,按快捷鍵“Ctrl + `”開啟),使用下述方法中的任意一種,停止當(dāng)前運(yùn)行的Docker:
1234 | # 方法1:停止當(dāng)前所有的Apollo項(xiàng)目Dockerdocker stop $(docker ps -a | grep apollo | awk '{print $1}')# 方法2:停止當(dāng)前所有的Dockerdocker stop $(docker ps -aq) |
執(zhí)行VSCode的菜單命令:任務(wù)->運(yùn)行任務(wù)(R)…,在彈出的窗口中,選擇 “clean the apollo project”(清理Apollo項(xiàng)目)。待清理完畢后,按快捷鍵“Ctrl+Shift+B”,重新構(gòu)建Apollo項(xiàng)目。
1.3.3 編譯時出現(xiàn)類似“Another command (pid=2466) is running. Waiting for it to complete…”的錯誤
這是由于在其他命令行終端進(jìn)行編譯或是在之前編譯時按下“Ctrl+C”鍵強(qiáng)行終止但殘留了部分編譯進(jìn)程所引起的。
解決方法:
按快捷鍵“Ctrl+C”鍵終止當(dāng)前構(gòu)建過程,在VSCode的命令終端窗口(如果未打開,按快捷鍵“Ctrl + `”開啟),使用如下命令終止殘留的編譯進(jìn)程:
123456789 | # 1.進(jìn)入Dockerbash docker/scripts/dev_into.sh# 2.殺死Docker中殘留的編譯進(jìn)程pkill bazel-real# 3.查看Docker中是否殘留bazel-real進(jìn)程,若有則按“q”退出,再次執(zhí)行步驟2。# 也可使用“ps aux | grep bazel-real”查看top# 4.退出Dockerexit |
按快捷鍵“Ctrl+Shift+B”,重新執(zhí)行構(gòu)建任務(wù)。
{ 二 }
使用VSCode本地調(diào)試Apollo項(xiàng)目
Apollo項(xiàng)目運(yùn)行于Docker中,不能在宿主機(jī)(所謂宿主機(jī)就是運(yùn)行Docker的主機(jī),因?yàn)镈ocker服務(wù)像寄宿于主機(jī)中,故有此稱呼)中直接使用GDB調(diào)試,而必須先在Docker中借助GDBServer創(chuàng)建調(diào)試服務(wù)進(jìn)程,再在宿主機(jī)中使用GDB連接Docker中的調(diào)試服務(wù)進(jìn)程來完成。下面介紹具體操作方法:
2.1前提條件2.1.1 編譯Apollo項(xiàng)目需帶調(diào)試信息
編譯Apollo項(xiàng)目時需使用build或build_gpu等帶調(diào)試信息的選項(xiàng),而不能使用build_opt或build_opt_gpu等優(yōu)化選項(xiàng)。
2.2.2 Docker內(nèi)部已安裝GDBServer
進(jìn)入Docker后,可使用如下命令查看:
1 | gdbserver --version |
若提示類似如下信息:
1234 | GNU gdbserver (Ubuntu 7.7.1-0ubuntu5~14.04.3) 7.7.1Copyright (C) 2014 Free Software Foundation, Inc.gdbserver is free software, covered by the GNU General Public License.This gdbserver was configured as "x86_64-linux-gnu" |
則表示Docker內(nèi)部已安裝了GDBServer(我已請Apollo項(xiàng)目組老師將GDBServer預(yù)裝至Docker內(nèi)部,正常情況下應(yīng)該能看到上述提示信息)。若提示如下信息:
1 | bash: gdbserver: command not found |
則表示Docker內(nèi)部未安裝GDBServer,可使用如下命令安裝:
1 | sudo apt-get install gdbserver |
2.2Docker內(nèi)部的操作2.2.1 啟動Dreamview后臺服務(wù)程序
進(jìn)入Docker,啟動Dreamview,命令如下:
1234567 | cd your_apollo_project_root_dir# 如果沒有啟動Docker,首先啟動,否則忽略該步bash docker/scripts/dev_start.sh -C# 進(jìn)入Dockerbash docker/scripts/dev_into.sh# 啟動Dreamview后臺服務(wù)bash scripts/bootstrap.sh |
2.2.2 啟動待調(diào)試模塊
啟動待調(diào)試模塊,既可使用命令行操作,也可借助Dreamview界面完成。我肯定喜歡使用Dreamview界面操作了,下面以調(diào)試“planning”模塊為例進(jìn)行說明。
打開Chrome瀏覽器,輸入網(wǎng)址:http://localhost:8888/,打開Dreamview界面,打開“SimControl”選項(xiàng),如下圖所示:
點(diǎn)擊左側(cè)工具欄“Module Controler”標(biāo)簽頁,選中“Routing”和“Planning”選項(xiàng),如下圖所示:
點(diǎn)擊左側(cè)工具欄“Default Routing”標(biāo)簽頁,選中“Route: Reverse Early Change Lane”或其中任意一個選項(xiàng),發(fā)送“Routing Request”請求,生成全局導(dǎo)航路徑,如下圖所示:
2.2.3 查看“Planning”進(jìn)程ID
使用如下命令,查看“Planning”進(jìn)程ID:
1 | top |
結(jié)果類似下圖,可以看到“Planning”進(jìn)程ID為4147,請記住該ID。按“q”退出“top”界面。
還可使用如下命令查看:
1 | ps aux | grep planning |
結(jié)果類似下圖,可以看到“Planning”進(jìn)程ID為4147。
2.2.4 使用GDBServer附加調(diào)試“Planning”進(jìn)程
接下來需要進(jìn)行我們的關(guān)鍵操作了,使用GDBServer附加調(diào)試“Planning”進(jìn)程,命令如下:
1 | sudo gdbserver :1111 --attach 4147 |
上述命令中,“:1111”表示開啟端口為“1111”的調(diào)試服務(wù)進(jìn)程,“4147”表示步驟2.2.3中查到的“Planning”進(jìn)程ID。若結(jié)果如下圖所示,則表示操作成功。
重新開啟一個命令終端,進(jìn)入Docker后,使用如下命令可看到“gdbserver”進(jìn)程已正常運(yùn)行:
1 | ps aux | grep gdbserver |
2.2.5 使用腳本文件啟動GDBServer
我寫了兩個腳本文件:scripts/start_gdb_server.sh、docker/scripts/dev_start_gdb_server.sh,其中前者用于在Docker內(nèi)部啟動GDBServer,后者直接在宿主機(jī)(Docker外部)啟動GDBServer。
假設(shè)調(diào)試planning模塊,端口號為1111,scripts/start_gdb_server.sh的使用方法為:
1234 | # 進(jìn)入Dockerbash docker/scripts/dev_into.sh# 啟動gdbserverbash scripts/start_gdb_server.sh planning 1111 |
假設(shè)調(diào)試planning模塊,端口號為1111,docker/scripts/dev_start_gdb_server.sh的使用方法為:
12 | # 在宿主機(jī)中(Docker外部)直接啟動gdbserverbash docker/scripts/dev_start_gdb_server.sh planning 1111 |
在2.3節(jié)我還將繼續(xù)配置VSCode文件,以便在VSCode中直接按快捷鍵“F5”就可啟動調(diào)試。
start_gdb_server.sh的內(nèi)容如下:
#!/usr/bin/env bashfunction print_usage()
{
RED=‘RM新时代网站-首页