컴파일은(는) 여기로 연결됩니다.
일본의 게임 회사에 대한 내용은 컴파일(게임 회사) 문서, 일본의 만화에 대한 내용은 컴파일러(만화) 문서
참고하십시오. '''이론 컴퓨터 과학 {{{#!wiki style="display: inline-block; font-family:Times New Roman, serif;font-style:italic"''' | |||||
{{{#!wiki style="margin: 0 -10px -5px; min-height: calc(1.5em + 5px)" {{{#!folding [ 펼치기 · 접기 ] {{{#!wiki style="margin: -5px -1px -11px" | <colbgcolor=#a36> 이론 | ||||
기본 대상 | 수학기초론{수리논리학(논리 연산) · 계산 가능성 이론 · 범주론 · 집합론} · 이산수학(그래프 이론) · 수치해석학 · 확률론 및 통계학 · 선형대수학 | ||||
다루는 대상과 주요 토픽 | |||||
계산 가능성 이론 | 재귀함수 · 튜링 머신 · 람다대수 · 처치-튜링 명제 · 바쁜 비버 | ||||
오토마타 이론 | FSM · 푸시다운 · 튜링 머신(폰노이만 구조) · 정규 표현식 · 콘웨이의 생명 게임 · 형식언어 | ||||
계산 복잡도 이론 | 점근 표기법 · 튜링 기계^고전, 양자, 비결정론적, 병렬 임의접근 기계^ · 알고리즘 · 자료구조 · 알고리즘 패러다임(그리디 알고리즘, 동적 계획법) | ||||
정보이론 | 데이터 압축(무손실 압축 포맷 · 손실 압축 포맷) · 채널 코딩(채널 용량) · 알고리즘 정보 이론(AIT) · 양자정보과학 | ||||
프로그래밍 언어이론 | 프로그래밍 언어(함수형 언어 · 객체 지향 프로그래밍 · 증명보조기) · 메타 프로그래밍 · 유형 이론 · 프로그래밍 언어 의미론 · 파싱 · 컴파일러 이론 | ||||
주요 알고리즘 및 자료구조 | |||||
기초 | 정렬 알고리즘 · 순서도 · 탐색 알고리즘 | ||||
추상적 자료형 및 구현 | 배열^벡터^ · 리스트^연결 리스트^ · 셋(set)^레드-블랙 트리, B-트리^ · 우선순위 큐^힙, 피보나치 힙^ | ||||
수학적 최적화 | 조합 최적화 | 외판원 순회 문제 · 담금질 기법 · 유전 알고리즘 · 기계학습 | |||
볼록 최적화 | 내부점 방법 · 경사하강법 | ||||
선형계획법 | 심플렉스법 | ||||
계산 수론 및 암호학 | 밀러-라빈 소수판별법 · Pollard-rho 알고리즘 · 쇼어 알고리즘 · LLL 알고리즘 · 해시(MD5 · 암호화폐 · 사전 공격(레인보우 테이블) · SHA) · 양자 암호 | ||||
대칭키 암호화 방식 | 블록 암호 알고리즘(AES · ARIA · LEA · Camellia) · 스트림 암호 알고리즘(RC4) | ||||
공개키 암호화 방식 | 공개키 암호 알고리즘(타원 곡선 암호 · RSA) · 신원 기반 암호 알고리즘(SM9) | ||||
계산기하학 | 볼록 껍질 · 들로네 삼각분할 및 보로노이 도형^Fortune의 line-sweeping 알고리즘^ · 범위 탐색^vp-tree, R-tree^ · k-NN | ||||
그래프 이론 | 탐색^BFS, DFS, 다익스트라 알고리즘, A* 알고리즘^ · 에드몬드-카프 · 크루스칼 알고리즘 · 위상 정렬 · 네트워크 이론 | ||||
정리 | |||||
정지 문제대각선 논법 · 암달의 법칙 · P-NP 문제미해결 · 콜라츠 추측미해결 | |||||
틀:이산수학 · 틀:수학기초론 · 틀:컴퓨터공학 | }}}}}}}}} |
[[컴퓨터공학|컴퓨터 과학 & 공학
Computer Science & Engineering
]]- [ 펼치기 · 접기 ]
- ||<tablebgcolor=#fff,#1c1d1f><tablecolor=#373a3c,#ddd><colbgcolor=#0066DC><colcolor=white> 기반 학문 ||수학(해석학 · 이산수학 · 수리논리학 · 선형대수학 · 미적분학 · 미분방정식 · 대수학(환론 · 범주론) · 정수론) · 이론 컴퓨터 과학 · 암호학 · 전자공학 · 언어학(형태론 · 통사론 · 의미론 · 화용론 · 음운론) · 인지과학 ||
하드웨어 구성 SoC · CPU · GPU(그래픽 카드 · GPGPU) · ROM · RAM · SSD · HDD · 참조: 틀:컴퓨터 부품 기술 기계어 · 어셈블리어 · C/C++ · C# · Java · Python · BIOS · 절차적 프로그래밍 · 객체 지향 프로그래밍 · 해킹 · ROT13 · 일회용 비밀번호 · 사물인터넷 · 와이파이 · GPS · 임베디드 · 인공신경망 · OpenGL · EXIF · 마이크로아키텍처 · ACPI · UEFI · NERF · gRPC · 리버스 엔지니어링 · HCI · UI · UX · 대역폭 · DBMS · NoSQL · 해시(SHA · 브루트 포스 · 레인보우 테이블 · salt · 암호화폐) · RSA 암호화 · 하드웨어 가속 연구
및
기타논리 회로(보수기 · 가산기 · 논리 연산 · 불 대수 · 플립플롭) · 정보이론 · 임베디드 시스템 · 운영 체제 · 데이터베이스 · 프로그래밍 언어{컴파일러(어셈블러 · JIT) · 인터프리터 · 유형 이론 · 파싱 · 링커 · 난해한 프로그래밍 언어} · 메타데이터 · 기계학습 · 빅데이터 · 폰노이만 구조 · 양자컴퓨터 · 행위자 모델 · 인코딩(유니코드 · MBCS) · 네트워크 · 컴퓨터 보안 · OCR · 슈퍼컴퓨터 · 튜링 머신 · FPGA · 딥러닝 · 컴퓨터 구조론 · 컴퓨터 비전 · 컴퓨터 그래픽스 · 인공지능 · 시간 복잡도(최적화) · 소프트웨어 개발 방법론 · 디자인 패턴 · 정보처리이론 · 재귀 이론 · 자연어 처리(기계 번역 · 음성인식) · 버전 (버전 관리 시스템 · Git · GitHub)
1. 개요
Compiler컴파일이란 어떤 언어의 코드 전체를 다른 언어로 바꿔주는 과정이다. 그리고 이것을 자동으로 수행해주는 소프트웨어를 컴파일러라고 한다.
코드가 실행되기 전 컴파일러를 거쳐서 기계어로 모두 변환되어 실행되는 프로그래밍 언어를 컴파일 언어라고 한다. 인터프리터 언어와 대조된다.
2. 상세
컴파일러를 엄밀히 말하자면, 어떤 프로그래밍 언어로 쓰인 소스 파일을 다른 프로그래밍 언어로 바꾸어주는 번역기인 셈이다. 어떤 언어 A를 B로 바꾸면 그게 컴파일러다. Scheme을 C언어로 번역한다든지, 심지어 기계어를 C언어로 번역하더라도(!) 컴파일러라고 칭할 수 있다. 하지만 대개의 경우 고수준 언어를 바이트코드나 기계어 등의 저수준 언어로 번역하는 프로그램을 일컫는다. 이 두 개념을 구분하고자 할 경우 전자를 트랜스컴파일러(transcompiler)나 소스간 컴파일러(source-to-source compiler), 후자를 디컴파일러(decompiler)라고 많이 부른다. 어셈블리어를 기계어로 번역하는 프로그램 역시 어셈블리어의 특수성 때문에 따로 어셈블러라 한다.초기엔 프로그램을 작성하기 위해서는 컴퓨터 위에서 바로 돌아가는 기계어를 통하여 프로그래밍을 했다. 그러나 이런 과정은 생산성, 기기 간 호환성,[1] 디버깅 등 모든 면에서 효율적이지 않다. 따라서 컴퓨터과학이 발전하면서 많은 부분을 추상화된 고수준 언어로 작성하고 이를 번역기를 통해 기계어로 번역하기 시작했는데, 이 번역기가 바로 컴파일러이다. 현재 많은 프로그램은 컴파일러를 통하여 전체를 기계어로 번역하여 실행하므로 프로그램 개발에 필수적인 툴 중에 하나다.
한 언어의 컴파일러를 자신의 언어로 재작성하는 것을 부트스트래핑이라고 한다. 재밌는 것은 컴파일러도 결국 하나의 언어로 짜여진 프로그램이라는 점. 따라서 바이너리 포맷의 파일을 쓸 수 있고 트리 자료구조를 생성할 수 있는 언어는 부트스트래핑(bootstrapping)이 가능하다.[2] 범용 목적 프로그래밍 언어는 당연히 이 조건을 만족하므로 부트스트래핑이 가능하다.[3] 일례로 GCC라는 C 컴파일러는 컴파일에 C++을 사용한다. 또 OpenJDK의 컴파일러 모듈인 javac는 Java로 작성되었다. 컴파일러의 최초 버전만 다른 언어용의 컴파일러 또는 어셈블러의 도움을 받아 만들고 나면[4] 컴파일러가 자기 자신의 언어로 짜일 수 있다. 일례로, GHC라는 Haskell 컴파일러는 최초에 Lazy ML이라는 다른 언어로 작성되었다가, 자기 자신의 언어인 Haskell로 재작성되었다.[5] 이런 식으로 거슬러 올라가다 보면, 최초의 어셈블러는 기계어로 만들어졌고 최초의 고급 언어는 어셈블러로 만들어졌음을 알 수 있다.
원칙적으로 컴파일러는 프로그램을 기계어로 바꾸기만 할 뿐 이를 바로 실행이 가능하게 하지는 않는다. 여러 소스 파일에서 나온 결과물을 합치고 라이브러리도 포함시키는 등 별도의 작업을 거쳐야 실행이 가능해지는데 이를 수행하는 프로그램이 링커이다. 하지만 보통은 그냥 뭉뚱그려 컴파일러라 부르는 경우가 많다. 또한 요즘은 그냥 프로그램 하나만 돌리면 컴파일과 링킹을 한 번에 끝낼 수 있게 되어 있다. 물론 내부적으로는 컴파일러와 링커가 따로 있어서 이를 이용하는 경우가 많다.
00년대 초반, 그 이전에는 싱글/듀얼코어 프로세서가 대세라 컴파일 시간에도 상당히 많은 시간을 잡아먹었는데 이를 해결하기 위해 헤더 파일 포함을 이용해 목적 파일을 큰 파일 하나로 모으는 트릭을 사용하기도 했으나, 최근 사용되는 개발자 PC의 경우 쿼드코어는 저사양이고 보통 6~16 혹은 그 이상의 코어를 가진 프로세서를 사용하는 데다, 분산 빌드를 사용하기 때문에 이런 짓은 코드가 짧은 편이 아닌 이상 코드 관리가 힘들어지는 바보짓이 된다. 하나의 매우 매우 긴 소스 파일을 읽는 것보다 파일/기능별로 정리된 코드를 보는 것이 생산성에도 훨씬 좋다. Visual Studio를 비롯해 최근에 나오는 대부분의 컴파일러(IDE)는 멀티 프로세서 컴파일을 지원하기 때문에 코어수가 늘어날수록 병렬로 컴파일 후 링킹하는 것이 훨씬 빠르다. OpenCV 등 대형 오픈 소스 프로젝트를 멀티코어 빌드해보면 CPU를 풀로드로 갈굴 수 있다.
컴파일을 하는 대신, 소스를 한꺼번에 번역하지 않고 명령 하나하나를 실행할 때마다 해석하여 계산하는 방법도 있는데 이 해석기를 인터프리터라 해서 따로 분류한다. 컴파일러가 번역기라면 인터프리터는 통역기인 셈.
인터프리터 언어에 비해 컴파일 언어의 단점은 수정이 용이하지 않다는 점이다. 수정 사항이 발생하면 다시 컴파일을 해야 되는데, 작은 프로그램일 경우에는 문제가 되지 않지만 컴파일이 몇 시간씩 걸리는 덩치 큰 프로그램에서는 문제가 된다. 특히 수정 사항이 빈번하게 발생할 경우에는 큰 문제가 된다. 이 때문에 수정 사항이 빈번하게 발생할 것 같은 부분은 인터프리터를 쓰는 방법으로 따로 빼 두는 기법을 많이 사용한다. 다만 멀티스레딩 프로그래밍이 굉장히 어려운 편(인터프리터는 속도는 느리지만 수정이 간단하다는 장점이 있다). 범용 프로그램 언어가 아닌 인터프리터 언어를 스크립트 언어라고 한다. 보통 Web/매크로/게임 등 특정 분야에 특화/로컬화된 인터프리터 언어들을 이렇게 부른다. 스크립트의 경우는 Lua 등 표준화된 스크립트 언어를 사용하는 경우도 있지만 범용 기계어 컴파일러보다 기능범위/명령어 수가 적기 때문에 회사/단체에서 내부 스크립트를 제작해서 쓰기도 한다.
3. 종류
컴파일러는 다음과 같은 네 분류로 나뉜다.- 원시 코드를 바로 기계어로 변환하는 정적 컴파일(Static Compilation)
- 원시 코드를 바이트코드로 변환하는 바이트코드 컴파일(Bytecode Compilation)
- 바이트코드 등의 중간 코드를 기계어로 변환하는 AOT 컴파일(Ahead-Of-Time Compilation)
- 실행시 최초 한 번에 한해 컴파일을 거치는 JIT 컴파일(Just-In-Time Compilation)
이 중 AOT 컴파일과 JIT 컴파일의 상대적인 특성을 대략적으로 비교하면 아래 그림과 같다.
요즘 컴파일러들은 기계가 프로그램을 빠르게 돌릴 수 있도록 적절한 최적화 작업을 하고 프로그래머가 실수할만한 부분을 경고하는데다 편집기와 연동하여 패턴 학습/코드 추천 등 갈수록 똑똑해지는 추세이다.
프로그래머가 할 수 있는 어렵다고 알려진 작업이 컴파일러, OS, 게임 엔진, 웹 브라우저 엔진, 딥러닝 프레임워크 제작이다.[6] 컴파일러는 컴퓨터과학 학부과정 커리큘럼의 3, 4학년에 있는 과목이다. 컴파일러를 제작하려면 컴퓨터구조와 소프트웨어를 전부 이해하고 있어야 하고 자료구조와 알고리즘에 대한 심도 깊은 이해와 함께 이산수학에도 능해야 한다. 컴파일러를 제작하고 LLVM같은 오픈 소스에 기여할 수 있을 정도의 실력이라면 글로벌 탑티어 IT 기업에 쉽게 들어갈 정도의 실력이 된다. 거기서 더 나간 스킬 트리로는 프로그램 최적화가 있는데 이건 컴파일러의 보조 스킬.
기계어를 다시 프로그래밍 언어로 바꾸는 디컴파일이라는 용어도 있다. 사실 컴파일 과정에서 소스 코드의 일부 정보를 지워버리기 때문에 완전한 디컴파일은 불가능하다. 대체로 Java/C# 등 VM기반 언어는 디컴파일시 손실되는 정보가 적은 편[7]이고 C/C++의 경우 컴파일 프로필이 '릴리즈' 모드일 경우 거의 모든 인터페이스 정보가 손실된다. 이를 디컴파일하는 것은 사실상 어셈블리를 분석하여 그에 맞는 C/C++ 코드를 역산하는 리버스 엔지니어링을 인공지능으로 하는 것에 가깝다. 간혹 프로필을 '디버그'로 둔 채 그대로 릴리즈해버린 경우가 있는데 이 경우에는 디컴파일시 꽤 많은 정보가 보존되어 나온다. 하지만 대개 지역변수 이름 같이 지역성이 명백하고 기계에게 필요없는 정보는 날아가는 편이다.
4. 크로스 컴파일러
호스트와 다른 CPU나 운영체제에서 작동하는 실행코드를 만들어주는 컴파일러. 예를 들자면 ARM에서 구동시킬 실행파일을 x86-64 리눅스/윈도우 환경에서 컴파일 및 링크하는 것을 말한다. 보통 임베디드 시스템에서 작동시킬 실행파일을 만들 때 사용한다. 주된 이유는 속도와 생산성 때문. 컴파일 과정은 CPU 작업을 상당히 많이 요구하며, 임베디드 시스템은 CPU 성능이 떨어지고 메모리가 협소하기 때문에 고성능 컴퓨터에서 편리하게 코드를 편집하고 컴파일 작업을 진행하는 것이 훨씬 더 빠르고 생산성이 좋다. 486~586 수준의 임베디드 시스템 내에서 직접 컴파일하는 것도 가능하지만, 고성능 x86-64 머신을 사용하는 게 20배 이상 빠르다. 물론 슈퍼컴퓨터용 바이너리를 8086에 DOS 같은 구닥다리에서 컴파일해 만들어도 크로스 컴파일이다.Android나 iPhone에서 작동하는 앱을 만들기 위해 윈도우나 iMac에서 개발도구로 실행파일을 만들어내는 것은 모두 크로스 컴파일에 속한다.
5. intrinsic
C 등의 고급 언어에서 CPU의 인스트럭션 하나로 해결할 수 있는 복잡한 기능(?)을 사용할 경우 특정 함수를 호출하면 컴파일러가 함수를 호출하는 명령을 넣어주는 것이 아니라 그냥 그 자리에 어셈블리를 사용한 것과 동일하게 기계어 코드를 직접 넣어주는 함수(처럼 생긴 예약어)가 있는데 이것을 intrinsic, 혹은 built-in function이라고 한다(인라인 함수와는 다르다). Compare-And-Exchange[8]의 예를 들어 a값이 m인 경우 n으로 바꾸는 코드는 x86 CPU에서 cmpxchg 인스트럭션 하나로 해결이 가능하다. 이러한 명령은 컴파일러가 지원하는 인트린식을 사용하면 된다. RISC에서 pseudoinstruction[9]을 사용하는 것과 반대의 개념으로 볼 수 있다.컴파일러별로, 그리고 아키텍처별로 지원하는 인트린식이 다르니 사용을 원하면 컴파일러 매뉴얼을 참조하면 된다.
#!syntax cpp
int a, b;
...
b = CAS(&a, 10, 20);
....
- C 코드
{{{#!syntax cpp
{
int oldpos = *pos;
if(*pos == oldval)
}if(*pos == oldval)
* pos = newval;
return oldpos;}}}
- 어셈블리 코드(x86-64)
{{{CAS:
movl %edx, %eax
lock
cmpxchgl %esi, (%rdi)
ret
- 어셈블리 코드(x86 32비트) (built-in function을 사용하지 않은 경우)
{{{CAS:
mov ecx, dword ptr[esp + 4]
mov eax, dword ptr[ecx]
push eax;
mov ebx, dword ptr[esp + 12];
cmp ebx, eax;
jne endpoint;
mov dword ptr[ecx], dword ptr[esp + 16];
pop eax;
ret 16;
}}}ret 16;
- 어셈블리 코드(x86) (built-in function을 사용한 경우)
{{{CAS:
mov ecx, dword ptr[esp + 4]
mov eax, dword ptr[ecx]
mov ebx, dword ptr[esp + 8];
mov edx, dword ptr[esp + 12];
cmpxchg ebx, edx;
mov dword ptr[ecx], esp;
ret 16;
- VC++ intrinsic
{{{#!syntax cpp
}}}
- gcc built-in function
{{{#!syntax cpp
}}}또 다른 예제로 popcount를 들 수 있다. 정수형의 값에서 1로 세트된 비트를 세는 것이다.
{{{#!syntax cpp
printf("%d %d\n", popcount(0x0000FFFF), popcount(0x00000001));16 1
}}}
- C 코드
{{{#!syntax cpp
{
int i, cnt = 0;
for(i = 0; i < sizeof(unsigned int) * 8; i++)
{
return cnt;
}for(i = 0; i < sizeof(unsigned int) * 8; i++)
{
/* i번째 비트가 1이면 cnt 증가 */
if(((a >> i) & 1) == 1) cnt++;
/* cnt += (a>>i) & 1; ^^; */
}if(((a >> i) & 1) == 1) cnt++;
/* cnt += (a>>i) & 1; ^^; */
return cnt;
}}}
- gcc built-in function
{{{#!syntax cpp
{
return __builtin_popcount(a);
}}}}
인텔의 x86 CPU는 삼각함수나 로그 등의 실수연산을 CPU가 바로 지원해주기 때문에 x86용 컴파일러는 대부분의 수학 함수를 인트린식으로 지원한다.
6. 목록
7. 관련 사이트
- Godbolt Compiler Explorer: 온라인으로 각종 언어의 컴파일러를 사용해 코드를 컴파일해볼 수 있는 사이트이다.
- 류갓닷컴: 온라인으로 170개가 넘는 언어의 컴파일러, 인터프리터를 리눅스 터미널과 함께 제공한다.
8. 컴파일러 개론
2021년 튜링상을 수상한 제프리 울만(Jeffrey D. Ullman), 알프레드 에이호(Alfred V. Aho)의 'Compilers: Principles, Techniques, and Tools' 이른바 드래곤책이 유명하다. 현재 2판까지 나왔다. 전산학과 학부생들이 배운다.1판 | 2판 |
- 컴파일러 구조(Compiler structure)
- 어휘 분석(정규 표현식 및 유한 오토마타 포함)(Lexical analysis (including regular expressions and finite automata))
- 구문 분석(문맥 없는 문법,LL 파서,상향식 파서,LR 파서 포함)(Syntax analysis (including context-free grammars, LL parsers, bottom-up parsers, and LR parsers))
- 구문 지향 번역(Syntax-directed translation)
- 유형 검사 (유형 변환 및 다형성 포함)(Type checking (including type conversions and polymorphism))
- 런타임 환경((매개변수 전달,기호 테이블 및 레지스터 할당 포함)(Run-time environment (including parameter passing, symbol tables and register allocation))
- 코드 생성(중간 코드 생성 포함)(Code generation (including intermediate code generation))
- 코드 최적화(Code optimization)
- 직접적인 번역(Directed translation)
- 새로운 데이터 흐름 분석(New data flow analyses)
- 병렬 머신(Parallel machines)
- 가비지 컬렉션(Garbage collection)
- 새로운 사례 연구(New case studies)
9. 관련 문서
[1] 예를 들어서 ARM 아키텍처 대상으로 작성된 프로그램은 x86 아키텍처에서 안돌아가는 식으로.[2] 트리 자료구조를 사용하지 않는다면 어셈블러에 해당하며, 고수준 언어를 컴파일할 수는 없다.[3] 그렇지 않은 일부 특수 목적 언어는 영원히 다른 언어의 도움을 받아야 한다.[4] 또는 다른 아키텍처상에서 구동하는 크로스컴파일러로[5] https://en.wikipedia.org/wiki/Glasgow_Haskell_Compiler[6] 웹 브라우저 엔진도 2010년대 오면서 OS급의 복잡성을 자랑하게 되었지만 엔진이 대부분 오픈 소스인 고로 자체개발이 목적이 아니면 그냥 끌리는 거 하나 퍼서 쓰면 된다(...).[7] 컴파일 프로필에 따라 완전한 소스 코드 복구까지 가능할 정도.[8] Compare-And-Swap이라고도 하며 줄여서 CAE 또는 CAS라고 부른다. 이는 멀티 쓰레딩이나 멀티 프로세싱에서 같은 메모리를 동시에 수정할 때 동기화 문제를 해결하기 위해 현대의 대부분의 CPU에서 지원하는 원자적인(atomic) 명령어이다.[9] 어셈블리 명령어는 있지만 실제 바이너리를 까보면 어러 명령어의 집합으로 나오는 경우