프로그래밍 언어가 머신 코드로 변환되는 방법
Source: Dev.to
소개
프로그래밍을 통해 계산기, 웹사이트, AI 에이전트 등을 만들 수 있습니다. 하지만 기계는 고수준 프로그래밍 언어를 직접 이해하지 못하고, 이진 코드(0과 1)만 이해합니다. 따라서 각 언어는 실행 전에 반드시 컴파일되거나 인터프리트되어야 합니다.
바이너리가 플랫폼마다 다른 이유
-
CPU 아키텍처 – 각 CPU마다 고유한 명령어 집합이 있습니다.
- Intel/AMD: x86 / x86‑64
- Apple M1/M2: ARM64
- 많은 Android 기기: ARM
-
운영 체제 – 같은 CPU라도 Windows, macOS, Linux는 서로 다른 시스템 API와 라이브러리 형식을 제공합니다.
결과
- Intel x86 CPU용으로 컴파일된 Windows 실행 파일은 ARM CPU가 장착된 Mac에서 실행되지 않습니다.
- Windows‑전용 API(
CreateFile())를 호출하는 Windows 프로그램은 macOS나 Linux에서 사용하는open()을 사용하지 않기 때문에 실행되지 않습니다. - 라이브러리 형식이 다릅니다: Windows는
.dll, macOS는.dylib, Linux는.so를 사용합니다. Windows.exe는 macOS에서 필요한 라이브러리를 찾을 수 없습니다.
비유
윈도우 주방에만 있는 도구를 참조하는 영어 레시피를 생각해 보세요. 그 레시피를 맥 주방의 요리사에게 주면 다음 이유로 실패합니다:
- 단계가 다른 “언어”(CPU 명령어 불일치)로 되어 있습니다.
- 필요한 도구가 존재하지 않습니다(OS 시스템 콜 불일치).
- 재료가 다른 방식으로 저장됩니다(라이브러리 불일치).
따라서 프로그램은 각 대상 플랫폼에 맞게 별도로 컴파일되어야 합니다.
컴파일 전략
직접 컴파일
| 언어 | 출력 |
|---|---|
| C, C++, Rust, Go | 특정 CPU + OS용 기계 코드 |
흐름: Source Code → Compiler → Machine Code (Windows / macOS / Linux)
- 장점: 가장 빠른 실행 속도.
- 단점: 각 플랫폼마다 별도의 바이너리가 필요합니다.
바이트코드 + 가상 머신
| 언어 | 출력 |
|---|---|
| Java, Kotlin, C#, Python | 바이트코드 → VM → 기계 코드 |
흐름: Source → Bytecode → Virtual Machine (VM) → Machine Code
- 장점: 호환되는 VM만 있으면 어떤 OS에서도 실행됩니다.
- 단점: 네이티브 코드보다 약간 느립니다.
인터프리트 + JIT
| 언어 | 출력 |
|---|---|
| JavaScript, Python (PyPy), Ruby | 인터프리터/JIT → 기계 코드 |
흐름: Source → Interpreter/JIT → Machine Code
- JIT(Just‑In‑Time) 컴파일은 순수 인터프리트보다 성능을 향상시킵니다.
트랜스파일
| 언어 | 출력 |
|---|---|
| TypeScript, Elm | 트랜스파일 → JavaScript → JIT → 기계 코드 |
흐름: Source → Transpiler → Target Language (예: JavaScript) → JIT → Machine Code
핵심 요점
우리는 인간에게 친숙한 언어로 코드를 작성하지만, CPU와 운영 체제는 자신들만의 바이너리 “방언”만 이해합니다. 컴파일러, 인터프리터, 가상 머신, JIT 엔진이 우리의 코드를 기계가 실행할 수 있는 형태로 변환해 주는 것입니다.