Bulid 란 ?
빌드(Build)란 여러 소스코드 파일들을 기계어로 변환 후 실행 파일 혹은 라이브러리로 만드는 과정을 의미합니다.
컴퓨터는 0 과 1밖에 모르기 떄문에 우리가 작성하는 코드들을 바로 컴퓨터에게 보내면 컴퓨터들을 이해할수가 없습니다.
그렇기에 이런 소스코드들을 번역을 하여 컴퓨터가 읽을수있게 만들어야 합니다.
컴퓨터가 이해하고 있는 언어를 기계어라고 말하는데, 작성한 코드를 소스 코드라고 하는데 이 소스코드를 기계어로 바꾸는 과정을 빌드(Build)라고 합니다.
그림과 같이 소스코드를 빌드를 하여 실행파일을 얻게되는데 실행파일은 exe 와 같은 종류로 되있는데 이것들이 모두 빌드라는 과정을 걸쳐 만들어진 파일인 것 입니다.
이 빌드라는 과정으로 실행파일을 만들어내는것까지는 알게되었지만 이 빌드가 어떻게 동작하는지에 대해서는 아직 모르고있습니다.
그 결과만을 알고있으면 그 원리를 모르기에 본인이 이에 관련된 문제가 생겼을때 그것을 해결하는 방법을 모를수 있기때문에 과정을 이해하는 것이 문제 해결 능력을 키운다고 생각합니다 .
그러므로 이제부터 빌드라는 과정을 세분화 하여 나누고 각각 무엇을 하는지에 설명을 드리겠습니다.
빌드순서
빌드 과정에는 총 4가지 작업이 있습니다.
1. 전처리 작업
2. 컴파일 작업
3. 어셈블 작업
4. 링크 작업
대부분의 언어가 위와 같은 과정을 거칩니다.
여기서 2 ~ 3번 까지의 작업을 컴파일 작업이라고 말하는 경우가 흔합니다.
(1 ~ 3번을 컴파일 작업이라고 말하는 경우도 있음.)
빌드 과정을 단순히 설명하자면 전처리 → 컴파일 → 링크 하는 작업이라고 볼 수 있습니다.
1 ~ 3번 까지의 작업은 컴파일할 파일마다 일어나는 작업 입니다.
4번 작업은 컴파일 작업을 마친 하나 혹은, 여러 파일들의 결과물들을 링크(합침)하여 실행 파일을 만드는 작업이라고 볼 수 있습니다.
자세한 내용은 하나 씩 알아보도록 하겠습니다.
Pre Processing [ 전처리 ]
전처리 과정은 소스 코드를 변환하여 트랜슬레이션 유닛(Translation Unit) 로 만드는 과정 입니다.
말 그대로 본 작업에 들어가기 전에 '사전 처리' 를 해주는 단계라고 알 수 있습니다.
전처리 단계에서는 지시어를 통해 어떤 코드를 주석 처리하거나 특정 소스코드 혹은, C언어 파일 자체에 들어있는 텍스트를 복붙하는 작업을 합니다.
그렇게 전처리 단계로 인해 추가되거나 제거한 소스 코드를 확장된 소스 코드라 하며 이를 트랜슬레이션 유닛(Translation Unit) 이라고 합니다.
트랜슬레이션 유닛(Translation Unit)은 오로지 소스 코드만으로 이루어지기 때문에 그제서야 컴파일러가 이해하여 읽어들일 수 있으며 그래서 트랜슬레이션 유닛(Translation Unit)을 컴파일 단위라고 합니다.
전처리기 지시어는 '#' 으로 시작됨.
Ex) #include
<> : 시스템 경로에서만 헤더 파일을 검색
" " : 현재 작업중인 디렉토리에서 우선 검색한 뒤, 시스템 경로에서 검색
전처리기 작업 단계는
1. 주석 제거
2. 매크로를 복붙 확장
3.인클루드(#include) 파일을 복붙 확장
Compilation [ 컴파일 ]
프로그래밍 하다보면 많이 듣는 말중에 하나라고 생각됩니다. compile 번역하자면 '번역하다' 라는 뜻이지요.
빌드 과정을 모르는 분들은 그저 소스 코드를 컴파일 하라하면 컴파일만으로 소스 코드가 실행 파일이 만들어져 실행을 한다고도 잘 못 알수도 있습니다.
하지만, 컴파일은 그저 '번역' 하는 역활일뿐 컴퓨터가 실행할수 있게 만드는 것은 아닙니다.
이렇게 소스 코드를 컴파일 하는 역활을 하는것은 컴파일러(Compiler) 라고 합니다.
컴파일러는 트랜슬레이션 유닛을 어셈블리어로 변환을 합니다.
컴파일러는 어떤 함수 구현부를 만나면 그 이름과 똑같은 레이블을 정의합니다.
함수를 호출하는 코드는 레이블이 정의된 곳으로 점프하는 코드로 변환을 하며 다만 레이블이 정의된 위치는 아직은 모르는 상태 입니다.
나중에 링크 작업에서 이 레이블이 정의된 곳이 어디인지 주소를 알아내어 그 주소로 점프하도록 만들어 줍니다.
함수를 호출하는 코드를 레이블이 정의된 곳으로 점프하는 코드로 변환 하는 것을 " 구멍 생성 " 이라고 말합니다.
또한, 링크작업에서 주소를 알아내어 점프하도록 해주는 것을 " 구멍 매꾸기 " 라고 합니다.
소스 코드는 플랫폼에 의존적인 코드가 없었지만, 어셈블리어 코드로 변환되는 순간 플랫폼에 의존적이게 됩니다.
( 윈도우에서 만든 소스코드를 그대로 맥에서 복붙해서 사용해도 괜찮지만 어셈블리어 코드로 변환후에는 불가능 하다는 뜻)
즉, 컴파일러가 변환한 어셈블리어 코드는 특정 플랫폼에서만 동작하는 코드라고 볼수있습니다.
왜냐면 어셈블리어는 기계어랑 1:1로 대응되기 때문입니다.
기계어는 기계가 이해할 수 있는 2진수 코드를 의미하는데, 기계가 이해할 수 있으면 동작할 수 있다는 의미이고, 플랫폼마다 기계가 동작하기 위한 명령어가 다르기 때문에 기계어에 의존적인 것 입니다.
어셈블리어는 기계어랑 1:1로 대응된다 했으므로 마찬가지인 것 입니다.
어셈블리어 코드로 변환되면 더 이상 자료형의 개념도 존재하지 않습니다.
변수 이름도 존재하지 않게 됩니다.
어느 메모리 주소에서 몇 바이트 만큼 데이터를 읽어올 지 까지도 이 단계에서 정해지는 것 입니다.
대입하는 코드도 어느 메모리 주소에 대입할 지에 대한 코드로 대체 됩니다.
그러기에, 컴파일 에러가 나는 경우는 문법적으로 문제가 있기 떄문에 나오는 것 입니다.
Assemble [ 어셈블 ]
앞 단계에서 컴파일러가 트랜슬레이션 유닛 을 어셈블리어로 번역을 해주었습니다.
이제 이 어셈블리어 를 기계어로 바꾸어야 하는데, 이 단계를 어셈블러(Assembler)라고 합니다.
어셈블러는 어셈블리어를 오브젝트 코드로 변환을 시켜줍니다.
이것을 '객체 코드' 라고 합니다.
여러개의 연관된 파일을 빌드하면 '링크' 단계 전까지는 각 파일별로 번역되기 때문에 그 전까지는 파일 하나하나가 일부분으로 '객체' 가 되는 것입니다.
Linking [ 링크 ]
링크는 앞에서 컴파일 된 오브젝트 코드들을 모두 받아서 하나의 실행 파일로 만드는 과정입니다.
여기서 컴파일 작업에서 미리 기억해뒀던 그 레이블이 정의된 오브젝트 코드의 주소로 점프하도록 대체해 줍니다.
만약 오브젝트 코드에서 사용하려하는 레이블이 정의가 안되어있다면,
링크가 호출된 함수의 정의를 못찾았다는 의미가 되므로 함수가 어떻게 동작되는지 모르기 때문에 링커 에러가 나는 것 입니다.
이렇게 오브젝트 코드들을 모아 연결시켜주며 최종적으로 하나의 실행 파일을 만들어 주는 것 입니다.
앞서 규모 있는 회사에서는 빌드를 컴파일, 링크 2단계로 나눠서 하는 경우가 흔합니다.
그 이유는 링크라는 작업이 왜 필요한지와 연관이 되있는데
링크 작업 없이 빌드하는 경우, 소스 코드 하나를 컴파일 할 때마다 모든 소스 코드를 훑어보면서
다른 파일의 변수나 함수를 사용했는지 체크하고 사용했으면 정의를 찾아서 구멍을 매꾸어 주어야 합니다.
하지만 링크 시에는 딱 한번만 모든 소스 코드를 훑어보면 됐었습니다.
모든 소스 코드를 훑어보는게 문제라면, 빌드 전에 분할된 소스 코드를 전부 정의 중복 안되게 어떻게든
하나의 소스 코드로 합쳐버려서 빌드하면 링크 작업을 없어도 괜찮다고 생각할 수 있습니다.(툴로 합치든, 노가다로 하든 해서)
물론 구멍을 메꾸는 과정이 없어지므로 빌드 시간이 빨라지긴 합니다.
(컴파일 전에 미리 파일을 합치는 링크 작업을 '유니티 빌드' 라고 함.)
하지만 컴파일 해야하는 소스 코드의 양 자체가 많아지므로
큰 회사는 컴파일과 링크 작업 2단계로 분리해서 빌드하는 것.
마무리
끝을 맺으며 빌드 단계
'전처리 - 컴파일 - 어셈블 - 링크' 를 살펴보았습니다.
쉽게 정리하자면 앞에서( 전처리 - 컴파일 - 어셈블) 번역을 한다음에 링크에서 번역한 것들을 모아서 실행파일로 만든다
라고 이해할수 있을것 같습니다.
빌드 과정을 이해한다면 코딩중 나오는 컴파일 오류, 링크 오류에 대해 좀더 능숙하게 해결할수 있게 될수있으며
오류를 찾는 과정이 좀 더 쉬워질것이라고 믿고있기에 기억해두면 도움이 될거라고 생각합니다.
여기까지 부족한 글 읽어주셔서 감사합니다.
'프로그래밍 > ETC' 카테고리의 다른 글
컴파일러 종류 [ Compiler ] (0) | 2022.12.31 |
---|---|
라이브러리 [ Library ] (0) | 2022.12.29 |
파일 분할 (0) | 2022.12.28 |