Bài tập

Sử dụng Clang trong Visual Studio Code

Huy Erick

Trong hướng dẫn này, bạn sẽ cấu hình Visual Studio Code trên macOS để sử dụng trình biên dịch và gỡ lỗi Clang/LLVM. Sau khi cấu hình VS Code, bạn sẽ biên dịch và gỡ...

Trong hướng dẫn này, bạn sẽ cấu hình Visual Studio Code trên macOS để sử dụng trình biên dịch và gỡ lỗi Clang/LLVM.

Sau khi cấu hình VS Code, bạn sẽ biên dịch và gỡ lỗi một chương trình C++ trong VS Code. Hướng dẫn này không giảng dạy về Clang hoặc ngôn ngữ C++. Đối với những chủ đề đó, có nhiều tài liệu tốt có sẵn trên Web.

Nếu gặp bất kỳ vấn đề nào, hãy thoải mái gửi một vấn đề cho hướng dẫn này trong kho lưu trữ tài liệu của VS Code.

Yêu cầu tiên quyết

Để hoàn thành hướng dẫn này thành công, bạn phải thực hiện các bước sau:

  1. Cài đặt Visual Studio Code trên macOS.
  2. Cài đặt tiện ích mở rộng C++ cho VS Code. Bạn có thể cài đặt tiện ích C/C++ bằng cách tìm kiếm từ khóa 'C++' trong chế độ xem tiện ích mở rộng (⇧⌘X (Windows, Linux Ctrl+Shift+X)).

Đảm bảo Clang đã được cài đặt

Clang có thể đã được cài đặt sẵn trên Mac của bạn. Để xác nhận điều này, mở một cửa sổ Terminal trên macOS và nhập lệnh sau:

clang -version

Nếu Clang chưa được cài đặt, nhập lệnh sau để cài đặt các công cụ phát triển dòng lệnh, bao gồm Clang:

xcode-select -install

Tạo ứng dụng Hello World

Từ Terminal macOS, tạo một thư mục trống có tên projects để lưu trữ tất cả các dự án VS Code của bạn, sau đó tạo một thư mục con có tên helloworld, điều hướng vào thư mục đó và mở VS Code trong thư mục đó bằng cách nhập các lệnh sau vào cửa sổ terminal:

mkdir projects
cd projects
mkdir helloworld
cd helloworld
code .

Lệnh code . mở VS Code trong thư mục làm việc hiện tại, thư mục này sẽ trở thành "workspace" của bạn. Khi bạn hoàn thành hướng dẫn, ba tệp tin sẽ được tạo trong thư mục .vscode trong không gian làm việc của bạn:

  • tasks.json (cài đặt biên dịch trình biên dịch)
  • launch.json (cài đặt gỡ lỗi)
  • c_cpp_properties.json (đường dẫn trình biên dịch và cài đặt IntelliSense)

Thêm một tệp mã nguồn hello world

Trên thanh tiêu đề File Explorer, chọn nút New File và đặt tên tệp là helloworld.cpp.

Dán đoạn mã nguồn sau vào tệp:

#include 
#include 
#include 

using namespace std;

int main() {
    vector msg {"Hello", "C++", "World", "from", "VS Code", "and the C++ extension!"};
    for (const string& word : msg) {
        cout  word  " ";
    }
    cout  endl;
}

Bây giờ nhấn ⌘S (Windows, Linux Ctrl+S) để lưu tệp. Lưu ý rằng các tệp của bạn được liệt kê trong chế độ xem File Explorer (⇧⌘E (Windows, Linux Ctrl+Shift+E)) trong thanh bên của VS Code.

Bạn cũng có thể kích hoạt Auto Save để tự động lưu các thay đổi của tệp bằng cách chọn File > Auto Save. Bạn có thể tìm hiểu thêm về các chế độ xem khác trong tài liệu Giao diện người dùng của VS Code.

Lưu ý: Khi bạn lưu hoặc mở một tệp C++, bạn có thể nhìn thấy thông báo từ tiện ích C/C++ về sự hiện diện của phiên bản Insiders, cho phép bạn thử nghiệm các tính năng và sửa lỗi mới. Bạn có thể bỏ qua thông báo này bằng cách chọn X (Clear Notification).

Khám phá IntelliSense

