본문으로 건너뛰기

안동민 개발노트

본문 시작

개발 환경 설정

에디터·컴파일러·링커의 역할을 이해하고 VS Code에서 C++ 소스를 빌드하고 실행하는 개발 환경을 단계별로 구성합니다.

앞 절에서 C++이 어떤 언어인지, 그리고 어디에 활용되는지 개괄적으로 살펴봤습니다.

이제는 C++ 코드를 직접 작성하고 실행하기 위한 준비 단계로 넘어가겠습니다.

건축가가 건물을 짓기 위해 설계 도구와 자재를 준비하듯이, 프로그래머도 코드를 작성하기 위한 적절한 도구와 환경이 필요합니다.

이 장에서는 C++ 개발에 필요한 핵심 도구를 정리하고, 컴퓨터에 개발 환경을 설정하는 과정을 단계별로 안내합니다.

먼저 전체 흐름을 보면, C++ 개발 환경은 코드를 쓰는 도구와 실행 파일을 만드는 도구를 하나의 경로로 연결하는 작업입니다.

g++ 컴파일러 드라이버가 전처리, 컴파일과 어셈블, 링크를 조정해 실행 파일을 만들고 운영체제가 그 파일을 실행하는 흐름

BUILD PIPELINE

한 번의 g++ 명령 안에서도 번역과 링크는 구별되며, 실행은 빌드가 끝난 뒤의 별도 단계입니다.

C++ 소스에서 Windows 실행 파일까지의 빌드와 실행 흐름 g++ 드라이버가 main.cpp를 전처리하고, 컴파일과 어셈블로 목적 코드를 만든 뒤, 목적 코드와 C++ 라이브러리를 링크해 hello.exe를 생성한다. PowerShell에서 hello.exe를 실행하면 Windows가 프로그램을 적재한다. g++ -std=c++20 main.cpp -o hello.exe 앞의 세 빌드 단계를 조정 전처리 main.cpp + header macro · #include 처리 컴파일 · 어셈블 C++ → 목적 코드 -c로 목적 파일에서 중지 링크 목적 코드 + 라이브러리 hello.exe 생성 실행 Windows가 프로그램 적재 .\hello.exe 빌드 실행
g++ driver 빌드와 실행의 경계를 나누어 읽습니다.
  1. 전처리

    #include와 매크로를 처리해 컴파일할 번역 단위를 준비합니다.

  2. 컴파일과 어셈블

    C++를 목적 코드로 바꿉니다. -c를 쓰면 링크하지 않고 목적 파일에서 멈출 수 있습니다.

  3. 링크

    목적 코드와 필요한 C++ 라이브러리를 연결해 hello.exe를 만듭니다.

  4. 실행

    PowerShell의 .\hello.exe가 빌드 결과를 시작하고 Windows가 프로그램을 적재합니다.

g++ main.cpp -o hello.exe처럼 한 번에 링크하면 목적 파일이 별도 파일로 남지 않을 수 있지만, 번역과 링크의 책임은 여전히 구분됩니다.

C++ 개발을 위한 핵심 도구들

C++ 코드를 작성하고 실행하려면 다음 역할을 맡는 도구가 필요합니다.

  • 텍스트 에디터(Text Editor): 소스 코드를 작성하고 탐색합니다. 문법 강조와 자동 완성 같은 편집 기능을 제공할 수 있습니다.
  • 컴파일러 도구 모음(Compiler Toolchain): 전처리, 컴파일, 어셈블 단계를 거쳐 소스를 목적 코드로 바꿉니다. g++ 같은 컴파일러 드라이버는 이 단계들과 링커 호출을 한 명령으로 조정할 수 있습니다.
  • 링커(Linker): 목적 코드와 필요한 라이브러리를 연결해 실행 파일을 만듭니다.
  • 디버거(Debugger): 실행 중인 프로그램을 멈추고 호출 흐름과 변수 값을 관찰합니다.

통합 개발 환경(IDE)은 이런 도구를 한 화면에서 호출하고 결과를 연결해 줍니다. 다만 IDE나 에디터 자체가 언제나 컴파일러를 포함하는 것은 아니므로, 사용하는 편집기와 별도로 툴체인을 설치해야 할 수 있습니다.


C++ 컴파일러 소개

C++ 소스는 전처리, 컴파일, 어셈블을 거쳐 목적 코드가 되고, 링크 단계에서 라이브러리와 결합해 실행 파일이 됩니다. 컴파일러 드라이버는 이 도구들을 순서대로 호출합니다.

