본문 바로가기
JAVA 공부

컴파일이란?

by KyeongOUK 2020. 4. 24.

컴파일이란 어떤 언어의 코드를 다른 언어로 바꿔주는 과정. 대표적인 예는 C++ 코드를 기계어로 바꿔주는 것이다. 사전적 의미는 (여러 출처에서 자료를 따와) 엮다, 편집[편찬]하다라는 뜻으로 소스코드와 기타 라이브러리 등을 하나로 엮어서 결과물을 만들어 낸다고 이해하면 될 듯.

컴파일러를 엄밀히 말하자면, 어떤 프로그래밍 언어로 쓰여진 소스 파일을 다른 언어로 바꾸어주는 번역 프로그램. 어떤 언어 A를 B로 바꾸면 그게 컴파일러다. Scheme을 C언어로 번역한다든지, 심지어 기계어를 C언어로 번역하더라도(!) 컴파일러라고 칭할 수 있다. 하지만 대개의 경우 고수준 언어를 기계어로 번역하는 프로그램을 일컫는다. 이 두 개념을 구분하고자 할 경우 전자를 트랜스컴파일러(transcompiler)나 소스간 컴파일러(source-to-source compiler), 후자를 디컴파일러(decompiler)라고 많이 부른다. 어셈블리어를 기계어로 번역하는 프로그램 역시 어셈블리어의 특수성 때문에 따로 어셈블러라 한다.

초기엔 프로그램을 작성하기 위해서는 컴퓨터 위에서 바로 돌아가는 기계어를 통하여 프로그래밍을 했다. 그러나 이런 과정은 생산성, 기기 간 호환성[1], 디버깅 등 모든 면에서 효율적이지 않다. 따라서 컴퓨터공학이 발전하면서 많은 부분 추상화된 고수준 언어를 작성하고 이를 번역기를 통해 기계어로 번역하기 시작했는데, 이 번역기가 바로 컴파일러이다. 현재 많은 프로그램은 컴파일러를 통하여 전체를 기계어로 번역하여 실행하므로 프로그램 개발에 필수적인 툴 중에 하나다.

한 언어의 컴파일러를 자신의 언어로 재작성하는 것을 부트스트래핑이라고 한다. 재밌는 것은 컴파일러도 결국 하나의 언어로 짜여진 프로그램이라는 점. 따라서 바이너리 포맷의 파일을 쓸 수 있고 트리 자료구조를 생성할 수 있는 언어는 부트스트래핑(bootstrapping)이 가능하다. [2] 범용 목적 프로그래밍 언어는 당연히 이 조건을 만족하므로 부트스트래핑이 가능하다. [3] gcc라는 C 컴파일러는 컴파일에 C++을 사용한다. 컴파일러의 최초 버전만 다른 언어용의 컴파일러 또는 어셈블러의 도움을 받아 만들고 나면[4] 컴파일러가 자기 자신의 언어로 짜여질 수 있다. 일례로, GHC라는 Haskell 컴파일러는 최초에 Lazy ML이라는 다른 언어로 작성되었다가, 자기 자신의 언어인 Haskell로 재작성 되었다. 이런 식으로 거슬러 올라가다 보면, 최초의 어셈블러는 기계어로 만들어졌고 최초의 고급 언어는 어셈블러로 만들어졌음을 알 수 있다.

원칙적으로 컴파일러는 프로그램을 기계어로 바꾸기만 할 뿐 이를 바로 실행이 가능하게 하지는 않는다. 여러 소스 파일에서 나온 결과물을 합치고 라이브러리도 포함시키는 등 별도의 작업을 거쳐야 실행이 가능해지는데 이를 수행하는 프로그램이 링커이다. 하지만 보통은 그냥 뭉뚱그려 컴파일러라 부르는 경우가 많다. 또한 요즘은 그냥 프로그램 하나만 돌리면 컴파일과 링킹을 한 번에 끝낼 수 있게 되어 있다. 물론 내부적으로는 컴파일러와 링커가 따로 있어서 이를 이용하는 경우가 많지만.

컴파일을 하는 대신, 소스를 한꺼번에 번역하지 않고 명령 하나하나를 실행할 때마다 해석하여 계산하는 방법도 있는데 이 해석기를 인터프리터라 해서 따로 분류한다. 컴파일러가 번역기라면 인터프리터는 통역기인셈.
인터프리터 언어에 비해 컴파일 언어의 단점은 수정이 용이하지 않다는 점이다. 수정 사항이 발생하면 다시 컴파일을 해야 되는데, 작은 프로그램일 경우에는 문제가 되지 않지만 컴파일이 몇 시간씩 걸리는 덩치 큰 프로그램에서는 문제가 된다. 특히 수정 사항이 빈번하게 발생할 경우에는 큰 문제가 된다. 이 때문에 수정 사항이 빈번하게 발생할 것 같은 부분은 인터프리터를 쓰는 방법으로 따로 빼 두는 기법을 많이 사용한다. (인터프리터는 속도는 느리지만 수정이 간단하다는 장점이 있다.)

컴파일러는 다음과 같은 세 분류로 나뉜다.
원시 코드를 바로 기계어로 변환하는 정적 컴파일(Static Compilation)
바이트코드 등의 중간 코드를 기계어로 변환하는 AOT 컴파일(Ahead-Of-Time Compilation)
실행시 최초 한 번에 한해 컴파일을 거치는 JIT 컴파일(Just-In-Time Compilation)

요즘 컴파일러들은 기계가 프로그램을 빠르게 돌릴 수 있도록 적절한 최적화 작업을 하고 프로그래머가 실수할만한 부분을 경고하는 등 갈수록 똑똑해지는 추세이다.

대졸 프로그래머가 할 수 있는 가장 어려운 프로그래밍 중 하나가 컴파일러, OS, 게임 엔진 제작이다.[5] 컴파일러는 대학교 컴퓨터공학과 커리큘럼의 가장 마지막(4학년)에 있는 과목이다.[6] 컴파일러를 제작하려면 하드웨어와 소프트웨어 전부를 이해하고 있어야 하고 자료구조와 알고리즘에 대한 심도 깊은 이해와 함께 전산수학에도 능해야 한다. 컴파일러를 제작할 수 있을 정도의 실력이라면 국내 탑티어 대기업에 들어갈 정도의 실력이 된다. 거기서 더 나간 스킬트리로는 프로그램 최적화가 있는데 이건 컴파일러의 보조 스킬.

기계어를 다시 프로그래밍 언어로 바꾸는 디컴파일이라는 용어도 있다. 사실 컴파일 과정에서 소스 코드의 일부 정보를 지워버리기 때문에 완전한 디컴파일은 불가능하다. 대체로 Java는 디컴파일시 손실되는 정보가 적은 편이고 C++의 경우 컴파일 프로필이 '릴리즈' 모드일 경우 상당수의 정보가 손실된다. 간혹 프로필을 '디버그'로 둔 채 그대로 릴리즈해버린 경우가 있는데 이 경우에는 디컴파일시 꽤 많은 정보가 보존되어 나온다. 하지만 대개 지역변수 이름 같이 지역성이 명백하고 기계한테 필요없는 정보는 날아가는 편이다.

'JAVA 공부' 카테고리의 다른 글

클래스와 객체  (0) 2020.04.24
JVM  (0) 2020.04.24
비트와 바이트  (0) 2020.04.24
자바 기초 : 문자와 문자열  (0) 2020.04.22
자바에서 메소드(Method)와 함수(function)의 차이  (0) 2020.04.22

댓글