IntelliSense là một công cụ giúp bạn viết mã nhanh hơn và hiệu quả hơn bằng cách thêm các tính năng chỉnh sửa mã như hoàn thành mã, thông tin về tham số, thông tin nhanh và danh sách thành viên.

Để xem IntelliSense hoạt động, di chuột qua vector hoặc string để xem thông tin về kiểu của chúng. Nếu bạn gõ msg. ở dòng 10, bạn có thể xem danh sách hoàn thành các hàm thành viên được đề xuất để gọi, tất cả được tạo ra bởi IntelliSense:

Bạn có thể nhấn phím Tab để chèn thành viên đã chọn. Sau đó, khi bạn thêm dấu ngoặc mở, thông tin về các đối số mà hàm yêu cầu sẽ được hiển thị.

Nếu IntelliSense chưa được cấu hình, hãy mở Command Palette (⇧⌘P (Windows, Linux Ctrl+Shift+P)) và nhập Select IntelliSense Configuration. Từ danh sách thấu kính của các trình dịch, chọn Use clang++ để cấu hình. Bạn có thể tìm hiểu thêm thông tin trong tài liệu về cấu hình IntelliSense.

Chạy helloworld.cpp

Hãy nhớ rằng tiện ích C++ sử dụng trình biên dịch C++ bạn đã cài đặt trên máy tính để xây dựng chương trình của bạn. Hãy đảm bảo bạn đã có một trình biên dịch C++ như Clang đã được cài đặt trước khi cố gắng chạy và gỡ lỗi helloworld.cpp trong VS Code.

  1. Mở tệp helloworld.cpp để làm tệp hoạt động.
  2. Nhấn nút phát ở góc trên bên phải của trình soạn thảo.

Bạn sẽ thấy danh sách các trình biên dịch phát hiện được trên hệ thống của bạn, hãy chọn C/C++: clang++ build and debug active file từ danh sách.

Bạn chỉ được yêu cầu chọn trình biên dịch lần đầu tiên bạn chạy helloworld.cpp. Trình biên dịch này là trình biên dịch "mặc định" được đặt trong tệp tasks.json.

Sau khi xây dựng thành công, kết quả chương trình của bạn sẽ xuất hiện trong Debug Console tích hợp sẵn.

Chúc mừng! Bạn vừa chạy chương trình C++ đầu tiên của mình trong VS Code!

Hiểu về tệp tasks.json

Lần đầu tiên bạn chạy chương trình của mình, tiện ích C++ sẽ tạo ra tệp tasks.json, nằm trong thư mục .vscode của dự án của bạn. tasks.json lưu trữ cấu hình xây dựng.

Dưới đây là một ví dụ về tệp tasks.json trên macOS:

{
    "tasks": [
        {
            "type": "cppbuild",
            "label": "C/C++: clang++ build active file",
            "command": "/usr/bin/clang++",
            "args": [
                "-fcolor-diagnostics",
                "-fansi-escape-codes",
                "-g",
                "${file}",
                "-o",
                "${fileDirname}/${fileBasenameNoExtension}"
            ],
            "options": {
                "cwd": "${fileDirname}"
            },
            "problemMatcher": ["$gcc"],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "detail": "Task generated by Debugger."
        }
    ],
    "version": "2.0.0"
}

Lưu ý: Bạn có thể tìm hiểu thêm về các biến tasks.json trong tài liệu về biến tham khảo.

Thiết lập command xác định chương trình muốn chạy. Trong trường hợp này, đó là clang++.

Mảng args xác định các đối số dòng lệnh được chuyển cho clang++. Những đối số này phải được chỉ định theo thứ tự mà trình biên dịch mong đợi.

Công việc này cho biết trình biên dịch C++ lấy tệp hoạt động (${file}), biên dịch nó và tạo một tệp đầu ra (-o switch) trong thư mục hiện tại (${fileDirname}) với cùng tên như tệp hoạt động nhưng không bao gồm phần mở rộng tệp (${fileBasenameNoExtension}). Quá trình này tạo ra helloworld.

Giá trị label là những gì bạn thấy trong danh sách các tác vụ, dựa trên sở thích cá nhân của bạn.

Giá trị detail là mô tả của tác vụ trong danh sách các tác vụ. Cập nhật chuỗi này để phân biệt nó với các tác vụ tương tự.