주요 C++ 컴파일러는 다음과 같습니다.

  • GCC: GNU Compiler Collection의 C++ 드라이버는 g++입니다. 이 문서의 Windows 실습에서는 MSYS2가 제공하는 MinGW-w64 빌드를 사용합니다. 예: g++ myprogram.cpp -o myprogram.exe
  • Clang: LLVM 프로젝트의 C++ 컴파일러 드라이버는 clang++입니다. 예: clang++ myprogram.cpp -o myprogram
  • MSVC: Microsoft의 C++ 컴파일러 드라이버는 cl이며 Visual Studio 또는 Build Tools와 함께 설치할 수 있습니다. 예: cl myprogram.cpp

프로젝트의 대상 운영체제, 사용하는 라이브러리와 빌드 시스템, 팀의 배포 환경에 맞는 툴체인을 선택하고 공식 문서의 지원 범위를 확인합니다.


통합 개발 환경 (IDE) 소개

IDE는 코드 편집, 컴파일, 디버깅 등의 기능을 통합적으로 제공하는 소프트웨어입니다.

도구의 예로는 MSVC 툴체인을 연결하는 Visual Studio, 외부 툴체인과 확장을 조합하는 Visual Studio Code, CMake 등의 빌드 시스템과 통합하는 CLionEclipse CDT가 있습니다.

제품 이름만으로 우열을 정하기보다 대상 플랫폼, 필요한 디버거와 빌드 시스템, 라이선스 조건을 각 공식 문서에서 확인해 선택합니다. 아래 실습은 도구 사이의 연결을 직접 확인하기 쉬운 VS Code와 MSYS2의 UCRT64 툴체인을 사용합니다.


개발 환경 설정 단계(VS Code)

Visual Studio Code 설치Visual Studio Code 설치 프로그램의 추가 작업 선택 화면
C/C++ 확장 설치VS Code 확장 탭에서 Microsoft C++ 확장을 검색한 화면
  • VS Code에서 확장(Extensions) 보기를 엽니다.
  • C/C++를 검색해 Microsoft의 ms-vscode.cpptools 확장을 설치합니다. 이 확장은 편집·IntelliSense·디버깅 기능을 제공하지만 컴파일러 자체를 설치하지는 않습니다.
MSYS2와 MinGW-w64 툴체인 설치(Windows)
  • 이 실습의 명령과 설정은 x86_64 PC의 64비트 Windows 10 1809 이상 또는 Windows 11에서 UCRT64 환경을 사용하는 경우를 기준으로 합니다. Windows 11 ARM64의 MSYS2 지원은 별도 CLANGARM64 환경과 패키지를 사용하는 예비 지원 단계이므로 MSYS2 ARM64 안내를 따릅니다.
  • MSYS2 공식 설치 페이지에서 최신 GUI 설치 프로그램을 내려받고 안내에 따라 설치합니다. 고정된 과거 버전 URL은 사용하지 않습니다.
  • 설치가 끝나면 MSYS2 UCRT64 터미널을 열고 아래 명령으로 x86_64 UCRT64 툴체인을 설치합니다.
pacman -S --needed base-devel mingw-w64-ucrt-x86_64-toolchain
MSYS2에서 UCRT64 툴체인 그룹의 기본 전체 선택을 묻는 화면
  • 그룹 구성과 패키지 개수는 갱신될 수 있습니다. Enter a selection (default=all) 프롬프트에서는 Enter를 눌러 현재 그룹의 기본 전체 선택을 수락합니다.
MSYS2가 설치할 패키지와 용량을 요약하고 진행 여부를 묻는 화면
  • 거래 요약 뒤 Proceed with installation? [Y/n] 프롬프트에서는 Y 또는 Enter를 눌러 설치를 진행합니다. 스크린샷의 버전과 개수보다 현재 터미널 출력과 공식 패키지 그룹을 기준으로 확인합니다.
환경 변수 설정
  • 사용자 환경 변수의 Path에 UCRT64의 bin 폴더를 추가합니다.
기본값으로 설치했을 경우 경로
C:\msys64\ucrt64\bin
  • 다른 설치 폴더를 선택했다면 이 Path뿐 아니라 아래 예제의 compilerPath, build task의 command, miDebuggerPath에 있는 C:\msys64 또는 C:/msys64도 실제 설치 루트로 모두 바꿉니다.
  • 열려 있던 터미널을 닫고 새 터미널에서 설치 결과를 확인합니다.
