VS Code C++ 설정 방법: IntelliSense 빨간 밑줄, tasks.json 빌드, launch.json 디버깅, clangd
[C++ 실전 가이드 #3] VS Code C++ 개발 환경 설정
VS Code로 C++을 처음 쓸 때 가장 흔한 문제는 이것입니다. 터미널에서는 g++ main.cpp -o main이 잘 되는데, 편집기에서는 <iostream>, <vector> 같은 표준 헤더에 빨간 밑줄이 그어지고 자동 완성도 제대로 동작하지 않습니다. 원인은 VS Code의 C/C++ 확장이 “어느 컴파일러를 쓰며, 헤더를 어디서 찾을지” 모르기 때문입니다.
설정할 파일은 .vscode/ 폴더 안의 세 개입니다. c_cpp_properties.json은 IntelliSense(코드 자동 완성, 함수 시그니처 표시, 에러 밑줄 같은 편집 보조 기능)가 쓸 컴파일러와 헤더 경로를, tasks.json은 빌드 명령을, launch.json은 디버거 실행 방법을 정합니다. 이 중 c_cpp_properties.json의 compilerPath를 터미널에서 쓰는 컴파일러와 같게 맞추기만 해도 빨간 밑줄은 대부분 사라집니다.
컴파일러(#2)가 설치되어 터미널에서 빌드가 되는 상태라고 가정합니다. 아직이라면 개발 환경 구축(#1)부터 진행하세요.
flowchart TB
subgraph editor[VS Code 에디터]
A[소스 코드 편집]
B[IntelliSense]
end
subgraph config["설정 파일 (.vscode/)"]
C[c_cpp_properties.json]
D[tasks.json]
E[launch.json]
end
subgraph build[빌드 & 실행]
F[g++/clang++]
G[실행 파일]
H[GDB/LLDB]
end
C -->|컴파일러 경로, 헤더 경로| B
B -->|자동 완성, 에러 표시| A
D -->|빌드 명령 정의| F
F -->|컴파일| G
E -->|디버그 설정| H
H -->|디버깅| G
1단계: VS Code와 C/C++ 확장 설치
VS Code 공식 사이트에서 운영체제에 맞는 설치 프로그램을 받아 기본 설정으로 설치합니다. Windows 설치 프로그램에서 “PATH에 추가” 옵션을 체크해 두면 터미널에서 code . 명령으로 현재 폴더를 열 수 있어 편합니다.
VS Code 자체는 C++을 이해하지 못하므로 확장을 설치해야 합니다. 왼쪽 사이드바의 Extensions 아이콘을 누르거나 Ctrl+Shift+X(macOS: Cmd+Shift+X)를 누른 뒤, “C/C++“를 검색해 Microsoft가 배포하는 확장(ms-vscode.cpptools)을 설치합니다. 이 확장이 IntelliSense, 코드 탐색, 그리고 GDB(GNU 디버거)·LLDB(LLVM 디버거, macOS 기본)를 이용한 디버깅을 제공합니다.
C/C++ 확장은 컴파일러를 직접 포함하지 않습니다. 설치된 컴파일러에게 기본 헤더 경로와 매크로를 물어보는 방식이라, compilerPath가 틀리거나 비어 있으면 시스템 헤더를 찾지 못해 “빌드는 되는데 빨간 밑줄이 나오는” 상황이 생깁니다.
2단계: c_cpp_properties.json으로 IntelliSense 맞추기
프로젝트 루트에 .vscode 폴더를 만들고 c_cpp_properties.json을 생성합니다. 명령 팔레트(Ctrl+Shift+P)에서 “C/C++: Edit Configurations (JSON)“을 실행해도 같은 파일이 만들어집니다.
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/usr/bin/g++",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "linux-gcc-x64"
}
],
"version": 4
}
각 필드의 의미는 다음과 같습니다.
| 필드 | 의미 |
|---|---|
name | 구성 이름. Linux, Mac, Win32로 지으면 확장이 현재 OS에 맞는 구성을 자동 선택합니다. |
includePath | 헤더 검색 경로. ${workspaceFolder}/**의 **는 하위 폴더 전체를 재귀적으로 포함한다는 뜻입니다. |
defines | IntelliSense가 정의된 것으로 볼 매크로. 예: ["DEBUG=1"]이면 #ifdef DEBUG 블록이 활성으로 표시됩니다. |
compilerPath | 실제 빌드에 쓰는 컴파일러의 전체 경로. which g++(Windows는 where g++)의 결과를 넣습니다. |
cppStandard | C++ 표준(c++17, c++20, c++23 등). 빌드 옵션의 -std와 같게 맞춥니다. |
intelliSenseMode | {os}-{compiler}-{arch} 형식의 분석 모드. 생략하면 compilerPath를 보고 자동으로 정해집니다. |
cppStandard가 빌드와 다르면 엉뚱한 곳에 밑줄이 생깁니다. 예를 들어 C++20의 std::format을 쓰면서 c++17로 두면 빌드는 되는데 편집기에서는 에러로 표시됩니다. intelliSenseMode는 컴파일러와 맞지 않는 값을 적어 두면 오히려 오작동하므로, 확신이 없다면 비워 두는 편이 낫습니다.
compile_commands.json을 쓰는 것이 가장 정확하다
includePath와 defines를 손으로 맞추는 방식은 파일 몇 개짜리 실습에서는 충분하지만, 실제 프로젝트에서는 빌드 옵션과 금방 어긋납니다. 빌드 시스템이 모든 소스 파일의 실제 컴파일 명령을 기록한 compile_commands.json을 만들게 하고 편집기가 그것을 읽게 하면, IntelliSense가 빌드와 같은 옵션으로 코드를 해석합니다.
cmake -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
// .vscode/c_cpp_properties.json
{
"configurations": [
{
"name": "CMake",
"compileCommands": "${workspaceFolder}/build/compile_commands.json"
}
],
"version": 4
}
CMake Tools 확장을 쓴다면 "configurationProvider": "ms-vscode.cmake-tools"로 두면 선택한 kit과 프리셋의 설정을 확장이 직접 넘겨줍니다. Makefile 프로젝트라면 bear -- make로 같은 파일을 만들 수 있습니다. 빨간 밑줄 문제의 대부분은 “빌드는 A 옵션으로 하는데 IntelliSense는 B 옵션으로 해석하는” 불일치에서 오기 때문에, 이 방식으로 바꾸면 그런 문제 자체가 생기지 않습니다.
OS별 compilerPath와 intelliSenseMode
Windows (MSYS2 UCRT64의 GCC):
"compilerPath": "C:/msys64/ucrt64/bin/g++.exe",
"intelliSenseMode": "windows-gcc-x64"
macOS:
"compilerPath": "/usr/bin/clang++",
"intelliSenseMode": "macos-clang-arm64"
Intel 맥이라면 macos-clang-x64를 씁니다.
Windows (MSVC):
"compilerPath": "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/<버전>/bin/Hostx64/x64/cl.exe",
"intelliSenseMode": "windows-msvc-x64"
MSVC는 cl.exe 경로만 맞춘다고 끝나지 않습니다. cl.exe가 표준 헤더와 라이브러리를 찾으려면 INCLUDE, LIB 같은 환경 변수가 필요하고, 이 값은 Visual Studio의 개발자 명령 프롬프트(vcvars)가 설정합니다. 그래서 tasks.json에서 cl로 빌드하려면 “Developer PowerShell for VS”를 연 뒤 그 창에서 code .로 VS Code를 실행해야 합니다. 시작 메뉴에서 VS Code를 그냥 실행하면 'cl' is not recognized 또는 Cannot open include file: 'iostream' 에러가 납니다. CMake Tools 확장을 쓴다면 “Visual Studio Community 2022 Release - amd64” 같은 kit을 고르면 이 환경을 대신 잡아 줍니다.
여러 OS에서 같은 저장소를 연다면 구성을 나란히 적어 둘 수 있습니다.
{
"configurations": [
{
"name": "Linux",
"includePath": ["${workspaceFolder}/**"],
"compilerPath": "/usr/bin/g++",
"cppStandard": "c++17"
},
{
"name": "Mac",
"includePath": ["${workspaceFolder}/**"],
"compilerPath": "/usr/bin/clang++",
"cppStandard": "c++17"
},
{
"name": "Win32",
"includePath": ["${workspaceFolder}/**"],
"compilerPath": "C:/msys64/ucrt64/bin/g++.exe",
"cppStandard": "c++17"
}
],
"version": 4
}
다만 팀원마다 설치 경로가 다르면 절대 경로가 맞지 않으므로, 프로젝트가 어느 정도 커지면 위의 compile_commands.json 방식으로 넘어가는 편이 관리하기 쉽습니다.
Windows에서 WSL 안의 g++로 빌드하고 싶다면 “WSL” 확장(예전 이름 Remote - WSL)으로 WSL 쪽 폴더를 엽니다. 그러면 C/C++ 확장도 WSL 안에 설치되어 동작하므로, compilerPath에는 /usr/bin/g++ 같은 Linux 경로를 씁니다.
3단계: tasks.json으로 빌드 작업 만들기
tasks.json은 Ctrl+Shift+B(macOS: Cmd+Shift+B) 또는 메뉴의 Terminal → Run Build Task를 실행했을 때 돌아갈 명령을 정의합니다. .vscode/tasks.json을 만듭니다.
{
"version": "2.0.0",
"tasks": [
{
"label": "C++ Build",
"type": "shell",
"command": "g++",
"args": [
"-g",
"-std=c++17",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": ["$gcc"]
}
]
}
label은 이 작업의 이름이고, 뒤에서 launch.json이 이 이름으로 작업을 참조합니다. type이 shell이면 명령이 셸을 거쳐 실행되므로 *.cpp 같은 와일드카드가 확장되고, process면 셸 없이 바로 실행됩니다. -g는 디버그 정보를 넣는 옵션으로, 이것이 없으면 디버거에서 소스 줄과 변수 이름을 볼 수 없습니다. group.isDefault: true로 두면 이 작업이 기본 빌드 작업이 되어 단축키로 바로 실행됩니다. problemMatcher의 $gcc는 컴파일러 에러 출력을 해석해 Problems 패널과 편집기에 표시해 줍니다.
출력 경로 ${fileDirname}/${fileBasenameNoExtension}은 “현재 파일과 같은 폴더에, 확장자를 뺀 같은 이름으로” 실행 파일을 만든다는 뜻입니다. /home/user/project/main.cpp를 열고 빌드하면 /home/user/project/main이 생깁니다. 자주 쓰는 변수는 다음과 같습니다.
| 변수 | 설명 |
|---|---|
${workspaceFolder} | 작업 공간 루트 디렉토리 |
${file} | 현재 파일 전체 경로 |
${fileBasename} | 현재 파일 이름 (예: main.cpp) |
${fileBasenameNoExtension} | 확장자 없는 파일 이름 (예: main) |
${fileDirname} | 현재 파일의 디렉토리 |
${file}은 현재 열린 파일 하나만 컴파일합니다. main.cpp와 utils.cpp처럼 여러 소스 파일을 함께 빌드하는 방법은 아래 멀티파일 절에서 다루며, 파일이 늘어나면 CMake로 넘어가는 편이 관리하기 쉽습니다.
4단계: launch.json으로 디버거 연결하기
launch.json은 디버거가 어떤 실행 파일을 어떻게 실행할지 정의합니다. preLaunchTask로 빌드 작업을 연결하면 디버깅을 시작하기 전에 자동으로 빌드가 실행됩니다. .vscode/launch.json을 만듭니다.
{
"version": "0.2.0",
"configurations": [
{
"name": "C++ Debug",
"type": "cppdbg",
"request": "launch",
"program": "${fileDirname}/${fileBasenameNoExtension}",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "C++ Build",
"miDebuggerPath": "/usr/bin/gdb"
}
]
}
주요 필드:
| 필드 | 의미 |
|---|---|
type | cppdbg는 C/C++ 확장의 GDB/LLDB(MI) 디버거, cppvsdbg는 Visual Studio 디버거 엔진입니다. |
request | launch는 프로그램을 새로 실행하고, attach는 이미 실행 중인 프로세스에 붙습니다. |
program | 디버깅할 실행 파일. tasks.json의 출력 경로와 같아야 합니다. |
args | 프로그램에 넘길 명령줄 인자. 예: ["input.txt"] |
stopAtEntry | true면 main 진입 직후 멈춥니다. |
cwd | 프로그램의 작업 디렉토리. 상대 경로로 파일을 열 때 기준이 됩니다. |
externalConsole | false면 VS Code 내장 터미널을, true면 별도 콘솔 창을 씁니다. |
MIMode | gdb 또는 lldb |
miDebuggerPath | GDB 경로(which gdb로 확인). macOS의 LLDB에서는 생략합니다. |
preLaunchTask | 디버깅 전에 실행할 작업. tasks.json의 label과 한 글자도 다르지 않아야 합니다. |
OS별 디버거 설정
Windows (MSYS2 GCC):
"MIMode": "gdb",
"miDebuggerPath": "C:/msys64/ucrt64/bin/gdb.exe"
Windows에서는 program에 .exe를 붙인 경로를 적습니다.
macOS:
"MIMode": "lldb"
macOS에서는 miDebuggerPath를 지정하지 않습니다. /usr/bin/lldb는 MI 프로토콜을 말하지 않는 일반 lldb라 여기에 넣으면 디버거가 시작되지 않으며, C/C++ 확장이 macOS용 lldb-mi를 자체적으로 포함하고 있으므로 MIMode만 lldb로 바꾸면 됩니다. 다만 cppdbg의 LLDB 연동은 MI 계층을 한 번 거치기 때문에 STL 컨테이너 값이 제대로 안 보이거나 단계 실행이 느린 경우가 있습니다. 그럴 때는 CodeLLDB 확장("type": "lldb")이나 LLVM이 배포하는 LLDB DAP 확장("type": "lldb-dap")으로 바꾸는 것을 권합니다. 둘 다 LLDB를 직접 쓰기 때문에 macOS에서 차이가 큽니다.
{
"name": "Debug (CodeLLDB)",
"type": "lldb",
"request": "launch",
"program": "${fileDirname}/${fileBasenameNoExtension}",
"cwd": "${fileDirname}",
"preLaunchTask": "C++ Build"
}
Windows (MSVC): MSVC로 빌드한 실행 파일은 GDB가 아니라 Visual Studio 디버거 엔진을 쓰는 "type": "cppvsdbg"로 디버깅합니다. 이 디버거는 MSVC가 만드는 PDB 디버그 정보를 읽으므로, 앞에서 만든 g++ 작업(C++ Build)의 결과물로는 브레이크포인트가 걸리지 않습니다. 빌드 작업도 cl.exe용으로 따로 둡니다.
// tasks.json에 추가
{
"label": "C++ Build (MSVC)",
"type": "shell",
"command": "cl.exe",
"args": [
"/Zi", "/EHsc", "/std:c++17", "/nologo",
"/Fe${fileDirname}\\${fileBasenameNoExtension}.exe",
"${file}"
],
"group": "build",
"problemMatcher": ["$msCompile"]
}
/Zi가 PDB를 만들고, /EHsc는 표준 C++ 예외 처리를 켭니다. cl.exe는 일반 터미널의 PATH에 없으므로, “Developer PowerShell for VS 2022”(또는 Developer Command Prompt)에서 code .로 VS Code를 열어야 이 작업이 컴파일러를 찾습니다. 시작 메뉴에서 그냥 연 VS Code에서는 'cl.exe' is not recognized 에러가 납니다.
{
"name": "Debug (MSVC)",
"type": "cppvsdbg",
"request": "launch",
"program": "${fileDirname}/${fileBasenameNoExtension}.exe",
"cwd": "${fileDirname}",
"console": "integratedTerminal",
"preLaunchTask": "C++ Build (MSVC)"
}
디버깅 실행
줄 번호 왼쪽을 클릭해 브레이크포인트를 걸고 F5(Run → Start Debugging)를 누릅니다. 디버깅 중에 쓰는 단축키:
| 단축키 | 동작 |
|---|---|
F5 | 디버깅 시작/계속 |
F10 | Step Over (다음 줄) |
F11 | Step Into (함수 안으로) |
Shift+F11 | Step Out (함수 밖으로) |
Shift+F5 | 디버깅 중지 |
브레이크포인트를 우클릭해 “Edit Breakpoint”에서 i == 5 같은 조건을 넣으면, 반복문에서 특정 반복에서만 멈추게 할 수 있습니다. GDB/LLDB 자체의 사용법은 GDB/LLDB 디버거 기초에서 다룹니다.
자주 만나는 오류와 해결
빌드는 되는데 표준 헤더에 빨간 밑줄이 나온다
c_cpp_properties.json의 compilerPath가 비어 있거나 터미널에서 쓰는 컴파일러와 다른 경우입니다. 터미널에서 which g++(또는 which clang++, Windows는 where g++)로 경로를 확인해 compilerPath에 그대로 넣습니다. intelliSenseMode를 적어 두었다면 컴파일러와 맞는지도 확인합니다. Linux의 GCC는 linux-gcc-x64, Linux의 Clang은 linux-clang-x64, Apple Silicon 맥의 Clang은 macos-clang-arm64입니다.
설정을 고쳤는데도 밑줄이 남아 있으면 명령 팔레트에서 “C/C++: Reset IntelliSense Database”를 실행하거나 “Developer: Reload Window”로 창을 다시 엽니다. “C/C++: Log Diagnostics”를 실행하면 확장이 실제로 사용한 컴파일러와 include 경로가 출력되어, 어느 설정이 적용됐는지 확인할 수 있습니다.
프로젝트 안의 헤더를 찾지 못한다
#include "myheader.h"에 밑줄이 생기면 그 헤더가 있는 폴더가 includePath에 없는 것입니다. 외부 라이브러리를 쓴다면 해당 include 경로를 추가합니다.
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/external/boost",
"/usr/local/include"
]
includePath는 IntelliSense만을 위한 설정이라는 점에 주의해야 합니다. 빌드에도 같은 경로가 필요하면 tasks.json의 args에 -I 옵션을 따로 넣어야 합니다. 이렇게 두 곳을 맞춰야 하는 번거로움이 compile_commands.json을 권하는 이유입니다.
”Could not find the task ‘C++ Build’”
F5를 누를 때 이 메시지가 나오면 launch.json의 preLaunchTask 값이 tasks.json의 label과 다른 것입니다. 대소문자나 공백 하나만 달라도 실패합니다.
// tasks.json
"label": "C++ Build"
// launch.json
"preLaunchTask": "C++ Build"
macOS에서 “Unable to find debugger” 또는 LLDB 오류
Xcode Command Line Tools가 설치되지 않았거나, launch.json이 MIMode: "gdb"로 되어 있는 경우가 대부분입니다. xcode-select --install로 도구를 설치하고, MIMode를 lldb로 바꾸고 miDebuggerPath는 지웁니다. 그래도 안 되면 위에서 설명한 CodeLLDB나 LLDB DAP로 바꿉니다.
Windows에서 g++ 또는 gdb를 찾지 못한다
MinGW/MSYS2의 bin 폴더가 PATH에 없는 경우입니다.
- MSYS2를 설치한 뒤 UCRT64 셸에서
pacman -S mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-gdb로 설치합니다. MSYS2는 최신 Windows에서 UCRT64 환경을 권장합니다. 예전 글에 나오는mingw64환경도 동작하지만, 두 환경의 컴파일러와 디버거를 섞으면 안 됩니다. - 시스템 환경 변수 PATH에
C:\msys64\ucrt64\bin을 추가하고 VS Code를 완전히 종료했다가 다시 실행합니다. 열려 있던 VS Code는 예전 PATH를 계속 씁니다. - PATH를 건드리고 싶지 않다면
tasks.json과launch.json에 전체 경로를 적습니다.
"command": "C:/msys64/ucrt64/bin/g++.exe",
"miDebuggerPath": "C:/msys64/ucrt64/bin/gdb.exe"
빌드한 .exe를 탐색기에서 더블클릭하면 libstdc++-6.dll을 찾을 수 없습니다가 나오는 경우가 있습니다. MinGW 런타임 DLL이 PATH에 없어서인데, VS Code 터미널에서는 PATH가 잡혀 있어 문제가 드러나지 않습니다. 다른 PC에 배포할 실행 파일이라면 -static 또는 -static-libstdc++ -static-libgcc로 링크하세요.
C++20 기능(std::format 등)에 빨간 밑줄
cppStandard가 c++17 이하이거나, 컴파일러 자체가 그 기능을 아직 지원하지 않는 경우입니다. std::format은 GCC 13, Clang 17(libc++) 이상에서 쓸 수 있으므로, 오래된 배포판의 기본 컴파일러에서는 표준을 c++20으로 바꿔도 헤더가 없습니다. 컴파일러 버전을 확인한 뒤 c_cpp_properties.json의 "cppStandard": "c++20"과 tasks.json의 "-std=c++20"을 함께 맞춥니다.
”undefined reference to” 링크 에러
컴파일은 되는데 링크에서 실패한다면, 헤더만 include하고 그 구현이 들어 있는 .cpp를 빌드에 넣지 않았거나 필요한 라이브러리를 -l로 지정하지 않은 경우입니다. 기본 tasks.json은 현재 파일 하나만 컴파일하므로, 같은 폴더의 .cpp를 모두 넣으려면 와일드카드를 씁니다.
// "type": "shell"이어야 셸이 *를 확장합니다
"args": [
"-g", "-std=c++17",
"${fileDirname}/*.cpp",
"-o", "${fileDirname}/app"
]
라이브러리는 소스 파일 뒤에 -lpthread, -lm처럼 붙입니다. GNU ld는 왼쪽에서 오른쪽으로 심볼을 해석하므로 -l 옵션을 소스 파일보다 앞에 두면 같은 에러가 납니다.
IntelliSense가 느리거나 멈춘다
큰 프로젝트에서 includePath에 ${workspaceFolder}/**를 두면 빌드 산출물과 서드파티 폴더까지 모두 훑게 됩니다. "${workspaceFolder}/src", "${workspaceFolder}/include"처럼 필요한 경로만 지정하고, C_Cpp.files.exclude와 files.watcherExclude에 build/, third_party/ 같은 폴더를 넣습니다. CMake 프로젝트라면 compile_commands.json을 쓰게 하는 것이 가장 효과적이고, 그래도 느리면 아래의 clangd를 검토합니다.
디버거에서 변수 값이 “optimized out”으로 나온다
-O2, -O3로 빌드하면 컴파일러가 변수를 레지스터에만 두거나 아예 없애기 때문에 디버거가 값을 보여 줄 수 없습니다. 디버그용 작업에서는 -O0 -g(GCC에서는 디버깅 경험을 해치지 않는 최적화만 하는 -Og도 선택지입니다)로 빌드합니다.
Windows에서 한글 경로 문제
MinGW의 GCC·GDB와 일부 도구는 Windows의 시스템 코드 페이지(한국어 Windows는 CP949)로 경로를 해석하기 때문에, 경로에 한글이 있으면 빌드나 디버깅이 실패할 수 있습니다. 사용자 이름이 한글이라 C:\Users\홍길동\ 아래에서 작업할 때 특히 흔합니다. 가장 확실한 해결책은 프로젝트를 C:\dev\project 같은 영문 경로에 두는 것입니다. 소스 안의 한글 문자열이 깨지는 것은 별개 문제로, MSVC는 /utf-8 옵션, 콘솔 출력은 chcp 65001이나 Windows Terminal로 해결합니다. 인코딩 전반은 문자 인코딩 글에 정리했습니다.
main·utils로 나눈 멀티파일 프로젝트 빌드
myproject/
├── .vscode/
│ ├── c_cpp_properties.json
│ ├── tasks.json
│ └── launch.json
├── main.cpp
├── utils.h
└── utils.cpp
// main.cpp
#include <iostream>
#include "utils.h"
int main() {
int result = add(5, 3);
std::cout << "5 + 3 = " << result << '\n';
return 0;
}
// utils.h
#pragma once
int add(int a, int b);
// utils.cpp
#include "utils.h"
int add(int a, int b) {
return a + b;
}
tasks.json에 파일 목록을 명시한 작업을 하나 더 만듭니다. options.cwd를 ${workspaceFolder}로 두면 어느 파일을 열고 있든 프로젝트 루트에서 빌드됩니다.
{
"label": "C++ Build Multi-File",
"type": "shell",
"command": "g++",
"args": [
"-g",
"-std=c++17",
"main.cpp",
"utils.cpp",
"-o",
"myapp"
],
"group": "build",
"options": {
"cwd": "${workspaceFolder}"
},
"problemMatcher": ["$gcc"]
}
launch.json에서는 실행 파일 경로와 빌드 작업 이름을 이에 맞춥니다.
"program": "${workspaceFolder}/myapp",
"preLaunchTask": "C++ Build Multi-File"
같은 방식으로 Debug용(-O0 -g)과 Release용(-O2 -DNDEBUG) 작업을 나눠 둘 수도 있습니다. 작업에 "presentation": { "reveal": "silent" }를 추가하면 빌드가 정상적으로 끝났을 때는 터미널 패널이 앞으로 나오지 않습니다.
CMake 프로젝트와 연동
프로젝트가 커지면 CMake를 쓰는 편이 좋습니다. CMake Tools 확장을 설치하면 tasks.json과 launch.json 없이도 확장의 명령으로 구성, 빌드, 디버깅을 할 수 있습니다. 명령 팔레트에서 “CMake: Configure”를 실행해 kit(컴파일러)을 고른 뒤, F7로 빌드하고 Ctrl+F5(“CMake: Debug”)로 선택한 타깃을 디버깅합니다. 이때 C/C++ 확장의 configurationProvider를 CMake Tools로 지정해 두면 IntelliSense도 CMake 설정을 그대로 따릅니다. 빌드 설정을 팀과 공유하는 방법은 CMakePresets.json 글에서 다룹니다.
clangd로 바꾸기, 그리고 VS Code 기반 다른 편집기
clangd
clangd는 LLVM이 만드는 C++ 언어 서버입니다. compile_commands.json을 읽어 파일마다 정확한 옵션으로 분석하고, 백그라운드 인덱스로 큰 프로젝트에서도 탐색이 빠르며, clang-tidy 경고를 편집기에서 바로 보여 줍니다. VS Code에서는 “clangd” 확장(llvm-vs-code-extensions.vscode-clangd)을 설치하면 되는데, Microsoft C/C++ 확장의 IntelliSense와 동시에 켜면 자동 완성과 오류 표시가 두 번씩 나옵니다. clangd 확장이 처음 실행될 때 Microsoft 쪽 IntelliSense를 끌지 물어보며, 직접 설정한다면 이렇게 둡니다.
// .vscode/settings.json
{
"C_Cpp.intelliSenseEngine": "disabled",
"clangd.arguments": [
"--compile-commands-dir=${workspaceFolder}/build",
"--background-index",
"--clang-tidy",
"--header-insertion=never"
]
}
이렇게 하면 Microsoft 확장은 디버거(cppdbg, cppvsdbg) 용도로만 남습니다. clangd가 표준 헤더를 못 찾는다면 GCC로 빌드하는 프로젝트에서 clangd가 GCC의 헤더 위치를 모르는 경우입니다. --query-driver=/usr/bin/g++*를 추가하면 clangd가 해당 컴파일러에게 헤더 경로를 물어봅니다.
Cursor, VSCodium 등에서 C/C++ 확장이 안 될 때
Microsoft의 C/C++ 확장은 라이선스상 Microsoft의 VS Code 제품에서만 쓰도록 되어 있고, 2025년부터는 확장이 실행 환경을 확인해 Cursor, VSCodium 같은 다른 VS Code 기반 편집기에서 동작을 막기 시작했습니다. 이런 편집기에서 Microsoft 제품에서만 쓸 수 있다는 메시지와 함께 IntelliSense와 디버깅이 멈췄다면 이것이 원인입니다. 대안은 clangd(코드 분석)와 CodeLLDB 또는 LLDB DAP(디버깅)의 조합이고, Windows의 MSVC 디버깅(cppvsdbg)처럼 대체가 어려운 부분은 VS Code 본체나 Visual Studio를 병행해야 합니다.
함께 쓰는 확장
| 확장 | 용도 |
|---|---|
| C/C++ (Microsoft) | IntelliSense, cppdbg/cppvsdbg 디버깅 |
| CMake Tools | CMake 프로젝트 구성·빌드·디버깅 |
| clangd | 대안 IntelliSense. 켜면 Microsoft 확장의 IntelliSense는 꺼 둡니다. |
| CodeLLDB / LLDB DAP | LLDB를 직접 쓰는 디버거. Microsoft 확장 없이도 동작합니다. |
팀원이 저장소를 열었을 때 필요한 확장을 추천받도록 .vscode/extensions.json을 둘 수 있습니다.
{
"recommendations": [
"ms-vscode.cpptools",
"ms-vscode.cmake-tools"
]
}
편집할 때 쓰는 단축키
| 단축키 (Windows/Linux) | 동작 |
|---|---|
Ctrl+Shift+P | 명령 팔레트 |
Ctrl+P | 파일 빠른 열기. @를 입력하면 현재 파일의 심볼, #를 입력하면 워크스페이스 전체 심볼을 검색합니다. |
F12 | 정의로 이동 |
F2 | 심볼 이름 변경 |
Ctrl+Space | 자동 완성 목록 강제 표시 (macOS도 Ctrl+Space) |
Ctrl+D | 같은 단어를 하나씩 추가 선택 |
Ctrl+Shift+L | 선택한 단어가 나오는 곳 전체 선택 |
Alt+클릭 | 커서 추가 (macOS: Option+클릭) |
macOS에서는 표의 Ctrl을 대부분 Cmd로 바꾸면 되지만, 자동 완성 표시는 Cmd+Space가 Spotlight와 겹치기 때문에 Ctrl+Space 그대로입니다.
.vscode 폴더 공유와 CI
tasks.json, launch.json, extensions.json은 Git에 커밋해 팀이 같은 설정을 쓰게 하는 편이 좋습니다. 개인 취향 설정은 저장소의 .vscode/settings.json이 아니라 사용자 설정에 두고, 개인 PC의 절대 경로가 들어가는 값은 커밋하지 않도록 주의합니다.
tasks.json의 빌드 명령과 CI의 빌드 명령을 같게 유지하면 “로컬에서는 되는데 CI에서는 안 된다”는 문제를 줄일 수 있습니다. 예를 들어 GitHub Actions에서 같은 옵션으로 빌드한다면 다음과 같습니다.
# .github/workflows/build.yml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
run: g++ -std=c++17 -Wall -Wextra -O2 main.cpp utils.cpp -o myapp
소스 파일이 많아져 목록을 손으로 관리하기 어려워지면, 빌드 정의를 CMake로 옮기고 로컬(CMake Tools)과 CI가 모두 그 정의를 쓰게 하는 것이 다음 단계입니다. 그 내용은 다음 글인 CMake 입문(#4)에서 이어집니다.