이번 포스트에서는 C++에서의 빌드 과정과 관련된 코드 예제를 한 줄씩 분석하고, 그 의미를 자세히 설명합니다. 이 코드 예제와 주석은 컴파일과 링크 과정에서 발생할 수 있는 문제를 이해하는 데 도움이 됩니다.
#include <iostream>
#include <string>
#define SQUARE(X) X*X
using namespace std;
#include <iostream>
: 표준 C++ 라이브러리의 iostream
헤더 파일을 포함하여 cout
과 같은 입출력 스트림을 사용할 수 있게 합니다.#include <string>
: C++ 표준 라이브러리의 string
클래스를 사용하기 위해 포함된 헤더 파일입니다.#define SQUARE(X) X*X
: 전처리기 매크로로, SQUARE(X)
는 텍스트 대체되어 X*X
로 변환됩니다. 주의해야 할 점은 매크로는 단순 텍스트 치환이므로, 의도하지 않은 부작용이 발생할 수 있습니다.using namespace std;
: std
네임스페이스에 있는 이름을 전역적으로 사용 가능하게 합니다. 즉, std::cout
대신 cout
을 사용할 수 있게 합니다.int sum(int, int);
int sum(int, int);
: sum
함수의 프로토타입을 선언합니다. 이 함수는 두 개의 int
값을 받아서 합을 반환할 것입니다. 그러나 실제 구현은 이 코드에 포함되어 있지 않으며, 다른 파일에 있을 것입니다(util.cpp
).int main(int argc, char* argv[])
{
SQUARE(1);
int main(int argc, char* argv[])
: 프로그램의 시작 지점인 main
함수입니다. argc
는 명령줄 인수의 개수를 나타내며, argv
는 명령줄 인수를 문자열 배열로 전달합니다.SQUARE(1);
: 이 코드는 전처리 단계에서 1*1
으로 대체됩니다. 그러나 실제로는 결과가 사용되지 않기 때문에 이 줄은 아무런 효과가 없습니다. int total = 0;
for (int i = 0; i < argc; ++i)
{
string arg(argv[i]);
int num = stoi(arg);
total = sum(total, num);
}
cout << total << endl;
}
int total = 0;
: 합계를 저장할 변수를 선언하고 0
으로 초기화합니다.for (int i = 0; i < argc; ++i)
: argc
에 저장된 인수의 수만큼 반복문을 실행합니다.string arg(argv[i]);
: argv[i]
에 저장된 문자열을 string
객체로 변환합니다.int num = stoi(arg);
: 문자열 arg
를 정수로 변환합니다.total = sum(total, num);
: sum
함수를 호출하여 total
과 num
의 합을 계산하고 total
에 저장합니다.cout << total << endl;
: 최종 합계를 출력합니다.// 1. 시작
// 2. Developer 입력
// 3. Developer Command Prompt for VS 2019 선택
// 4. cd 를 이용하여 main.cpp 파일의 경로로 이동
main.cpp
파일이 있는 디렉토리로 이동하는 과정입니다. 이 명령 프롬프트는 컴파일러와 링커를 실행할 수 있는 환경을 제공합니다.// 컴파일 후 실행
// 1. cl main.cpp util.cpp
// 2. main.exe 10 20 30
// 3. del *.obj
// 4. del main.exe
cl main.cpp util.cpp
: cl
명령은 C++ 컴파일러를 실행합니다. 이 명령은 main.cpp
와 util.cpp
를 컴파일하고, 링커를 통해 main.exe
실행 파일을 생성합니다.main.exe 10 20 30
: 생성된 main.exe
파일을 실행하고, 명령줄 인수로 10
, 20
, 30
을 전달합니다. 이 값들이 argv
로 전달되어 sum
함수에서 계산됩니다.del *.obj
: 중간 컴파일 결과물인 .obj
파일들을 삭제합니다.del main.exe
: 생성된 실행 파일 main.exe
를 삭제합니다.// 1. cl main.cpp
// 안 됨, sum 함수를 찾을 수 없음, obj 파일은 생성 됨
main.cpp
만 컴파일하면 sum
함수가 구현된 util.cpp
가 없기 때문에 링크 단계에서 sum
함수가 정의되지 않아 에러가 발생합니다. 하지만 main.obj
파일은 생성됩니다.// 1. cl util.cpp
// 안 됨, main 함수를 찾을 수 없음, obj 파일은 생성 됨
util.cpp
만 컴파일하면 main
함수가 정의되지 않아 main
을 찾을 수 없다는 오류가 발생합니다. 그러나 util.obj
파일은 생성됩니다.// 1. cl main.cpp util.cpp /c
// main.obj, util.obj 파일이 생성 되어있음. /c는 컴파일만 하겠다는 의미
// 2. link main.obj util.obj
// main.exe 생성
cl main.cpp util.cpp /c
: 이 명령은 main.cpp
와 util.cpp
를 컴파일하지만, 링크 과정을 수행하지 않고 .obj
파일만 생성합니다. /c
옵션은 컴파일만 하고 링킹은 하지 않겠다는 의미입니다.link main.obj util.obj
: 이 명령은 이전에 생성된 .obj
파일들을 링크하여 main.exe
실행 파일을 생성합니다.// obj가 생성되었다는 것은 컴파일이 되었다는 것을 의미
// 컴파일 후 링킹 과정이 있는데 main.cpp, util.cpp를 각각 별도로 컴파일 하면 링킹에서 실패
.obj
파일이 생성되었다는 것은 컴파일이 성공했다는 의미입니다. 하지만 링킹 과정에서 모든 필요한 함수들이 정의되어 있지 않다면, 링크 오류가 발생할 수 있습니다.// 1. link main.obj
// sum 함수를 찾을 수 없음
main.obj
만 링크하려고 하면, sum
함수의 정의를 포함하고 있는 util.obj
파일이 없기 때문에 링크 오류가 발생합니다.// 1. cl main.cpp /P
// main.i 생성, 전처리만 함
// iostream 파일들이 main.cpp 에 붙여넣은 결과가 생성
// SQUARE와 같이 전처리 매크로도 대체가 됨
cl main.cpp /P
: /P
옵션은 컴파일러가 전처리 단계만 수행하도록 하며, 결과물을 .i
파일로 출력합니다. 이 파일에는 모든 #include
된 파일의 내용이 포함되며, 매크로 치환도 완료된 상태입니다.main.i
생성: 전처리된 파일이 생성됩니다. 이 파일은 실제로 컴파일되지 않으며, 전처리 결과만을 보여줍니다.컴파일 단계:
.cpp
)이 컴파일되어 중간 산출물(.obj
)이 생성됩니다. 이 단계에서는 함수 프로토타입이나 변수 선언의 문법 오류를 확인합니다.#include
파일이 포함되고, 매크로는 텍스트 치환으로 처리됩니다.링크 단계:
.obj
파일들을 하나로 결합하여 실행 가능한 프로그램(.exe
)을 생성합니다.빌드 과정:
.obj
파일들을 정확히 링크해야 실행 파일이 제대로 생성됩니다.전처리:
#include
파일들이 어떻게 포함되었는지 확인할 수 있습니다.