VScode 使用初步

什麼是 VScode

Visual Studio Code(VScode) 是一個輕量級但功能強大的源代碼編輯器,可在桌面上運行,並且可用於Windows,macOS和Linux。VS code 包括一整套系統:比如內部支持 JavaScript,TypeScript 和 Node.js,能夠進行多種語言擴展(如 C++,C#,Java,Python,PHP,Go),也能夠進行多種運行擴展(如.NET 和 Unity)。

簡單的說就是 notepad+compiler+extensions。

VScode 特點

之前我也沒有用過 VScode,一直用的都是 VS,Qt 這樣的工具,但是真的用上 VScode 之後,就發現其實如果瞭解一下 VScode 的使用方式的話,這個工具使用起來還是比較簡單的。主要的特點有:

  • 跨平臺。VScode 能夠運行在 macOS,Linux,Windows操作系統上
  • 輕便靈活。VScode 在最初安裝只包含了開發流程共享的基本組件,只實現了包括編輯器,文件管理,窗口管理,首選項設置, JavaScript/TypeScript 語言服務和 Node.js 調試器等基本功能,此時的 VScode 就是一個代碼編輯器
  • 可擴展。VS Code 擴展可以添加對以下內容的支持:
    • 語言:C++,C#,Go,Java,Python
    • 工具:ESLint,JSHint,PowerShell
    • 調試器:Chrome,PHP XDebug。
    • 鍵盤映射:Vim,Sublime Text,IntelliJ,Emacs,Atom,Visual Studio,Eclipse

hello world

這一部分以實際例子來說明 VScode 的使用方法,運行平臺爲 Linux,編程語言爲 C/C++。

前提條件

  • GCC
  • GDB
  • VScode

建立工程

VScode 不同於 VS,Qt 可以直接新建工程,在 VScode 中需要自己手動建立工程目錄。其實就是新建一個文件夾,也不需要在文件夾中包含類似 CMakeLists.txt 的文件,因爲這樣的文件會在之後自動生成。

然後打開 VScode,利用菜單欄中的 File 打開剛剛新建的新文件夾,該文件夾就是工程目錄。

代碼編輯

此時先寫一個簡單的 hello world 程序:

// main.cpp
#include <iostream>

using namespace std;

int main()
{
    cout<<"Hello world!"<<endl;

    return 0;
}

.vscode

默認情況下,在工程目錄中會自動生成隱藏目錄 .vscode,該文件中主要包含三個文件:

  • task.json(編譯器構建設置)
  • launch.json(調試器設置)
  • c_cpp_properties.json(編譯器路徑和IntelliSense設置)

如果如果你此時沒有看到該隱藏文件夾也沒有關係,之後你構建上述三個文件中的任何一個文件都會生成該隱藏文件夾。

從這裏來看,該隱藏文件夾有點像是 Qt 中的 .pro 文件。

task.json

既然代碼已經寫完了,接下來就是 build task 了。

在主菜單中,選擇 Terminal > Configure Default Build Task。出現一個下拉列表,顯示用於C++編譯器的各種預定義構建任務。選擇C/C++: g++ build active file。

這將在 .vscode 文件夾中創建 tasks.json 文件,並在編輯器中將其打開。tasks.json 文件應類似於以下 JSON:

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558 
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "type": "shell",
            "label": "g++ build active file",
            "command": "/usr/bin/g++",
            "args": [
                "-g",
                "${file}",
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}"
            ],
            "options": {
                "cwd": "/usr/bin"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}

此時可以看到隱藏文件目錄 .vscode 自動被創建。上邊的參數有:

  • Command: 指定要運行的程序,在這種情況下是 g++
  • Args: 指定將傳遞給 g++ 的命令行參數。參數必須按照編譯器期望的順序指定
  • Label: 就是在任務列表中看到的值,可以隨意命名
  • Group: "isDefault": true指定當按Ctrl+Shift+B時將運行此任務。此屬性僅僅是爲了便利性,如果將其設置爲false,仍然可以通過terminal菜單中的Tasks: Run Build Task運行

此任務告訴 g++ 獲取活動文件(${file}),對其進行編譯,然後在當前目錄(${fileDirname})中創建一個與活動文件同名但沒有擴展名(${fileBasenameNoExtension)})的可執行文件,示例爲 main。

運行程序

  1. 返回 main.cpp,任務將構建活動文件。
  2. 要運行 tasks.json 中定義的構建任務,按 Ctrl+Shift+B 或從 terminal 菜單中選擇 Run Build Task。
  3. 任務啓動時,會看到集成終端面板出現在源代碼編輯器下方。任務完成後,終端將顯示編譯器的輸出,指示構建成功還是失敗。
  4. 使用 + 按鈕創建一個新終端,這將在 WSL 上下文中運行一個 bash 終端,並以當前文件夾作爲工作目錄。
  5. 此時可以在終端運行 main。

launch.json

此時只是構建了任務,生成了可執行程序,但是想要調試的話還需要用到 launch.json 來設置調試器的相關內容。

  • 在菜單欄中選擇 Run > Add Configuration...,然後選擇 C++ (GDB/LLDB)
  • 然後將出現各種預定義調試配置的下拉列表。選擇 g++ build and debug active file
  • VS Code 創建 launch.json 文件,在編輯器中打開爲:
{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "g++ - Build and debug active file",
            "type": "cppdbg",
            "request": "launch",
            "program": "${fileDirname}/${fileBasenameNoExtension}",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "g++ build active file",
            "miDebuggerPath": "/usr/bin/gdb"
        }
    ]
}

 上邊的參數中:

  • Program: 指定要調試的程序。這裏被設置爲活動文件文件夾${fileDirname}和沒有擴展名的活動文件名${fileBasenameNoExtension},如果helloworld.cpp是活動文件,則爲helloworld
  • 默認情況下,C++擴展不會在源代碼中添加任何斷點,因此stopAtEntry值設置爲false。stopAtEntry值爲true時,調試器啓動調試時遇到main方法停止

