개요
제가 저번 게임 프로그래밍 수업 정리글이였던 게임 프로그래밍 | C++ | 메모리 구조 에서 말했듯이 다음 글은 빌드가 될 예정이였습니다...만!
이런... 글을 그 사이에 5개나 적어버렸더군요.
사실 빌드 정리글을 적어야 한다는 사실도 블로그를 싹다 갈아 엎으면서 다듬는 과정에서 글을 다시 읽었기에 떠오른 것이였습니다.
일단 적어보겠습니다. 정확히 기억은 잘 안나지만 수업 자료 대충 돌려보면서 되짚으면 기억나지 않을까요?
무엇을?
일단 빌드가 무엇인지부터 알아야겠죠?
저희 프로그래머가 보통 빌드라고 부르는 것은 소스 코드를 실행 가능한 실행 파일로 만드는 것을 말합니다.
허구한날 빌드본, 빌드본 거리는 이유가 여기에 있죠.
헤더에서 볼 수 있듯 여기선 C++ 소스 파일의 빌드 과정을 알아볼겁니다.
빌드 과정
빌드 과정은 자세히 하나하나 뜯었을때 6개의 단계로 이루어져있습니다.
- 소스 코드 작성
- 전처리
- 컴파일
- 링크
- 로드
- 실행
이렇게 6개의 단계로 이루어져 있는데 여기서 저희가 눈여겨 봐야할건 컴파일, 링크 두개입니다.
그래도 나머지를 알아둬서 나쁠건 없으니 하나하나 알아봅시다.
소스 코드 작성
사실... 이걸 빌드 과정이라고 부르기는 애매한데 따지고 보면 소스 코드가 없으면 빌드 자체가 무의미 하니 일단 빌드 과정이긴 합니다.
말 그대로 우리가 적는 코드입니다.
전처리
우리가 적은 소스 코드를 다듬는 단계입니다.
코드를 깔끔하게 만들어주는건 아니구요. 컴파일러에게 먹이기 전에 쓸데없는 부분 쳐내고 대체할 부분 대체하는 단계입니다.
주석 같은 코드에 전혀 쓸데 없는 부분을 지우고, #define 같은 매크로도 본래 코드로 치환하는 단계죠.
컴파일
우리가 적은 소스 코드를 기계어(Assembly)로 변환하는 단계입니다.
물론 기계어로 변환만 하진 않습니다.
일단 우리가 Visual Studio를 켜서 세미콜론(;)만 엄청나게 찍어대도 뜨는 빨간줄의 오류같은 것을 잡아주는게 누구죠?
바로 컴파일러입니다.
컴파일 단계에선 소스 코드에서 발생한 오류 또한 잡습니다. 물론 잡기만 하기 때문에 고치는건 우리가 해야하죠.
그리고 데이터 영역의 메모리를 할당하는 역할 또한 맡습니다.
이러한 컴파일 과정을 거치면 .cpp 파일 하나하나의 확장자가 .obj로 바뀝니다.
그리고 이 파일을 가지고 다음 단계로 넘어가죠.
링크
사실상 이 글에서 가장 중요한 부분입니다.
저희가 소스 코드를 작성할때 단 한개의 cpp 파일만 작성하는 경우는 없습니다.
당장 유니티의 사례만 보더라도 PlayerController가 모든 것을 다 하진 않잖아요?
간단한 프로그램이면 몰라도 규칙이 5개 정도 밖에 없는 게임이라도 만드려면 cpp 파일을 분리해야 훨씬 적기 편해집니다.
무엇보다 main 함수를 실행하는 cpp 파일이 더러워지면 불편해요.
아무튼 이 링크 단계에선 컴파일러가 obj로 변환해준 cpp 파일을 연결합니다.
이게 무슨 말이냐구요?
#pragma once
int Add(int a, int b);
이러한 코드를 가진 Math.h 라는 헤더가 있다고 해봅시다.
그리고 main에서 헤더를 include한 다음 Add함수를 사용하고 싶습니다.
#include<iostream>
#include "Math.h"
using namespace std;
int main()
{
cout << Add(1,2) << endl;
}
근데 일단 이러면 당연하게도 오류가 나겠죠?
헤더를 include하는건 복잡한 작업이 아닙니다. 그저 헤더의 원문을 그대로 복사해다가 붙여넣는거죠.
그러니까 저 main 함수를 실행하는 cpp 파일은 사실상 요렇게 생겨먹은 겁니다.
#include<iostream>
int Add(int a, int b);
using namespace std;
int main()
{
cout << Add(1,2) << endl;
}
iostream은 너무 기니까 패스하겠습니다.
분명히 설명했던 내용인 것 같은데 딴곳에다가 적었던 것 같군요. 나중에 헤더 관련으로 간단하게 글 한번 더 쓰겠습니다.
진짜로! 1주 안에 헤더 글로 뵙죠.
아무튼 저렇게 헤더 함수의 본문을 구현하는 cpp파일을 따로 만들어서 저 헤더의 함수를 구현해줬습니다.
#include "Math.h"
int Add(int a, int b)
{
return a + b;
}
근데 이렇게 cpp 파일이 나눠져 있는데 함수 실행이 잘 되는 이유가 뭘까요?
그것은 링커가 이 cpp 파일들이 컴파일 되고 나온 obj 파일들을 연결했기 때문입니다.
이러면 사실상 헤더에 의해 전방 선언된 Add 라는 함수의 원문을 Math.cpp 파일에서 가져오는 것과 마찬가지죠.
... 전부 이해하고 적고 있는 거 맞습니다. 글에 두서가 없네요... 조만간 다듬겠습니다.
그리고 이렇게 다 묶어준 obj 파일을 기반으로 .exe 확장자의 실행 파일을 만듭니다.
로드
실행 할 프로그램을 메모리에 할당하는 단계입니다.
동적 라이브러리 같은 것을 사용한다면 그것도 같이 로드 된다고 하는데 저는 잘 모르겠어요.
왜냐하면 라이브러리를 아직까지 사용해본 경험이 단 한번도 없기 때문이죠.
마치는 말
뭔가 급하게 마무리 하는것 같은데 기분 탓 아니고 사실 급하게 마무리 하는거 맞습니다.
더 적을 뭔가가 없어요.
'개발 > C++' 카테고리의 다른 글
[C++] | extern "C"와 __declspec(dllexport)는 대체 뭔데 (0) | 2024.11.06 |
---|---|
게임 프로그래밍 | C++ | 헤더 (0) | 2024.05.23 |
자료구조 | C++ | 연산자 오버로딩 (Overload) (1) | 2024.04.23 |
C++ | 동적 배열 (3) | 2024.04.17 |
게임 프로그래밍 | C++ | 메모리 구조 (0) | 2024.04.17 |