<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    在Linux中使用VS Code編譯調試C++項目

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    最近項目需求,需要在Linux下開發C++相關項目,經過一番摸索,簡單總結了一下如何通過VS Code進行編譯調試的一些注意事項。

    關于VS Code在Linux下的安裝這里就不提了,不管是CentOS還是Ubuntu,如果不懂且搜Q足夠的情況下,你會解決的。

    一. 前置知識——gcc/g++的編譯鏈接過程

    在Windows下,如果你用Visual Studio進行開發,C/C++的編譯器一般采用微軟提供的MSBuild;在Linux下C/C++的編譯器大多采用gcc/g++。既然要在Linux下進行C++開發,很有必要了解一下g++編譯器的一些基本知識。

    假設我現在有一個最簡單的C++文件:

    1 #include <iostream>
    2 using namespace std;
    3 int main() {
    4     cout << "Hello, world!!!!" << endl;
    5     return 0;
    6 }

    接下來如何編譯呢?簡單來說分成兩步:先編譯,再鏈接

    1. 安裝g++編譯器

    啟動終端,進入root模式,安裝gcc和g++

    Ubuntu:

    xxx@xxx:~$ sudo apt-get install build-essential

    xxx@xxx:~$ gcc --version
    xxx@xxx:~$ sudo apt-get install g++-4.8
    xxx@xxx:~$ g++ --version

    CentOS:

    [xxx@xxx ~]$ su
    [xxx@xxx ~]# yum install gcc
    [xxx@xxx ~]# gcc --version
    [xxx@xxx ~]# yum install gcc-g++
    [xxx@xxx ~]# g++ --version

    2. 編譯hello.cpp

    [xxx@xxx ~]$ g++ -c hello.cpp

    輸出結果是一個hello.o文件,這是編譯過程的生成的中間文件。-c 表示只編譯,不鏈接

    3. 鏈接hello.o生成hello.out

    [xxx@xxx ~]$ g++ -o hello.out hello.o

    輸出結果是一個hello.out文件,這是最終的可執行文件。-o 表示輸出文件,hello.o是上一步生成的.o文件。

    當然,如果第2、3步是可以合并執行,直接執行命令

    [xxx@xxx ~]$ g++ -o hello.out hello.cpp

    然而第2、3步分開執行是有意義的,后面會講到。

    4. 運行hello.out

    最后執行以下hello.out驗證一下輸出結果唄

    [xxx@xxx ~]$ ./hello.out

    二. 構建項目

    實際開發過程中當然不可能只有一個cpp這么簡單,有時候會有非常多的.h和.cpp文件相互配合,那么上面直接通過g++編譯可執行文件就沒那么簡單了。我們需要借助Make這個強大的項目構建工具,幫助我們構建和組織項目代碼。

    假設現在有如下3個文件:hw2.cpp、solution.h和solution.cpp

    1 /* solution.h */
    2 class Solution {
    3 public:
    4     void Say();
    5 };
    1 /* solution.cpp */
    2 #include <iostream>
    3 #include "solution.h"
    4 void Solution::Say(){
    5    std::cout << "HI!" << std::endl;
    6 }
    復制代碼
    1 /* hw2.cpp */
    2 #include "solution.h"
    3 int main () {
    4     Solution sln;
    5     sln.Say();
    6     return 0;
    7 }
    復制代碼

     

    可以看到這個簡單例子包括頭文件引用、定義和實現分離等情況,如果直接g++ -o hw2.out hw2.cpp將會報未定義引用的錯誤:

    [xxx@xxx ~]$ g++ -o hw2.out hw2.cpp 
    /tmp/ccIMYTxf.o:在函數‘main’中:
    hw2.cpp:(.text+0x10):對‘Solution::Say()’未定義的引用
    collect2: 錯誤:ld 返回 1

     

    這時Make就該大顯身手了。

    首先我們還需要了解一下makefile。

    在項目的根目錄下創建一個makefile文件,以告訴Make如何編譯和鏈接程序。

    復制代碼
    1 build : hw2.o solution.o
    2     g++ -o build hw2.o solution.o #注意前面必須是tab,不能是空格
    3 hw2.o : hw2.cpp solution.h
    4     g++ -g -c hw2.cpp
    5 solution.o : solution.h solution.cpp
    6     g++ -g -c solution.cpp
    7 clean :
    8     rm hw2.o solution.o build
    復制代碼

     

    先來解釋一下makefile的基本語法規則:

    target ... : prerequisites ...
      command    #注意前面是tab

    target是一個目標文件,可以是Object File,也可以是執行文件,還可以是一個標簽;

    prerequisites是要生成那個target所需要的文件或是目標;

    command是make需要執行的命令(任意的Shell命令)。

    說白了就是target這一個或多個目標,依賴于prerequisites列表中的文件,其執行規則定義在command里。如果prerequisites列表中文件比target要新,就會執行command,否則就跳過。這就是整個make過程的基本原理。

     

    那么,我們回頭看看上面定義的makefile文件,我們解釋一下每兩行的作用

    1 build : hw2.o solution.o
    2     g++ -o build hw2.o solution.o

    target是build,依賴于hw2.o 和 solution.o,執行的命令是 g++ -o build hw2.o solution.o

    意思是通過g++鏈接hw2.o和solution.o,生成可執行文件build,prerequisites有兩個.o文件,是因為代碼里hw2引用了solution.h。

     

    3 hw2.o : hw2.cpp solution.h
    4      g++ -g -c hw2.cpp

    target是hw2.o,依賴于hw2.cpp和solution.h,執行命令是g++ -g -c hw2.cpp

    意思是通過g++編譯hw2.cpp文件,生成hw2.o文件,g++命令中 -g 表示生成的文件是可調試的,如果沒有-g,調試時無法命中斷點。

     

    5 solution.o : solution.h solution.cpp
    6     g++ -g -c solution.cpp

    同上,編譯solution.cpp文件,生成solution.o文件。

     

    7 clean :
    8     rm hw2.o solution.o build

    這里clean不是一個可執行文件,也不是一個.o文件,它只不過是一個動作名字,類似于label的作用,make不會去找冒號后的依賴關系,也不會自動執行命令。如果要執行該命令,必須在make后顯示指出整個動作的名字,如make clean。

     

    好了,接下來說一下make的工作原理。在默認的方式下,我們只需輸入make,則發生了以下行為:

    a. make在當前目錄下找名為makefile或Makefile的文件;

    b. 如果找到,它會找文件中的第一個target,如上述文件中的build,并作為終極目標文件;

    c. 如果第一個target的文件不存在,或其依賴的.o 文件修改時間要比target這個文件新,則會執行緊接著的command來生成這個target文件;

    d. 如果第一個target所依賴的.o文件不存在,則會在makefile文件中找target為.o的依賴,如果找到則執行command,.o的依賴必是.h或.cpp,于是make可以生成 .o 文件了

    e. 回溯到b步執行最終目標

     

    看一下執行結果

    復制代碼
    [xxx@xxx ~]$ make
    g++ -g -c hw2.cpp
    g++ -g -c solution.cpp
    g++ -o build hw2.o solution.o #注意前面必須是tab,不能是空格
    [xxx@xxx ~]$ ./build 
    HI!
    [xxx@xxx ~]$
    復制代碼

     

    由于makefile文件中加了-g這一選項,于是可以通過gdb進行調試,并且會命中斷點,這里感興趣可以再了解一下gdb的使用。

    接下來我們要說到如何通過VS Code進行調試。

     

    三. 在VS Code中編譯調試

    首先安裝完VS Code之后,還需要安裝一下擴展cpptools,請自行完成。

    RFID設備管理軟件

     

    點擊菜單 查看-> 調試,或直接快捷鍵ctrl + shift + D

     RFID設備管理軟件

    點擊設置圖標,在彈出的選擇環境中選擇C++(GDB/LLDB),會自動創建一個launch.json文件

    RFID設備管理軟件

    顧名思義,laucn.json的作用是告訴VS Code如何執行啟動任務,也就是我們要把什么文件啟動起來,在上述例子中顯然是build這個可執行文件了。修改一下json文件中波浪線的program節點,改成${workspaceRoot}/build,其余的暫時不變

     

    復制代碼
     1 {
     2     "version": "0.2.0",
     3     "configurations": [
     4         {
     5             "name": "C++ Launch",
     6             "type": "cppdbg",
     7             "request": "launch",
     8             "program": "${workspaceRoot}/build",
     9             "args": [],
    10             "stopAtEntry": false,
    11             "cwd": "${workspaceRoot}",
    12             "environment": [],
    13             "externalConsole": true,
    14             "linux": {
    15                 "MIMode": "gdb"
    16             },
    17             "osx": {
    18                 "MIMode": "lldb"
    19             },
    20             "windows": {
    21                 "MIMode": "gdb"
    22             }
    23         },
    24         {
    25             "name": "C++ Attach",
    26             "type": "cppdbg",
    27             "request": "attach",
    28             "program": "${workspaceRoot}/build",
    29             "processId": "${command.pickProcess}",
    30             "linux": {
    31                 "MIMode": "gdb"
    32             },
    33             "osx": {
    34                 "MIMode": "lldb"
    35             },
    36             "windows": {
    37                 "MIMode": "gdb"
    38             }
    39         }
    40     ]
    41 }
    復制代碼

    接著我們嘗試一下F5,開始調試,結果可以看到報了一個缺少build文件的錯誤。原因是我們還沒執行make編譯出可執行文件呢。我們在launch.json文件中,添加一個preLaunchTask的節點,并設置值為“build”。注意這里的build不是指可執行文件build,而是一個名為build的任務!

    復制代碼
     1 {
     2     "version": "0.2.0",
     3     "configurations": [
     4         {
     5             "name": "C++ Launch",
     6             "type": "cppdbg",
     7             "request": "launch",
     8             "program": "${workspaceRoot}/build",
     9             "args": [],
    10             "stopAtEntry": false,
    11             "cwd": "${workspaceRoot}",
    12             "environment": [],
    13             "externalConsole": true,
    14             "preLaunchTask": "build",
    15             "linux": {
    16                 "MIMode": "gdb"
    17             },
    18             "osx": {
    19                 "MIMode": "lldb"
    20             },
    21             "windows": {
    22                 "MIMode": "gdb"
    23             }
    24         },
    25         {
    26             "name": "C++ Attach",
    27             "type": "cppdbg",
    28             "request": "attach",
    29             "program": "${workspaceRoot}/build",
    30             "processId": "${command.pickProcess}",
    31             "linux": {
    32                 "MIMode": "gdb"
    33             },
    34             "osx": {
    35                 "MIMode": "lldb"
    36             },
    37             "windows": {
    38                 "MIMode": "gdb"
    39             }
    40         }
    41     ]
    42 }
    復制代碼

    再嘗試F5,會提示一個信息:

    RFID設備管理軟件

    點擊配置任務運行程序,并選擇Others, 會自動生成一個tasks.json文件,這個文件的作用就是告訴launch或者編譯器需要執行什么操作。顯然我們這里要執行make命令,修改tasks.json為如下:

    復制代碼
     1 {
     2     "version": "0.1.0",
     3     "command": "make",
     4     "showOutput": "always",
     5     "tasks": [
     6         {
     7             "taskName": "clean"
     8         },
     9         {
    10             "taskName": "build",
    11             "problemMatcher": {
    12                 "owner": "cpp",
    13                 "fileLocation":  ["relative", "${workspaceRoot}"],
    14                 "pattern": {
    15                     "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
    16                     "file": 1,
    17                     "line": 2,
    18                     "column": 3,
    19                     "severity": 4,
    20                     "message": 5
    21                 }
    22             }
    23         }
    24     ]
    25 }
    復制代碼

    其中tasks節點是一組任務,注意到其中一個名為build的任務,這就是launch.json文件中指定的preLaunchTask,表明在啟動可執行程序之前,會先執行一下preLaunchTask即這里的build任務,重新make一下代碼,更新可執行程序之后再啟動。

    當然也可以指運行tasks這些任務而不啟動可執行程序,直接ctrl + shift + B,在VSC的console里可以看到和終端執行一樣的輸出:

    RFID設備管理軟件

    執行完后,項目中會多出.o和build文件

    RFID設備管理軟件

     

    關于VS Code的launch.json和tasks.json中更多節點的含義,參考

    https://code.visualstudio.com/docs/editor/debugging

    https://code.visualstudio.com/docs/editor/tasks

     

    接著設置好斷點之后F5,就可以進入斷點調試了

    RFID設備管理軟件

     

     --------------------------------------------------------------------------------------------------------------------------------------------------

     

    本篇總結了gcc/g++和make/makefile的基礎知識,以及在Linux下使用VS Code進行調試開發的方法,希望對正在挖坑的同學有所幫助,坑避免一個是一個。

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全