調試代碼

  • 返回 main.cpp,使其成爲活動文件
  • 按 F5 或從主菜單中選擇 Run > Start Debugging。此時用戶界面會發生一些更改:
    • 集成終端出現在源代碼編輯器的底部。在 Debug Output 選項卡中,可以看到指示調試器已啓動並正在運行
    • 編輯器突出顯示main方法中的第一條語句。這是 C++ 擴展自動設置的斷點
    • 左側的 run 視圖顯示調試信息
    • 在代碼編輯器的頂部,將顯示一個調試控制面板

調試控制面板的使用方法與其它 IDE 基本相同。

WATCH

在調試的時候,左側邊欄會出現一個 WATCH 的欄目,利用 WATCH 可以實現對變量跟蹤:

  • 在 WATCH 窗口中,單擊加號,然後在文本框中鍵入 var(變量名),此時可以逐步調試程序,可以看出該變量一直顯示在 WATCH
  • 在斷點開啓時,要快速查看任何變量的值,可以使用鼠標指針懸停在其上

c_cpp_properties.json

編程中通常會使用到一些第三方庫,如果要用到第三方庫的頭文件的話,就需要在該文件中添加頭文件目錄,不過此時添加的頭文件目錄只是爲了編程更加方法,實現智能感知,而並沒有真正的鏈接。

真正的鏈接需要在 task.json 文件中設置參數,才能夠正常編譯。

可以通過從 Command Palette (Ctrl+Shift+P) 運行命令 C/C++: Edit Configurations (UI) 來查看 C/C++ 配置 UI。

  • 當在此處進行更改時,VS Code會將更改寫入.vscode文件夾中的c_cpp_properties.json文件中。
  • 僅當程序包含不在工作空間或標準庫路徑中的頭文件時,才需要修改includepath設置。

外部庫鏈接的實例

當需要進行外部庫鏈接時,至少需要在 tasks.json 中進行頭文件包含和外部庫鏈接,如果需要使用代碼提示等智能感知功能的話,還需要修改 c_cpp_properties.json 文件。

以下用一個 C 語言的實例來簡單說明需要進行外部庫鏈接的情況(這裏的靜態庫是利用這篇文章中的文件生成的):

// main.c
#include <stdio.h>
#include <node.h>

int main()
{
    printf("insert a node from tail\n");
    ND *head = createListTail();

//    printf("insert a node from head\n");
//    ND *head = createListHead();

    printf("traval all node using next\n");
    travalListNext(head);

    printf("insert a node\n");
    insertList(head,10);
    travalListNext(head);

//    printf("traval all node using pre\n");
//    travalListPre(head);

    printf("calculate the length of list\n");
    int length = lenList(head);
    printf("The length of list is %d\n",length);

    printf("search a node in list from single direction\n");
    ND *pp = searchNodeSdir(head,10);
    printf("The search node is %d\n",pp->data);

//    printf("search a node in list from both direction\n");
//    pp = searchNodeBdir(head,10);
//    printf("The search node is %d\n",pp->data);

    printf("delete a node\n");
    deleteNode(pp);
    travalListNext(head);

    printf("sort list by swap data\n");
    sortSwapData(head,9);
    travalListNext(head);

//    printf("sort list by swap pointer\n");
//    sortSwapPointer(head,9);
//    travalListNext(head);

    printf("destroy list\n");
    destroyList(head);
}
// tasks.json
{
    "version": "2.0.0",
    "tasks": [
        {
            "type": "shell",
            "label": "gcc build active file",
            "command": "/usr/bin/gcc",
            "args": [
                "-g",
                "${file}",
                "-I",
                "~/libr",
                "-L",
                "~/libr",
                "-l",
                "node",
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}"
            ],
            "options": {
                "cwd": "/usr/bin"
            },
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}
// launch.json
{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "gcc - Build and debug active file",
            "type": "cppdbg",
            "request": "launch",
            "program": "${fileDirname}/${fileBasenameNoExtension}",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "Enable pretty-printing for gdb",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "gcc build active file",
            "miDebuggerPath": "/usr/bin/gdb"
        }
    ]
}
// c_cpp_properties.json
{
    "configurations": [
        {
            "name": "Linux",
            "includePath": [
                "${workspaceFolder}/**",
                "~/libr/**"
            ],
            "defines": [],
            "compilerPath": "/usr/bin/gcc",
            "cStandard": "c11",
            "cppStandard": "c++17",
            "intelliSenseMode": "clang-x64"
        }
    ],
    "version": 4
}
  • 該工程需要的編譯器是 gcc,而不是 g++
  • 如果在 c_cpp_properties.json 文件中沒有爲 includePath 參數添加頭文件,則在 main.c 文件中的 #include <node.h> 會出現下劃線,也就是說編輯器找不到該函數,但是實際是能夠編譯的。
  • 在 tasks.json 文件中添加了一些參數,如 -I,-L,-l 等,這些參數包含了頭文件和外部鏈接庫。
  • 不需要調試的話,可以不用添加 launch.json 文件

一個常見錯誤

當開始構建或調試時,xxx.cpp 不是活動文件時,最常見的錯誤原因(如 undefined _main 或 attempting to link with file built for unknown-unsupported file format 等)。這是因爲編譯器正在嘗試編譯不是源代碼的內容(如 launch.json,tasks.json 或 c_cpp_properties.json 文件)。

因此,運行任務時一定要保證當前活動文件爲包含 main 函數的文件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章