Tags: , , , ,

Categories:

5 minute read

Windows VSCode C++ 문제풀이 설정


이것 때문에 정말 오랫동안 싸워왔고, 일부 성공한 상태로만 1년을 사용했다. vscode는 기본적으로 코드 편집기이고 자체적으로 빌드하는 기능은 제공하지 않는다. vscode의 동작 방식은 동작 코드 -> 실행 엔진에 전달 -> [실행 엔진] -> 실행 엔진 결과물 확인 -> 동작 결과 사용자에게 전달이다. 여기서 실행 엔진들이 우리가 알고 있는 GCC 컴파일러, Python 인터프리터, JVM과 같은 것들이다. 익스텐션에서 볼 수 있는 C/C++, Python, Java와 같은 것들은 사실, 실행 엔진단계에서 사용되는 것들이 아닌 실행 엔진에 전달에 대한 설정을 담당하고, 실행 엔진 결과물 확인동작 결과 사용자에게 전달 과정을 돕는 역할을 수행한다. 그리고 사용자는 실행 엔진을 제외하면 많은 부분을 커스텀할 수 있다.

이러한 vscode의 성질은 이를 매우 자유롭게 만든다. 하지만 반대로 초심자에게 절망을 선사한다. 터미널을 기본적으로 다룰 줄 알아야만 json 설정들의 키워드를 어느정도 이해하고, 지레 짐작이라도 할 수 있기 때문이다.

준비물

모든 설정을 완료하기 위해서는 bash터미널이 필요하다. bash터미널은 리눅스에서 사용하는 터미널로, 이것저것 편의 기능이 내장되어 있다. 구글에 git을 치고, 이를 다운받으면 git bash가 자동으로 설치된다. git은 개발자들에게도 필수적인 기능이므로 설치하는데 거부감을 가질 필요는 없다. 어차피 언젠가는 설치하게 된다.

GCC 컴파일러

문제풀이를 위한 컴파일러는 단연 gcc를 추천한다. 따라서 이번 설정에도 GCC 컴파일러를 다운받아 설정할 것이다.

GCC 컴파일러는 winlibs에서 다운로드 가능하다. 아래 UCRT runtime 메뉴에서 원하는 버전의 GCC 컴파일러를 다운로드하자. 오직 문제풀이만을 위해서라면 사실 크게 버전은 중요하지 않으므로, 아무거나 해도 무방하다. 나는 12.2.0버전을 다운로드 했다. (without LLVM/Clang/LLD/LLDB 버전을 다운로드해도 크게 상관은 없을 것이다.)

이를 압축풀기하면 안에 mingw64라는 폴더가 있을 것이다. 이를 C드라이브에 넣어두자.

image

이제 환경 변수를 지정해주어야 한다. 환경 변수는 터미널에서 특정 키워드를 입력했을때, 적절한 파일이 있는지 찾아주는 최우선 경로라고 보면 된다. 만약 터미널에서 gcc키워드를 입력했을 때, 현재 경로에서 gcc를 찾지 못하면 환경 변수path로 등록된 경로에 gcc키워드를 처리할 수 있는 파일이 있는지 모두 검색한다.

윈도우즈의 시스템 환경 변수 편집을 찾아 열어준다.

시스템 속성 환경 변수
image image

Path를 더블 클릭하면 경로들을 추가해줄 수 있다. 우리가 추가해줘야하는 경로는 gcc.exeg++.exe 컴파일러가 있는 경로이다. 따라서 C:\mingw64\bin 경로를 입력해주면 된다. 그리고 터미널을 열어주어 gcc --version을 입력하여 아래와 같이 나온다면 성공이다.

Path 추가 gcc 컴파일러 확인
image image

만약 여기까지 제대로 했는데, 컴파일러 확인이 되지 않는다면 재부팅을 하고 오면 될 것이다.

VSCode 설정

이제 VSCode 설정을 해보자. 만약 깔려있지 않다면 구글에 visual studio code를 검색하고 설치하자.

우선 C/C++ 익스텐션을 설치해야한다. C/C++ Extension Pack을 설치하면 기타 등등 필요한 것들을 한꺼번에 받을 수 있다. 여기까지 설치가 완료되었다면, cpp 파일을 만들어 코드를 작성해보자.

C/C++ Extension Pack 코드 작성
image image

위와 같이 코드 하이라이트가 적용되면 성공이다. 만약 안된다면, 역시 vscode를 껐다가 켜보자.

하지만, 아직 cpp코드를 실행할 수 없다. (물론 터미널로는 가능하지만) 우선 기본 터미널을 git bash로 설정해야 한다.