gcc --version
g++ --version
gdb --version
프로젝트 폴더 생성 및 설정
  • 새 폴더 생성 후 VS Code로 열기
  • .vscode 폴더에 c_cpp_properties.json, tasks.json, launch.json을 만듭니다. 아래 예제는 현재 활성 소스 파일 하나를 같은 폴더의 같은 이름 .exe로 빌드하고 디버그합니다.
c_cpp_properties.json
{
  "configurations": [
    {
      "name": "GCC",
      "includePath": ["${workspaceFolder}/**"],
      "compilerPath": "C:/msys64/ucrt64/bin/g++.exe",
      "cStandard": "c17",
      "cppStandard": "c++20",
      "intelliSenseMode": "windows-gcc-x64"
    }
  ],
  "version": 4
}
tasks.json
{
  "tasks": [
    {
      "type": "cppbuild",
      "label": "C/C++: g++.exe 활성 파일 빌드",
      "command": "C:\\msys64\\ucrt64\\bin\\g++.exe",
      "args": [
        "-fdiagnostics-color=always",
        "-std=c++20",
        "-Wall",
        "-Wextra",
        "-g",
        "${file}",
        "-o",
        "${fileDirname}\\${fileBasenameNoExtension}.exe"
      ],
      "options": {
        "cwd": "${fileDirname}"
      },
      "problemMatcher": ["$gcc"],
      "group": {
        "kind": "build",
        "isDefault": true
      },
      "detail": "디버거에서 생성된 작업입니다."
    }
  ],
  "version": "2.0.0"
}
launch.json
{
  "configurations": [
    {
      "name": "C/C++: g++.exe 활성 파일 빌드 및 디버그",
      "type": "cppdbg",
      "request": "launch",
      "program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
      "args": [],
      "stopAtEntry": false,
      "cwd": "${fileDirname}",
      "environment": [],
      "externalConsole": false,
      "MIMode": "gdb",
      "miDebuggerPath": "C:/msys64/ucrt64/bin/gdb.exe",
      "setupCommands": [
        {
          "description": "gdb에 자동 서식 지정 사용",
          "text": "-enable-pretty-printing",
          "ignoreFailures": true
        },
        {
          "description": "디스어셈블리 버전을 Intel(으)로 설정",
          "text": "-gdb-set disassembly-flavor intel",
          "ignoreFailures": true
        }
      ],
      "preLaunchTask": "C/C++: g++.exe 활성 파일 빌드"
    }
  ],
  "version": "0.2.0"
}

세 파일의 version은 같은 값을 공유하는 앱 버전이 아니라 서로 다른 설정 스키마 버전입니다. C/C++ 설정 명세, 작업 스키마, 디버그 구성 명세에 따라 이 예제에서는 c_cpp_properties.json이 숫자 4, tasks.json이 문자열 2.0.0, launch.json이 문자열 0.2.0을 사용합니다.

c_cpp_properties.json은 IntelliSense가 참고할 컴파일러와 표준을 정하고, 실제 빌드 명령은 tasks.json이 실행합니다. launch.json은 그 빌드 결과를 GDB로 시작합니다. 따라서 compilerPath와 build task의 command, cppStandard-std 인수, task의 -o 출력과 program, task labelpreLaunchTask를 각각 짝으로 맞춥니다. includePath는 IntelliSense 검색 범위일 뿐 GCC의 include 경로를 바꾸지 않으므로, 소스 상대 경로나 시스템 경로 밖의 헤더를 쓴다면 build task에도 대응하는 -I 인수를 추가하거나 빌드 시스템에서 함께 관리합니다.