Giá trị problemMatcher chọn trình phân tích cú pháp đầu ra để tìm các lỗi và cảnh báo trong đầu ra trình biên dịch. Đối với clang++, trình phân tích cú pháp $gcc tạo ra kết quả tốt nhất.

Kể từ bây giờ, nút phát luôn đọc từ tasks.json để tìm cách xây dựng và chạy chương trình của bạn. Bạn có thể xác định nhiều tác vụ xây dựng trong tasks.json và bất kỳ tác vụ nào được đánh dấu là mặc định sẽ được sử dụng bởi nút phát. Nếu bạn cần thay đổi trình biên dịch mặc định, bạn có thể chạy Tasks: Configure Default Build Task trong Command Palette. Hoặc bạn có thể sửa đổi tệp tasks.json và loại bỏ mặc định bằng cách thay thế đoạn mã sau:

"group": {
    "kind": "build",
    "isDefault": true
}

bằng đoạn mã sau:

"group": "build"

Sửa đổi tệp tasks.json

Bạn có thể sửa đổi tệp tasks.json của mình để xây dựng nhiều tệp C++ bằng cách sử dụng đối số như "${workspaceFolder}/*.cpp" thay vì "${file}". Điều này sẽ xây dựng tất cả các tệp .cpp trong thư mục hiện tại. Bạn cũng có thể sửa đổi tên tệp đầu ra bằng cách thay thế "${fileDirname}/${fileBasenameNoExtension}" bằng một tên tệp được định cứng (ví dụ "${workspaceFolder}/myProgram.out").

Gỡ lỗi helloworld.cpp

Để gỡ lỗi mã của bạn:

  1. Quay trở lại tệp helloworld.cpp để làm cho tệp hoạt động.
  2. Đặt một điểm dừng bằng cách nhấp vào mép biên tập viên hoặc sử dụng F9 trên dòng hiện tại.

Từ thanh thả xuống kế bên nút phát, chọn Debug C/C++ File.

Chọn C/C++: clang++ build and debug active file từ danh sách các trình biên dịch đã phát hiện trên hệ thống của bạn (bạn chỉ được yêu cầu chọn trình biên dịch lần đầu tiên bạn chạy hoặc gỡ lỗi helloworld.cpp).

Bạn sẽ thấy tác vụ được thực thi và in kết quả ra cửa sổ Terminal.

Nút phát có hai chế độ: Run C/C++ FileDebug C/C++ File. Chế độ mặc định là chế độ cuối cùng sử dụng. Nếu bạn thấy biểu tượng gỡ lỗi trên nút phát, bạn có thể chọn nút phát để gỡ lỗi, thay vì chọn mục trong thả xuống.

Khám phá trình gỡ lỗi

Trước khi bạn bắt đầu từng bước đi qua mã, hãy để ý một số thay đổi trong giao diện người dùng:

  • Terminal được tích hợp xuất hiện ở cuối biên tập viên mã nguồn. Trong tab Debug Console, bạn thấy đầu ra cho biết trình gỡ lỗi đang hoạt động.
  • Biên tập viên nhấn mạnh dòng bạn đặt điểm dừng trước khi bắt đầu trình gỡ lỗi.
  • Thanh Run and Debug trong thanh hoạt động hiển thị thông tin về gỡ lỗi.
  • Ở đầu trình soạn thảo mã, một bảng điều khiển gỡ lỗi xuất hiện. Bạn có thể di chuyển bảng điều khiển này xung quanh màn hình bằng cách kéo các chấm ở phía trái.

Đi qua mã

Bây giờ bạn đã sẵn sàng bắt đầu từng bước đi qua mã.

  1. Chọn biểu tượng Step over trong bảng điều khiển gỡ lỗi để làm nổi bật câu lệnh for (const string& word : msg).

    Lệnh Step Over bỏ qua tất cả các cuộc gọi hàm nội bộ trong lớp vector và string được gọi khi biến msg được tạo và khởi tạo. Chú ý sự thay đổi trong cửa sổ Variables. Nội dung của msg hiển thị vì câu lệnh đó đã hoàn thành.

  2. Nhấn Step over một lần nữa để tiến tới câu lệnh tiếp theo (bỏ qua tất cả các mã nội bộ được thực thi để khởi tạo vòng lặp). Bây giờ, cửa sổ Variables hiển thị thông tin về biến vòng lặp.

  3. Nhấn Step over một lần nữa để thực thi câu lệnh cout.

  4. Nếu bạn muốn, bạn có thể tiếp tục nhấn Step over cho đến khi tất cả các từ trong vector được in ra màn hình console. Nhưng nếu bạn tò mò, hãy thử nhấn nút Step Into để đi qua mã nguồn trong thư viện chuẩn C++!