image

터미널을 열어 기본 프로필 선택을 눌러주면 기본 터미널을 설정할 수 있다. git bash로 설정해주자. 만약 위와 같은 터미널 창이 현재 VSCode 화면에서 보이지 않는다면 ctrl + `(백틱, 1 왼쪽, tab키 위쪽)을 눌러 터미널을 켜주자.

설정이 되고, ctrl + shift + `을 눌러 새로운 터미널을 열면, git bash가 열리게 될 것이다.

image

이제 본격적으로 실행하는 방법을 세팅할 것이다. ctrl + shift + b를 누르면 위 프롬프트에 g++ 활성화 빌드와 같은 것이 보이게 될 것이다. 클릭하면 .vscode/경로가 생기고 안에 tasks.json이라는 파일이 생성될 것이다.

해당 파일에 아래와 같이 복사해주자.

{
    "version": "2.0.0",
    "tasks": [
        {
            "type": "shell",
            "label": "C++ 빌드",
            "command": "g++",
            "args": [
                "-fdiagnostics-color=always",
                "-g",
                "${relativeFileDirname}/${fileBasename}",
                "-o",
                "${relativeFileDirname}/${fileBasenameNoExtension}.out",
                "&&",
                "${relativeFileDirname}/${fileBasenameNoExtension}.out",
                "<",
                "input.txt",
                ">",
                "output.txt"
            ],
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        },
        {
            "type": "shell",
            "label": "g++ debug",
            "command": "g++",
            "args": [
                "-fdiagnostics-color=always",
                "-g",
                "${relativeFileDirname}/${fileBasename}",
                "-o",
                "${relativeFileDirname}/${fileBasenameNoExtension}.out"
            ],
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "build"
            },
        }
    ]
}

tasks.json은 쉽게 말하면 매크로이다. 위는 C/C++ 빌드g++ debug두 가지 매크로에 대한 정보를 담고 있다.

설정에 대해 간단하게만 설명하면아래와 같다.

설정 설정하는 값 설정 내용
type 명령의 종류 쉘스크립트를 이용할 것이므로 shell을 입력하였다.
label 명령의 이름 VSCode에서 보여지는 해당 명령의 이름
원하는 이름을 작성해주면 된다.
command 명령 인자 g++을 이용하여 cpp 파일을 빌드할 것이므로 g++을 입력해주었다. 환경 변수 설정이 되지 않았다면 g++.exe파일의 절대 경로를 작성해주어야 한다.
args 명령 작성 시 뒤에 붙는 인자들 이는 따로 설명
problemMatcher 컴파일 에러 발생 시 처리 gcc컴파일러가 에러메시지를 전달할 것이므로 $gcc로 작성
group 그룹 해당 명령의 그룹, 둘다 cpp파일 빌드를 담당할 것이므로 "kind": "build"로 설정, 기본 빌드는 C/C++ 빌드이므로 C/C++ 빌드에만 "isDefault": true를 작성해줌

args 설명


args는 프로그램 실행 시 전달하는 인자들이다.

예시를 들면 아래와 같다. typeshell, commandg++이고 args["a.cpp", "-o", "a.out"]이라면 shell에 다음과 같은 명령어가 실행된다.

$ g++ a.cpp -o a.out

이는 g++을 이용하여 a.cpp 파일을 컴파일하여 a.out으로 결과를 만든다는 g++ 명령어이다. 하지만 bash 터미널을 이용하면 이러한 꼼수를 부릴 수 있다.

args["a.cpp", "-o", "a.out", "&&", "./a.out", "<", "input.txt", ">", "output.txt"]이라면 shell에 다음과 같은 명령어가 실행된다.

$ g++ a.cpp -o a.out && ./a.out < input.txt > output.txt

여기서 &&은 두 개의 명령을 구분한다는 의미이다. 따라서 위는 g++ a.cpp -o a.out./a.out < input.txt > output.txt가 순차적으로 실행된다. 그리고 bash터미널에서 <의 의미는 표준 입력 리다이렉션, >의 의미는 표준 출력 리다이렉션이다. 위 명령어를 통해 ./a.out이 실행 될 때, 터미널에서 입력을 받지 않고 input.txt 파일에서 입력을 받게 된다. 이렇게 하면, 번거롭게 예제 입력을 복사 및 붙여넣기 하지 않고, 한 번만 input.txt에 작성하면 된다. 그리고 출력은 터미널이 아닌 output.txt에 작성된다. 이는 출력을 재활용할 때, 굉장히 유용하다.

그럼 이제 C/C++ 빌드 tasks.jsonargs를 다시 가져와보겠다.