VS Code의 공식 MinGW 안내에 따라 작업 폴더의 *.cpp 와일드카드를 컴파일러 인수로 직접 넘기지 않았습니다. 2024년 11월 3일부터 MSYS2 mingw-w64 프로그램은 와일드카드 인수 확장을 기본으로 비활성화했으므로, tasks.jsonargs${workspaceFolder}/*.cpp를 직접 넣어도 Bash의 glob 확장처럼 동작하지 않습니다. 파일이 여러 개인 프로젝트는 소스를 명시적으로 나열하거나 CMake·Make 같은 빌드 시스템으로 전환합니다.

c_cpp_properties.json은 편집 지원, tasks.json은 실제 빌드, launch.json은 디버그 시작을 담당하며 컴파일러와 실행 파일 경로를 서로 맞춰야 한다는 설정 계약

CONFIG CONTRACT

세 JSON 파일은 같은 일을 반복하지 않습니다. 각 파일의 책임과 서로 맞아야 하는 값만 구분합니다.

VS Code C++ 설정 파일별 책임과 연결 지점
파일 결정하는 것 일치시킬 값
c_cpp_properties.json IntelliSense가 참고할 컴파일러, include 경로, C++ 표준 compilerPathcppStandard를 실제 빌드 조건에 맞춤
tasks.json g++에 전달할 소스·옵션·출력 경로 command는 같은 툴체인, 출력 경로는 디버그 대상과 같아야 함
launch.json GDB가 시작할 프로그램과 작업 폴더 program은 빌드 출력, preLaunchTask는 task의 label과 정확히 일치
c_cpp_properties.json
책임 IntelliSense의 컴파일러·include 경로·C++ 표준
계약 compilerPathcppStandard를 실제 빌드 조건에 맞춥니다.
tasks.json
책임 실제 g++ 명령, 소스, 옵션, 출력 경로
계약 출력 실행 파일이 launch.jsonprogram과 같아야 합니다.
launch.json
책임 GDB로 시작할 프로그램과 작업 폴더
계약 preLaunchTask가 task의 label과 정확히 같아야 합니다.
IntelliSense가 정상이어도 빌드 명령은 실패할 수 있습니다. 편집 지원과 실제 빌드는 서로 다른 설정 경로입니다.

첫 번째 프로그램 작성 및 실행

새 파일 생성 (main.cpp)
main.cpp
#include <iostream>

int main() {
    std::cout << "Hello, C++ World!" << std::endl;
    return 0;
}
파일 저장 후 터미널에서 다음 명령어 실행
g++ -std=c++20 -Wall -Wextra -g main.cpp -o hello.exe
.\hello.exe

첫 프로그램이 바로 실행되지 않을 때는 IDE 설정을 무작정 바꾸기보다, 저장된 소스 파일, 컴파일러 호출, 링커 단계, 실행 파일 위치를 순서대로 나누어 확인하는 편이 빠릅니다.

실패 단계만 분리해도 고칠 파일과 설정 범위가 크게 줄어듭니다.

명령을 찾지 못함, 컴파일 오류, 링크 오류, 실행 파일 불일치, 런타임 문제를 각각 설치와 Path, 번역, 링크, 실행 시작, 실행 중 단계로 좁히는 진단표

FIRST-ERROR TRIAGE

설정을 모두 바꾸기 전에 첫 오류 메시지가 어느 경계에서 나왔는지 확인합니다.

Hello World 빌드·실행 증상별 첫 확인 지점
보이는 증상 멈춘 단계 먼저 확인할 것
g++ 또는 gdb를 찾을 수 없음 설치 · Path 새 터미널에서 버전 명령을 실행하고 C:\msys64\ucrt64\bin을 확인
error: expected ... 또는 header를 찾지 못함 전처리 · 컴파일 첫 진단에 따라 저장된 파일의 문법 또는 #include 이름·검색 경로를 확인
undefined reference 또는 cannot find -l... 링크 함수 정의가 든 목적 파일, 라이브러리 이름·경로·명령 인수 순서를 확인
빌드됐지만 실행 파일을 찾지 못함 실행 시작 tasks.json-olaunch.jsonprogram을 대조
실행되지만 출력이나 동작이 예상과 다름 실행 중 현재 작업 폴더, 입력값, 중단점과 변수 값을 확인
명령을 찾을 수 없음
단계 설치 · Path
확인 새 터미널에서 g++ --versiongdb --version을 실행합니다.
컴파일 · header 진단
단계 전처리 · 컴파일
확인 첫 진단에 따라 문법 또는 #include 이름·검색 경로를 봅니다.
링크 진단
단계 링크
확인 누락된 정의·목적 파일·라이브러리와 명령 인수 순서를 봅니다.
실행 파일을 찾지 못함
단계 실행 시작
확인 build의 출력 경로와 debug의 program 경로를 맞춥니다.
출력이나 동작이 예상과 다름
단계 실행 중
확인 작업 폴더·입력값·중단점·변수 값을 확인합니다.
여러 진단이 이어지면 가장 먼저 출력된 오류부터 해결합니다. 뒤의 메시지는 앞선 실패가 만든 연쇄 증상일 수 있습니다.

첫 환경 설정의 목표는 많은 설정 파일을 외우는 것이 아니라, 저장한 main.cpp가 컴파일러와 링커를 거쳐 실행 파일로 만들어지는 경로를 직접 확인하는 것입니다.