부트스트랩 (컴파일러)
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.
1. 개요
부트스트랩(컴파일러)은 컴파일러를 개발하는 과정으로, 컴파일러가 스스로를 컴파일할 수 있도록 하는 기술을 의미한다. 일반적인 부트스트랩 절차는 0단계에서 부트스트랩 컴파일러를 준비하고, 1단계에서 부트스트랩 컴파일러를 생성하며, 2단계와 3단계에서 완전한 컴파일러를 반복적으로 생성하는 3~4단계로 이루어진다. 부트스트래핑은 컴파일될 언어에 대한 테스트, 컴파일러 개발의 용이성, 백엔드 개선의 효과, 일관성 검사 등의 장점을 제공한다. 최초의 컴파일러를 어떻게 만들 것인가에 대한 '닭이 먼저냐, 달걀이 먼저냐' 문제는 인터프리터 사용, 다른 언어의 컴파일러 활용, 언어의 하위 집합 사용, 크로스 컴파일, 바이트코드 버전 제공 등의 다양한 해결 방법을 통해 극복한다.
더 읽어볼만한 페이지
- 컴파일러 이론 - 크로스 컴파일러
크로스 컴파일러는 소프트웨어 빌드 환경과 대상 환경을 분리하여 다른 환경을 위한 실행 코드를 생성하는 컴파일러로, 임베디드 시스템, 다중 운영 체제 지원, 서버 팜 활용 등에 사용되며 GCC, Manx Aztec C, Microsoft C, Free Pascal, Clang 등이 있다. - 컴파일러 이론 - 템플릿 메타프로그래밍
템플릿 메타프로그래밍은 템플릿을 활용하여 컴파일 시간에 계산을 수행하는 프로그래밍 기법으로, 코드 중복을 줄이고 런타임 성능을 향상하며 정적 다형성을 구현하는 데 사용된다. - 컴파일러 - 바이너리 재컴파일러
- 컴파일러 - 링커 (컴퓨팅)
링커는 여러 모듈로 된 목적 파일을 결합해 실행 가능한 프로그램을 만들고, 정적/동적 링킹으로 라이브러리를 연결하며, 심볼 해결 및 재배치로 변수와 함수를 메모리 주소에 연결하는 소프트웨어 도구이다.
부트스트랩 (컴파일러) | |
---|---|
개요 | |
주제 | 컴파일러 작성 프로세스 |
관련 개념 | 부트스트래핑 (컴퓨터) |
상세 내용 | |
부트스트래핑 컴파일러 | 자기 컴파일 컴파일러 작성 프로세스 |
핵심 질문 | "최초의 컴파일러는 어떻게 만들어졌는가?" (닭이 먼저냐, 달걀이 먼저냐 문제와 유사) |
필요성 | 고급 프로그래밍 언어로 작성된 컴파일러를 실행하기 위해 |
단계 | 1단계: 더 간단한 언어로 컴파일러 작성 (예: 어셈블리어) 2단계: 1단계 컴파일러를 사용하여 더 높은 수준의 언어로 작성된 컴파일러 컴파일 |
예시 | Pascal 컴파일러 GCC |
고려 사항 | |
이식성 | 다른 플랫폼으로 컴파일러 이식 용이 |
유지보수성 | 자체적으로 컴파일 가능하므로 유지보수 용이 |
최적화 | 자체 컴파일러를 사용하여 더 나은 코드 생성 가능 |
역사 | |
기원 | 1950년대 후반 |
선구자 | 하인츠 루티샤우저와 그의 팀 (ALGOL 58 컴파일러 개발) |
추가 정보 | |
관련 용어 | 메타 컴파일러 Tombstone diagram 반사 |
2. 절차
일반적인 부트스트랩 절차는 세 단계 혹은 네 단계로 이루어진다.[13][14][15][3][4][5] 각 단계는 다음과 같다.
- 0단계: 부트스트랩 컴파일러가 동작할 환경을 준비하고 사용할 소스 언어와 생성할 출력 언어를 정의한다.
- 1단계: 정의된 환경에서 부트스트랩 컴파일러를 생성한다. 이 컴파일러는 최소한 자기 자신의 소스 코드를 컴파일할 수 있어야 한다.
- 2단계: 1단계에서 생성된 부트스트랩 컴파일러를 사용하여 완전한 기능을 갖춘 컴파일러를 생성한다.
- 3단계: 2단계에서 생성된 완전한 컴파일러를 사용하여 다시 한번 완전한 컴파일러를 생성하며, 필요에 따라 추가 기능을 개발하기 위해 2단계로 돌아갈 수 있다.
2. 1. 0단계: 부트스트랩 컴파일러 준비
부트스트랩 컴파일러가 동작할 환경을 준비하는 단계이다.[13][14][15][3][4][5] 이 단계에서는 부트스트랩 컴파일러가 사용할 소스 언어와 생성할 출력 언어를 정의한다.만약 컴파일러가 전혀 없는 베어 머신 환경이라면, 소스 코드와 출력 결과물 모두 바이너리 기계어로 직접 작성해야 한다. 또는, 대상 기계가 아닌 다른 기계에서 크로스 컴파일러를 이용하여 결과물을 생성할 수도 있다.[13][14][15][3][4][5]
반면, 대상 기계에 이미 다른 컴파일러가 존재하는 경우에는 해당 컴파일러가 이해할 수 있는 언어로 부트스트랩 컴파일러를 작성한다. 이렇게 작성된 부트스트랩 컴파일러는 고급 프로그래밍 언어, 어셈블리 언어, 오브젝트 파일, 또는 기계어 등 대상 기계에서 실행 가능한 코드를 생성하는 역할을 한다.[13][14][15][3][4][5]
2. 2. 1단계: 부트스트랩 컴파일러 생성
부트스트랩 컴파일러가 생성되는 단계이다. 이 컴파일러는 자체 소스 코드를 대상 머신에서 실행할 수 있는 프로그램으로 변환하기에 충분한 기능을 갖춘다.[13][14][15][3][4][5] 이 시점부터 모든 추가적인 개발은 부트스트랩 컴파일러에 의해 정의된 언어를 사용하여 이루어지며, 2단계가 시작된다.2. 3. 2단계: 완전한 컴파일러 생성
부트스트랩 컴파일러를 이용하여 완전한 컴파일러를 생성하는 단계이다.[13][14][15] 이 과정은 일반적으로 필요에 따라 여러 세부 단계를 거쳐 진행된다. 예를 들어, 특정 언어의 X 버전 컴파일러는 다음 버전인 X+1의 새로운 기능을 컴파일할 수 있도록 개발될 수 있다. 하지만 이 X 버전 컴파일러 자체는 아직 X+1의 기능을 사용하지는 못한다.이렇게 만들어진 새 컴파일러가 충분한 테스트를 거치고, 자기 자신의 소스 코드를 성공적으로 컴파일할 수 있음이 확인되면(즉, 셀프 호스팅이 가능해지면), 이 컴파일러가 바로 X+1 버전의 공식 컴파일러로 릴리즈된다. 이후부터 개발자들은 이 새로운 X+1 버전 컴파일러를 통해 해당 언어의 새로운 기능들을 사용할 수 있게 된다.
때로는 생성된 완전한 컴파일러의 정확성을 검증하기 위해, 이 컴파일러를 이용해 소스 코드를 다시 한번 컴파일해보기도 한다. 이렇게 두 번 컴파일한 결과물이 서로 동일해야 한다. 만약 결과물이 다르다면, 이는 앞서 사용된 부트스트랩 컴파일러나 방금 생성된 완전한 컴파일러 중 하나에 버그가 있다는 것을 의미한다.[13][3]
2. 4. 3단계: 완전한 컴파일러 반복 생성
2단계에서 생성된 완전한 컴파일러를 사용하여 다시 한번 완전한 컴파일러를 생성하는 단계이다.[13][15] 컴파일러에 추가적인 기능이 필요한 경우, 이 3단계에서 만들어진 컴파일러가 기존의 부트스트랩 컴파일러를 대신하여 다시 2단계부터 개발을 시작하게 된다.[13]부트스트랩 과정의 정확성을 검증하기 위해, 완전한 컴파일러는 두 번 만들어져 그 결과물을 비교한다. 만약 두 결과물이 서로 다르다면, 이는 부트스트랩 컴파일러 또는 2단계에서 만들어진 완전한 컴파일러에 버그가 있다는 것을 의미한다.[13]
3. 장점
컴파일러를 부트스트래핑하는 것은 다음과 같은 장점들을 가진다:[16][17][6]
- 컴파일되는 언어에 대한 중요한 테스트이며, 이로 인해 도그푸딩의 한 형태가 된다.
- 컴파일러 개발자와 버그 보고자는 컴파일되는 언어만 알면 된다.
- 컴파일러 개발은 컴파일되는 해당 고급 언어로 이루어질 수 있다.
- 해당 컴파일러의 백엔드 개선은 범용 목적 프로그램뿐만 아니라 해당 컴파일러 자신 또한 개선한다.
- 컴파일러가 언어 자신의 목적 코드를 재생산해 내어야 하므로 포괄적인 일관성 검사가 된다.
이러한 장점 중 일부는 해당 언어의 런타임 시스템 역시 동일한 언어로 작성되었다고 가정한다는 점에 유의해야 한다.[6]
4. 닭이 먼저냐, 달걀이 먼저냐 문제
X 언어로 작성될 컴파일러를 만들어야 할 때, 특히 그 컴파일러 자체가 X 언어로 작성된다면 '첫 번째 컴파일러를 어떻게 컴파일할 것인가?'라는 문제가 발생한다. 이는 마치 닭이 먼저냐, 달걀이 먼저냐 문제와 같다. 이 문제를 해결하기 위한 다양한 방법들이 존재한다.
4. 1. 해결 방법
X 언어로 작성될 컴파일러를 처음 만들어야 할 때, 즉 컴파일 대상 언어(X)와 컴파일러 구현 언어(X)가 같을 때 '첫 컴파일러를 어떻게 컴파일하는가?'라는 닭이 먼저냐, 달걀이 먼저냐와 같은 문제가 발생한다. 이 문제를 해결하기 위해 실제로 사용되는 다양한 방법은 다음과 같다.- 다른 언어(Y)를 사용하여 X 언어용 인터프리터나 컴파일러를 작성한다. 예를 들어, 니클라우스 비르트는 최초의 파스칼 컴파일러를 포트란으로 작성했다고 밝혔다.[7]
- X 언어를 위한 인터프리터나 컴파일러가 이미 다른 언어(Y)로 작성되어 있는 경우 이를 활용한다. 스킴이 종종 이런 방식으로 부트스트랩된다.
- 컴파일하려는 언어(X)의 일부 기능만을 사용하여 컴파일러의 초기 버전을 작성한다. 이 방식은 해당 언어의 하위 집합(subset)을 컴파일할 수 있는 다른 컴파일러가 이미 존재할 때 가능하다. 자바, 하스켈, 초기 프리 파스칼 컴파일러 등이 이 방법을 사용했다.
- 컴파일러를 구현할 때 특정 컴파일러에 의존적인 비표준 확장 기능이나 선택적 기능을 사용하지 않고 작성한다. 이렇게 하면 동일한 기본 언어를 지원하는 다른 컴파일러(예: 다른 확장 기능 집합을 지원하는 컴파일러)를 사용하여 컴파일할 수 있다. 예를 들어, C++ 컴파일러인 clang의 주요 부분은 g++와 Microsoft Visual C++ 모두에서 컴파일 가능한 C++의 하위 집합으로 작성되었다.
- X 언어 컴파일러가 이미 존재하는 다른 아키텍처에서 크로스 컴파일한다. C 언어 컴파일러를 다른 플랫폼으로 이식할 때 흔히 사용되며, 초기 부트스트랩 이후의 프리 파스칼에서도 사용되는 방식이다.
- X 언어로 컴파일러를 작성한 뒤, 소스 코드를 직접 손으로 컴파일한다(이 경우 보통 최적화 수준은 낮다). 이렇게 얻은 초기 컴파일러를 사용하여 다시 컴파일러 자신의 소스 코드를 컴파일함으로써 최적화된 컴파일러를 얻는다. 도널드 커누스는 그의 WEB 리터럴 프로그래밍 시스템에 이 방법을 사용했다.
컴파일러를 소스 코드 형태로 배포할 때, 컴파일러의 이식 가능한 바이트코드 버전을 함께 제공하여 사용자가 컴파일러 자체를 컴파일하는 부트스트랩 과정을 수행하도록 할 수도 있다. T-다이어그램은 이러한 컴파일러 부트스트랩 기술을 설명하는 데 사용되는 표기법이다.[6] 때로는 소프트웨어가 거의 없는 시스템에서 복잡한 컴파일러를 구동하기 위해, 비교적 단순한 어셈블러부터 시작하여 점차 더 정교한 어셈블러와 컴파일러를 단계적으로 구축하는 방법이 가장 편리할 수 있다.[8]
최초로 부트스트래핑 기법이 구현된 언어는 넬리악(ALGOL의 방언)이었으며, 상용 구현 중에서는 PL/I이 최초이다.
오늘날에는 C 언어와 같이 시스템 프로그래밍에 적합한 언어의 컴파일러는 해당 언어 자체로 작성되는 경우가 많다. 따라서 아무것도 없는 환경에서는 부트스트래핑이 필요할 수 있지만, 대부분의 경우 바이너리 배포판을 이용하거나 크로스 컴파일을 통해 이 과정을 피할 수 있다. 몇몇 최신 구현의 부트스트래핑 방법은 다음과 같다.
- OCaml: OCaml로 작성된 네이티브 코드 컴파일러는 소스 코드와 함께 바이트코드 형태의 컴파일러도 배포한다.
- 글래스고 하스켈 컴파일러(GHC): 하스켈로 작성되었으며, 중간 언어로 C를 사용하는 옵션을 활용한다. 부트스트래핑을 위해 C 컴파일러로 컴파일할 수 있는 C 소스 코드를 배포한다.
유사한 문제는 파서 생성기처럼 언어 처리 시스템 구현 과정에서 프로그램을 생성하는 프로그램을 사용하는 경우에도 발생할 수 있다.
5. 역사
어셈블러는 스스로를 부트스트랩(bootstrap)하기 위한 첫 번째 언어 도구였다.
최초로 부트스트랩을 구현한 고급 언어는 1958년의 NELIAC이었다. NELIAC은 ALGOL의 한 종류이다. 널리 사용된 초기 사례로는 1961년 Burroughs B5000의 Algol 컴파일러와 1962년 LISP가 있다. 상용 구현 중에서는 PL/I의 구현이 최초였다.
LISP의 경우, 1962년 MIT의 하트(Hart)와 레빈(Levin)이 LISP를 사용하여 LISP 컴파일러를 작성했다. 이들은 기존에 존재하던 LISP 인터프리터 내에서 컴파일러를 테스트했다. 컴파일러가 개선되어 자신의 소스 코드를 컴파일할 수 있는 수준에 이르자, 컴파일러는 자체 호스팅(self-hosting)이 가능해졌다.[9]
이러한 부트스트랩 방식은 컴파일하려는 언어와 동일한 언어로 작성된 인터프리터가 이미 존재할 때 가능하다. 이는 프로그램이 자기 자신을 입력으로 받아 실행하는 개념을 활용한 것으로, 이론 전산학에서 정지 문제가 해결 불가능함을 증명하는 과정(예: 라이스의 정리 활용)에서도 유사한 아이디어가 사용된다.
6. 종류
언어 X로 작성된 컴파일러를 처음 컴파일해야 할 때, 마치 닭이 먼저냐, 달걀이 먼저냐와 같은 문제가 발생한다. 즉, 컴파일러를 컴파일하기 위한 컴파일러가 필요한 상황이다. 이 문제를 해결하기 위해 여러 가지 방법이 사용된다.
6. 1. 해결 방법
X 언어로 작성된 컴파일러를 해당 언어 X로 컴파일해야 할 경우, '어떻게 첫 번째 컴파일러를 만들 수 있는가?'라는 닭이 먼저냐, 달걀이 먼저냐 문제가 발생한다. 이 문제를 해결하기 위해 실제로 사용되는 다양한 방법은 다음과 같다.- 언어 X의 인터프리터나 컴파일러를 다른 언어 Y로 구현한다. 예를 들어, 니클라우스 비르트는 최초의 파스칼 컴파일러를 포트란으로 작성했다고 알려져 있다.[7]
- 언어 X를 위한 다른 인터프리터나 컴파일러가 이미 언어 Y로 작성되어 있는 경우 이를 활용한다. 이는 스킴에서 자주 사용되는 방식이다.
- 언어 X의 일부 기능만을 사용하는 서브셋 컴파일러를 먼저 만들고, 이 서브셋 컴파일러를 이용해 완전한 X 언어 컴파일러를 작성한다. 자바, 하스켈, 초기 프리 파스칼 컴파일러 등이 이 방식으로 부트스트랩되었다.
- 언어 X 컴파일러가 이미 존재하는 다른 플랫폼에서 크로스 컴파일을 통해 새로운 플랫폼용 컴파일러를 생성한다. C 언어 컴파일러를 다른 플랫폼으로 이식할 때 일반적으로 사용되며, 프리 파스칼도 초기 부트스트랩 이후 이 방법을 사용한다.
- 언어 X로 작성된 컴파일러 소스 코드를 사람이 직접 기계어나 어셈블리어로 번역("핸드 컴파일")하여 최초의 컴파일러를 만든다. 도널드 커누스는 그의 문학적 프로그래밍 시스템 WEB에서 이 방식을 사용했다.
- 언어 X의 인터프리터가 이미 구현되어 있다면, 그 인터프리터 상에서 X 언어로 작성된 컴파일러 소스 코드를 실행하여 컴파일러 자체를 컴파일한다. UCSD 파스칼의 P-Code 방식이 이에 해당한다.
컴파일러를 소스 코드 형태로 배포할 때, 이식이 용이한 바이트코드 버전의 컴파일러를 함께 제공하여 사용자가 직접 컴파일러를 빌드(부트스트랩)할 수 있도록 하는 방법도 있다. T-다이어그램은 이러한 컴파일러 부트스트랩 기술을 설명하는 데 사용되는 표기법이다.[6] 때로는 소프트웨어가 거의 없는 시스템에서 복잡한 컴파일러를 구동하기 위해, 비교적 단순한 어셈블러부터 시작하여 점차 더 복잡한 컴파일러를 순서대로 빌드하는 방법을 사용하기도 한다.[8]
7. 셀프 호스팅 컴파일러를 가지고 있는 언어 목록
아래 프로그래밍 언어들은 셀프 호스팅 컴파일러를 가지고 있다:
- Ada
- BASIC
- Burroughs ALGOL
- C
- C++ (컴파일러 : Visual C ++, clang 등)
- C# 및 Visual Basic .NET( Microsoft Roslyn을 통해)
- CoffeeScript
- Common Lisp
- Crystal
- Delphi
- Eiffel
- F#
- FASM
- 팩터
- 팬시
- 프리 파스칼
- 고
- 하스켈
- 자바
- 머큐리
- Modula-2
- 님로드
- 오베론
- OCaml
- 파스칼
- 펄 6 (컴파일러: Rakudo Perl과 Niecza Perl 6 모두 자기 호스팅)
- PL/I
- 파이썬
- 러스트
- 스킴
- 스칼라
- 스몰토크
- SML
- TypeScript
- 발라
- XPL
최초의 부트스트래핑 구현은 넬리악(ALGOL의 일종)이었다. 상용 구현 중에서는 PL/I이 최초이다.
오늘날에는 C 언어처럼 시스템 프로그래밍에 적합한 언어는 해당 언어 자체로 컴파일러를 구현하는 경우가 많아, 아무것도 없는 환경에서는 부트스트래핑이 필요할 수 있다. 하지만 대부분의 환경에서는 바이너리 배포판이나 크로스 컴파일을 이용하므로 이 과정은 생략 가능하다. 몇몇 언어의 부트스트래핑 방법은 다음과 같다.
- OCaml: OCaml로 작성된 네이티브 코드 컴파일러는 소스 코드뿐만 아니라 바이트 코드도 배포한다.
- 글래스고 하스켈 컴파일러: Haskell로 작성되었으며, 부트스트래핑을 위해 중간 언어로 C 언어 코드를 생성하는 옵션을 제공한다. 이 C 코드는 일반적인 C 컴파일러로 컴파일할 수 있다.
파서 생성기처럼 언어 처리 시스템 구현에 사용되는 도구 자체를 해당 언어로 만들 때도 비슷한 문제가 발생할 수 있다.
8. 현재의 노력
신뢰할 수 없는 신뢰 공격(컴파일러가 컴파일하는 프로그램에 은밀한 백도어를 삽입하거나, 심지어 컴파일러 자체의 미래 버전에서 악의적인 수정을 복제하여 영구적인 불신의 순환을 만드는 것을 포함하는 공격)과 같은 보안 문제 및 바이너리 신뢰성에 대한 다양한 공격 때문에, 여러 프로젝트에서는 소스 코드로부터 직접 부트스트랩하는 과정을 단순화하고, 누구나 소스 코드와 최종 실행 파일이 일치하는지 검증할 수 있도록 노력하고 있다. 이러한 노력의 일환으로 부트스트랩 가능한 빌드(Bootstrappable Builds) 프로젝트[10]와 재현 가능한 빌드(Reproducible Builds) 프로젝트[11] 등이 진행 중이다.
참조
[1]
학술지
Bootstrapping a self-compiling compiler from machine X to machine Y
https://dl.acm.org/d[...]
2003-12
[2]
학술회의
Perspectives of Systems Informatics: 8th International Andrei Ershov Memorial Conference, PSI 2011, Novosibirsk, Russia, June 27 – July 1, 2011, Revised Selected Papers
Springer
[3]
웹사이트
Installing GCC: Building
https://gcc.gnu.org/[...]
[4]
웹사이트
rust-lang/rust: bootstrap
https://github.com/r[...]
[5]
웹사이트
Advanced Build Configurations — LLVM 10 documentation
https://llvm.org/doc[...]
[6]
서적
Compilers and Compiler Generators: An Introduction With C++
International Thomson Computer Press
[7]
학술지
50 years of Pascal
Association for Computing Machinery (ACM)
2021-02-22
[8]
웹사이트
Bootstrapping a simple compiler from nothing
http://homepage.ntlw[...]
2003-04-23
[9]
웹사이트
AI Memo 39-The new compiler
ftp://publications.a[...]
2008-05-23
[10]
웹사이트
Bootstrappable builds
https://bootstrappab[...]
[11]
웹사이트
Reproducible Builds — a set of software development practices that create an independently-verifiable path from source to binary code
https://reproducible[...]
[12]
학술지
Compiler bootstrapping and cross-compilation
http://www.currentsc[...]
[13]
웹인용
Installing GCC: Building - GNU Project
https://gcc.gnu.org/[...]
2022-06-03
[14]
웹인용
rust/src/bootstrap at master · rust-lang/rust
https://github.com/r[...]
2022-06-03
[15]
웹인용
Advanced Build Configurations — LLVM 15.0.0git documentation
https://llvm.org/doc[...]
2022-06-03
[16]
서적
Compilers and Compiler Generators: An Introduction With C++
International Thomson Computer Press
[17]
문서
Compiler Construction and Bootstrapping
[18]
웹인용
Bootstrapping a simple compiler from nothing
http://homepage.ntlw[...]
2022-06-03
본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.
문의하기 : help@durumis.com