"args": [
    "-fdiagnostics-color=always",
    "-g",
    "${relativeFileDirname}/${fileBasename}",
    "-o",
    "${relativeFileDirname}/${fileBasenameNoExtension}.out",
    "&&",
    "${relativeFileDirname}/${fileBasenameNoExtension}.out",
    "<",
    "input.txt",
    ">",
    "output.txt"
]

-fdiagnostics-color=always는 에러 발생시, 컴파일러의 내용을 컬러로 출력하겠다는 명령어이다. -g는 디버그 옵션으로, 사실 이유는 모르겠으나, 이 디버그 옵션으로 인해 undefined behavior의 동작이 달라져 과제 점수를 0점 받은 적이 있다. 웬만하면 붙여주는 편이다. 여기서 ${relativeFileDirname}는 실행하는 파일의 상위 폴더의 상대 경로를 출력해주는 VSCode 예약어이다. ${fileBasename}은 실행하는 파일의 이름으로 바꾸어준다. 따라서 workspace 경로가 ~/이고, ~/ps/practice.cpp를 실행한다고 하면 ${relativeFileDirname}./ps가 되고, ${fileBasename}practice.cpp가 되어 전체 명령어가 ./ps/practice.cpp가 된다. ${fileBasenameNoExtension}은 실행 파일에서 확장자를 제거해준다. practice.cpppractice 될 것이다. 따라서 해당 경우 위 명령어는 아래와 같이 실행된다.

$ g++ -fdiagnostics-color=always -g ./ps/practice.cpp -o ./ps/practice.out && \
 ./ps/practice.out < input.txt > output.txt

컴파일을 완료하고, 그 파일을 실행하는데, input.txtoutput.txt로 리다이렉션을 수행한다는 뜻이 되는 것이다.

cpp 파일 실행

이제 input.txt를 생성하고, 프로그램을 실행하는 ctrl + shift + b를 누르면 프로그램 실행이 될 것이다.

image

여기까지가 바로 프로그램 실행에 대한 설정이고, 1년 전에 이미 성공했던 내용이다. 이제 디버깅 설정을 해보겠다.

gdb 디버깅 설정

디버거를 설정하기 위해 먼저 tasks.json의 설정을 미리 건드려두었다. g++ debug 매크로가 바로 그것이다. 이 매크로는 .out파일로 컴파일만 진행하고 default가 아니라서 ctrl + shift + b를 누르더라도 실행되진 않는다. 이제 launch.json파일을 설정해보자. 없다면 .vscode 경로에 직접 생성해주어도 좋다.

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "C++ Launch",
            "type": "cppdbg",
            "request": "launch",
            "program": "${fileDirname}/${fileBasenameNoExtension}.out",
            "stopAtEntry": false,
            "args": ["<", "input.txt", ">", "output.txt"],
            "cwd": "${fileDirname}",
            "MIMode": "gdb",
            "miDebuggerPath": "gdb",
            "preLaunchTask": "g++ debug"
        }
    ]
}

위는 나도 정확하게 이해하는 부분이 많지는 않으니 이해하고 있는 부분만 간단하게만 설명하겠다. .cpp 파일에 F5를 누르면 launch가 진행된다. 이 때 cpp파일을 실행할 수 있는 cppdbg라는 type이 찾아져 위 명령을 실행한다. 그리고 "MIMiode" : "gdb" 명령어를 통해 C/C++ 익스텐션의 debug기능과 실행이 연결된다.

한편 .cpp파일은 컴파일을 해주어야 하므로 먼저 "preLaunchTask": "g++ debug"를 통해 g++ debug 매크로가 먼저 실행되어 컴파일이 진행된다. program을 통해 실행할 파일이 정해지며, 이 파일은 컴파일 완료된 .out파일이다. 단, 이 실행에서도 역시 리다이렉션을 사용할 것이므로 args를 위와 같이 설정해주었다. cwdgdb에 명령어 전달시 필요한 키워드인 것으로 보인다. 현재 workspace 경로를 지정해주었다. 디버거 경로는 miDebuggerPath로 지정된다. 환경 변수가 설정되어있으므로 gdb로 입력해두었다.

이제 모든 설정이 완료되었다. 이제 자동으로 input.txt, output.txt에서 입력이 진행되는 디버그를 VSCode에서 진행할 수 있다.

image

이제 디버깅까지 모든 과정을 VSCode에서 편하게 진행할 수 있을 것이다. 추가적으로 나는 ctrl + shift + b는 불편해서 ctrl + alt + c로 바꿔서 쓰고 있긴 하다.

Leave a comment