컴파일링이란 무엇입니까?
컴파일(compile)
(1) 프로그래머가 CHILL, FORTRAN, COBOL 등의 고급 언어(high level language)로 작성한 프로 그램을 번역하고, 컴퓨터가 실행(execute)할 수 있는 형식인 기계어(machine language)의 (목적)프로그램으로 변환하는 동작. 기계어와 거의 일대일에 대응한 기호를 쓰는 어셈블리 언어로 쓰인 프로그램을 번역하는 어셈블(assemble)과 대비된다.
(2) 컴파일을 실제로 행하는 프로그램(소프트웨어)을 컴파일러(compiler)라고 한다. COBOL 컴파일러, FORTRAN 컴파일러 등으로 부른다. 전자 교환기의 교환국 파일 작성 과정에서는 CHILL 언어로 작성된 교환용 프로그램의 소스 모듈을 컴파일러에 입력시켜 기계어로 번역된 오브젝트 모듈을 출력시킨다. 컴파일러는 언어 프로세서(language processor)의 하나이다.
▲ 컴파일의 순서
- 컴파일러(compiler)
컴파일러는 특정 프로그래밍 언어로 쓰여 있는 문서를 다른 프로그래밍 언어로 옮기는 프로그램을 말한다. 원래의 문서를 소스 코드 혹은 원시 코드라고 부르고, 출력된 문서를 목적 코드라고 부른다.
목적 코드는 주로 다른 프로그램이나 하드웨어가 처리하기에 용이한 형태로 출력되지만 사람이 읽을 수 있는 문서 파일이나 그림 파일 등으로 옮기는 경우도 있다. 원시 코드에서 목적 코드로 옮기는 과정을 컴파일이라고 한다. 컴파일러는 소스 프로그램을 읽어서 즉시 결과를 출력하는 인터프리터와는 구분된다.
소스 코드를 컴파일하는 이유는 대부분 사람에게 이해하기 쉬운 형태의 고수준 언어로부터 실행 가능한 기계어 프로그램을 만들기 위해서이다. 좁은 의미의 컴파일러는 주로 고수준 언어로 쓰인 소스 코드를 저수준 언어(어셈블리어, 기계어 등)로 번역하는 프로그램을 가리킨다.
- 컴파일러의 조건
컴파일러에서 꼭 지켜야 할 두 가지 조건이 있다. 첫째로 컴파일러는 옮김의 과정에서 프로그램의 뜻을 보존하여야 한다. 입력 받은 프로그램의 의미를 충실히 따라야 한다. 이런 조건이 없다면 컴파일러를 사용하는 사용자가 컴파일러를 믿고 프로그램을 작성할 수도 없고, 잘못된 옮김을 인정한다면 컴파일러를 올바르게 하기 위한 노력을 들일 필요가 없을 것이다.
두 번째로 실용적인 면에서, 컴파일러는 입력으로 들어온 프로그램을 어떤 면에서든지 개선해야 한다. 예를 들어 소스 코드를 기계어로 옮긴다면 기계가 이해할 수 없었던 언어를 기계가 이해할 수 있게 개선한 것이 된다. 같은 언어로 옮긴 경우에는 성능이 개선되는 등의 장점이 있어야 한다. 그렇지 않다면 컴파일을 수행할 이유가 없어진다.
- 컴파일러의 기능과 장점
(1) 고급언어를 직접 기계어 코드로 변환한다.
(2) 자바의 경우 바이트 코드로 변환한다. 중간단계의 코드를 생성하고 이것을 해석해서 실행한다.
C/C++언어와 같은 고급언어는 직접 기계어 코드로 변환한다. 마이크로프로세서는 각각 다른 기계어 코드를 가지고 있기 때문에 같은 고급언어라도 다른 기계어 코드를 생성해야 한다. 따라서 개발자는 해당 마이크로프로세서에 맞는 컴파일러 사용해야 한다. 그러나 자바는 다양한 마이크로프로세서에서 실행되도록 하는 철학을 가지고 개발되었기 때문에 바이트 코드를 가지고 해석을 해서 실행하는 방식이다.
장점은 한번 컴파일된 바이트 코드는 다른 플랫폼에서 재컴파일 없이 실행할 수 있다. 그러나 단점은 바이트 코드를 해석해서 실행할 프로그램 구조가 필요하고, 직접 기계어 코드를 실행하는 것 보다 속도에서 늦다.
소스 코드로부터 컴파일하면 중간단계인 오브젝트파일들을 생성한다. 고급언어뿐만 아니라 어셈블리어 소스를 어셈블해도 오브젝트 파일을 생성한다. 이 오브젝트 파일들을 묶어 하나의 실행파일을 만드는 과정을 링커에 의해 거치면 목적 실행파일이 생성된다. 이때 경우에 따라 라이브러리로부터 함수 코드가 붙어 하나의 실행파일을 만든다.
- 목적코드가 실행되는 방법
컴파일러가 실행되는 컴퓨터나 운영체제가 컴파일러의 목적코드가 실행될 컴퓨터나 운영체제와 같은 경우 네이티브 컴파일러(native compiler 또는 hosted compiler)라고 한다.
(1) 네이티브 컴파일러 예
- 마이크로소프트 윈도용 응용프로그램 개발하기 비주얼 스튜디오로 컴파일하면 실행파일(exe 파일) 생성한다.
- 리눅스용 응용프로그램 개발하기 위해 x86용 gcc를 사용하면 리눅스 실행파일이 생성된다.
반면에 크로스 컴파일러(cross compiler)는 다른 컴퓨터나 운영체제에서 실행되도록 제작된다. 임베디드 시스템 등 소프트웨어 개발에 충분한 환경을 갖추지 못한 환경에서 동작할 프로그램을 만들기 위해 사용된다.
(2) 크로스 컴파일러 예
- 리눅스(x86)에서 ARM용 임베디드 시스템용 프로그램이나 커널을 개발하기 위해 ARM용 gcc을 사용하면 ARM 코드의 실행파일이 생성된다.
- 마이크로소프트 윈도에서 8051, AVR, PIC등의 시스템 프로그램을 개발하기 위해 해당 컴파일러를 사용하면 해당 CPU의 코드가 생성된다.
- 일단구조와 다단구조
소스를 한 번 읽고 번역하여 바로 출력물을 내놓는 컴파일러도 있지만 여러 가지 목적을 위해 중간 결과를 만들어 그 결과를 다시 최종 결과로 출력하는 컴파일러도 있다. 중간 결과를 만드는 데는 여러 가지 이유가 있다.
(1) 다양한 언어 지원
다양한 입력 언어를 동일한 중간 표현으로 표현하거나 동일한 중간 표현을 여러 가지 출력 언어로 표현하면 다양한 입력 언어와 출력 언어를 지원하는 컴파일러를 작성할 수 있다.
(2) 속도 및 최적화
고수준 언어일수록 최적화된 성능보다는 사람에게 이해하기 쉬운 형태를 염두에 두고 설계된다. 때문에 중간형태를 거치는 것이 보다 저수준에서 효율적으로 프로그램을 최적화한 다음 최종적으로 출력물을 내놓는 데 유리할 수 있다.
(3) 저스트 인 타임 컴파일 (JIT 컴파일)
스몰토크, 자바, 마이크로소프트 공통 중간 언어(CIL) 등의 컴파일러는 가상 머신의 바이트코드를 출력한다. 그러나 가상 머신은 플랫폼의 기계어에 비해 속도가 느릴 수밖에 없으므로 이들 가상 머신에는 저스트 인 타임 컴파일러가 탑재되어 실행 직전에 현재 플랫폼의 기계어로 다시 한 번 컴파일되어 속도를 향상시킨다.
커뮤니티 Q&A
위 이론과 관련된 게시글이에요.
이해가 안 되거나 궁금한 점이 있다면 커뮤니티에 질문해 보세요!
게시글 작성하기