✅ 컴파일러(Compiler)
컴파일러란 사람이 이해할 수 있는 언어를 기계어로 변환해주는 작업이다. 사람이 이해할 수 있는 언어는 우리가 사용하는 C언어, Java, Python 등의 프로그래밍언어로 작성된 소스코드를 의미한다. 그리고 이러한 프로그래밍 언어를 하위 수준 언어로 변환하여 실행가능한 프로그램을 만드는 작업을 컴파일러(Compiler)라고 한다.
물론 소스코드를 실제 실행 파일로 변환하는 컴파일 작업에는 위와 같이 많은 단계들이 있지만 간단하게 살펴보려고 한다.
✅ 컴파일 과정
컴파일 과정은 4가지 단계(전처리 과정 - 컴파일 과정 - 어셈블리 과정 - 링킹 과정)으로 나누어 진다.
이 4가지 단계를 묶어서 컴파일 과정, 빌드 과정이라고 부르기도 하고 컴파일 과정과 링킹 과정을 따로 나눠서 부르기도 한다.
1. 전처리(Pre-processing) 과정
전처리(Pre-processing) 과정은 전처리기(Preprocessor)를 통해 소스 코드 파일(*.c)을 전처리 된 소스 코드 파일(*.i)로 변환하는 과정이다.
이 과정에서 대표적으로 세 가지 작업을 수행한다.
주석 제거: 소스 코드에서 주석을 전부 제거한다. 주석은 사람들이 알아볼 수 있게 남긴 내용이지 컴퓨터가 알 필요는 없기 때문
헤더 파일 삽입: #include 지시문을 만나면 해당하는 헤더 파일을 찾아 헤더 파일에 있는 모든 내용을 복사해서 소스 코드에 삽입한다. 즉, 헤더 파일은 컴파일에 사용되지 않고 소스 코드 파일 내에 전부 복사된다. 헤더 파일은 컴파일에 사용되지 않고 소스 코드 파일 내에 전부 복사된다. 헤더 파일에 선언된 함수 원형은 후에 링킹 과정을 통해 실제로 함수가 정의되어 있는 오브젝트 파일(컴파일된 소스 코드 파일)과 결합한다.
매크로 치환 및 적용: #define 지시문에 정의된 매크로를 저장하고 같은 문자열을 만나면 #define된 내용으로 치환한다. 간단하게 말해 매크로 이름을 찾아서 정의한 값으로 전부 바꿔준다.
2. 컴파일(Compilation) 과정
컴파일(Compilation) 과정은 컴파일러(Compiler)를 통해 전처리된 소스 코드 파일(*.i)을 어셈블리어 파일(*.s)로 변환하는 과정이다.
이 과정에서 우리가 일반적으로 컴파일하면 생각하는 언어의 문법 검사가 이루어진다. 또한 Static한 영역(Data, BSS 영역)들의 메모리 할당을 수행한다.
3. 어셈블리(Assembly) 과정
어셈블리어를 설명하기 앞서 어셈블리어 정의를 살펴보자. 기계어는 다른 말로 명령어라고 부르는데 명령어는 0101010과 같은 이진수로 이뤄진 숫자로 CPU 종류마다 고유한 내용을 가지고 있다.
어셈블리어는 이런 명령어를 사람이 이해할 수 있게 부호화한 것으로 CPU 명령어(기계어)와 1대1로 매칭된다.
어셈블리(Assembly) 과정은 어셈블러(Assembler)를 통해 어셈블리어 파일(*.s)을 오브젝트 파일(*.o)로 변환하는 과정이다.
4. 링킹(Linking) 과정
링킹(Linking) 과정은 링커(Linker)를 통해 오브젝트 파일(*.o)들을 묶어 실행 파일로 만드는 과정이다. 이 과정에서 오브젝트 파일들과 프로그램에서 사용하는 라이브러리 파일들을 링크하여 하나의 실행 파일을 만든다. 이때 라이브러리를 링크하는 방법에 따라 정적 링킹(Static Linking)과 동적 링킹(Dynamic Linking)으로 나눌 수 있다.
✅ Compile Language VS Interpret Language
그렇다면 소스코드를 실행할 때 실행파일로 컴파일이 필요하지 않은 언어는 없을까? 대표적으로 파이썬(Pyton)이 컴파일이 필요하지 않다.
파이썬처럼 소스코드를 실행할 때 컴파일 없이 바로 실행 가능한 언어를 인터프리터(Interpreter)언어라고 한다. 인터프리터는 소스코드로 된 명령어를 한 번에 한 줄씩 읽어들여서 실행하는 프로그램이다.
소스코드를 실행시키기 위해서는 2가지 번역 방식이 있는데 하나는 프로그램을 컴파일하는 것이고, 다른 하나는 프로그램을 인터프리터에 통과 시키는 방법이다. 인터프리터는 소스코드를 중간 형태로 번역한 다음 그것을 실행하며 컴파일러는 소스코드를 직접 기계어로 번역한다.
컴파일 언어 | 인터프리터 언어 | |
구분 | 소스코드를 실행할 때 컴파일이 필요한 언어 | 소스코드를 실행할 때 별도의 컴파일 작업 없이 바로 실행이 가능한 언어 |
프로그램 실행 방법 | 컴파일된 파일(주로 exe프로그램)을 한꺼번에 실행 | 인터프리터에 의해 한 줄씩 실행 |
예 | C, C++, Java | Python, Ruby, PHP, JavaScript |
인터프리터 방식은 다음과 같은 방법을 따른다.
1. 소스 코드를 직접 실행한다.
2. 소스 코드를 효율적인 다른 중간 코드로 변환하고, 변환한 것을 바로 실행한다.
3. 인터프리터 시스템의 일부인 컴파일러가 만든, 미리 컴파일된 저장 코드의 실행을 호출한다.
인터프리터라고 해서 컴파일이란 작업이 전혀 없는 것은 아니다. 파이썬의 경우 __pycache__ 라는 이름의 폴더가 있는 경우가 있는데 이 폴더에는 확장자가 .pyc인 파일을 두는 곳이다. 이 파일은 바이트코드로 컴파일된 파일이다. 이런 파일이 있으면 파이썬 인터프리터가 파이썬 소스코드를 실행할때 .pyc파일을 실행하여 좀 더 빨리 프로그램을 실행할 수 있다. 즉, 컴파일 방식과 인터프리터 방식의 절충형이다.
참고
'Computer Science' 카테고리의 다른 글
[네트워크] 웹 사이트에 접속하는 과정 (0) | 2023.01.09 |
---|---|
디자인 패턴(Design Pattern)이란? (0) | 2023.01.08 |
세션 vs 토큰(JWT) 인증의 차이 (0) | 2023.01.06 |
GPU(그래픽 처리 장치) 개념 및 CPU와의 차이점 (0) | 2023.01.05 |
IPv4와 IPv6 개념 및 차이점 (0) | 2023.01.05 |