Đặt một watch

Bạn có thể theo dõi giá trị của một biến khi chương trình của bạn được thực thi bằng cách đặt watch trên biến đó.

  1. Đặt con trỏ chèn vào trong vòng lặp. Trong cửa sổ Watch, chọn dấu cộng và nhập word vào ô văn bản. Đây là tên biến vòng lặp. Bây giờ hãy xem cửa sổ Watch khi bạn từng bước đi qua vòng lặp.

  2. Thêm một watch khác bằng cách thêm câu lệnh này trước vòng lặp: int i = 0;. Sau đó, trong vòng lặp, thêm câu lệnh này: ++i;. Bây giờ thêm một watch cho i như bạn đã làm ở bước trước.

  3. Để nhanh chóng xem giá trị của bất kỳ biến nào trong khi thực thi tạm dừng, bạn có thể di chuột qua nó.

Tùy chỉnh gỡ lỗi với launch.json

Khi bạn gỡ lỗi với nút phát hoặc F5, tiện ích C++ tạo một cấu hình gỡ lỗi động ngay lập tức.

Có những trường hợp bạn muốn tùy chỉnh cấu hình gỡ lỗi của mình, để xác định đối số để truyền vào chương trình khi chạy. Bạn có thể xác định cấu hình gỡ lỗi tùy chỉnh trong một tệp launch.json.

Để tạo launch.json, chọn Add Debug Configuration từ menu thả xuống nút phát.

Bạn sẽ thấy một danh sách thả xuống cho các cấu hình gỡ lỗi được xác định trước. Chọn C/C++: clang++ build and debug active file.

VS Code tạo ra tệp launch.json, nó sẽ trông giống như sau:

{
    "configurations": [
        {
            "name": "C/C++: clang++ build and debug active file",
            "type": "cppdbg",
            "request": "launch",
            "program": "${fileDirname}/${fileBasenameNoExtension}",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${fileDirname}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "lldb",
            "preLaunchTask": "C/C++: clang++ build active file"
        }
    ],
    "version": "2.0.0"
}

Thiết lập program xác định chương trình bạn muốn gỡ lỗi. Ở đây, nó được đặt là thư mục tệp hoạt động ${fileDirname} và tên tệp hoạt động ${fileBasenameNoExtension}, nếu helloworld.cpp là tệp hoạt động, sẽ là helloworld. Thuộc tính args là một mảng các đối số để truyền vào chương trình khi chạy.

Mặc định, tiện ích C++ không thêm bất kỳ điểm dừng nào vào mã nguồn của bạn và giá trị stopAtEntry được đặt là false.

Thay đổi giá trị stopAtEntry thành true để buộc trình gỡ lỗi dừng ở phương thức main khi bạn bắt đầu gỡ lỗi.

Đảm bảo giá trị preLaunchTask khớp với nhãn của tác vụ xây dựng trong tệp tasks.json.

Lưu ý: Từ bây giờ trở đi, nút phát và F5 sẽ đọc từ tệp launch.json của bạn khi khởi chạy chương trình của bạn để gỡ lỗi.

Thêm các thiết lập C/C++ bổ sung

Để có sự kiểm soát hơn về tiện ích C/C++, hãy tạo tệp c_cpp_properties.json, cho phép bạn thay đổi các thiết lập như đường dẫn đến trình biên dịch, đường dẫn bao gồm, chuẩn C++ để biên dịch (như C++17), và nhiều hơn nữa.

Xem giao diện cấu hình C/C++ bằng cách chạy lệnh C/C++: Edit Configurations (UI) từ Command Palette (⇧⌘P (Windows, Linux Ctrl+Shift+P)).

Điều này mở trang C/C++ Configurations.

Visual Studio Code đặt các thiết lập này trong tệp .vscode/c_cpp_properties.json. Nếu bạn mở tệp này trực tiếp, nó nên trông giống như sau:

{
    "configurations": [
        {
            "name": "Mac",
            "includePath": ["${workspaceFolder}/**"],
            "defines": [],
            "macFrameworkPath": [
                "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks"
            ],
            "compilerPath": "/usr/bin/clang",
            "cStandard": "c11",
            "cppStandard": "c++17",
            "intelliSenseMode": "macos-clang-arm64"
        }
    ],
    "version": 4
}

Bạn chỉ cần sửa đổi thiết lập Include path nếu chương trình của bạn bao gồm các tệp tiêu đề không nằm trong không gian làm việc của bạn hoặc đường dẫn thư viện chuẩn.

Đường dẫn trình biên dịch

Tiện ích C/C++ sử dụng thiết lập compilerPath để suy luận đường dẫn đến các tệp tiêu đề thư viện chuẩn C++. Khi tiện ích biết nơi tìm các tệp đó, nó có thể cung cấp các tính năng như hoàn thành thông minh và điều hướng Go to Definition.

Tiện ích C/C++ cố gắng điền compilerPath với vị trí trình biên dịch mặc định dựa trên những gì nó tìm thấy trên hệ thống của bạn. Trình tự tìm kiếm compilerPath là:

  1. PATH của bạn cho tên của các trình biên dịch đã biết. Thứ tự các trình biên dịch xuất hiện trong danh sách phụ thuộc vào PATH của bạn.
  2. Sau đó, các đường dẫn Xcode được cố định được tìm kiếm, chẳng hạn như /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/

Để biết thêm thông tin, hãy xem tài liệu về cấu hình IntelliSense.

Đường dẫn framework trên Mac

Trên màn hình cấu hình C/C++, cuộn xuống và mở rộng Advanced Settings và đảm bảo Mac framework path trỏ đến các tệp tiêu đề thư viện hệ thống. Ví dụ: /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks

Khắc phục sự cố

Lỗi biên dịch và liên kết

Nguyên nhân phổ biến nhất của lỗi (như undefined _main, hoặc cố gắng liên kết với tệp xây dựng cho định dạng tệp không được hỗ trợ không biết) xảy ra khi helloworld.cpp không phải là tệp hoạt động khi bạn bắt đầu xây dựng hoặc gỡ lỗi. Điều này xảy ra vì trình biên dịch đang cố gắng biên dịch một cái gì đó không phải là mã nguồn, chẳng hạn như tệp launch.json, tasks.json hoặc c_cpp_properties.json của bạn.

Nếu bạn thấy lỗi xây dựng đề cập đến "C++11 extensions", có thể bạn chưa cập nhật tác vụ xây dựng của mình trong tệp tasks.json để sử dụng đối số của clang++ là -std=c++17. Mặc định, clang++ sử dụng chuẩn C++98, không hỗ trợ cách khởi tạo được sử dụng trong helloworld.cpp. Hãy đảm bảo thay thế toàn bộ nội dung của tệp tasks.json của bạn bằng khối mã được cung cấp trong phần Chạy helloworld.cpp.

Cửa sổ Terminal không khởi chạy để nhập

Trên macOS Catalina và các phiên bản sau, bạn có thể gặp sự cố không thể nhập vào khi sử dụng "externalConsole": true. Một cửa sổ terminal mở ra, nhưng bạn không thể nhập bất kỳ đầu vào nào.

Vấn đề này đang được theo dõi tại #5079.

Cách khắc phục là để VS Code khởi chạy cửa sổ terminal một lần. Bạn có thể làm điều này bằng cách thêm và chạy tác vụ sau trong tệp tasks.json của bạn:

{
    "label": "Open Terminal",
    "type": "shell",
    "command": "osascript -e 'tell application \"Terminal\" to do script \"echo hello\"",
    "problemMatcher": []
}

Bạn có thể chạy công việc cụ thể này bằng Terminal > Run Task... và chọn Open Terminal.

Sau khi bạn chấp nhận yêu cầu cho phép, sau đó cửa sổ bên ngoài nên xuất hiện khi bạn gỡ lỗi.

Tiếp theo

  • Tìm hiểu thêm về VS Code User Guide.
  • Xem lại Tổng quan về tiện ích C++.
  • Tạo một không gian làm việc mới, sao chép các tệp .json của bạn vào đó, điều chỉnh các thiết lập cần thiết cho đường dẫn không gian làm việc mới, tên chương trình, và nhiều hơn nữa, và bắt đầu lập trình!
1