Компиляция — процесс перевода программного кода¶
Компиляция — процесс перевода исходного кода компьютерной программы, написанного на языке программирования высокого уровня, в эквивалентный программный код на более низком уровне (обычно в машинный код), пригодный для выполнения процессором. Программа, выполняющая эту функцию, называется компилятором. Термин происходит от англ. to compile — «составлять, собирать».
¶Принцип работы
Компилятор осуществляет последовательное преобразование текста программы. На вход подаётся исходный файл (или набор файлов) с кодом на исходном языке, на выходе — объектный модуль, содержащий машинные инструкции, либо исполняемый файл. Между этими точками выполняется ряд стадий:
- Лексический анализ — исходный текст разбивается на лексемы (токены): идентификаторы, ключевые слова, операторы, константы.
- Синтаксический анализ — построение синтаксического дерева (AST) на основе грамматики языка; проверка соответствия кода синтаксическим правилам.
- Семантический анализ — проверка типов, области видимости переменных, корректности ссылок на функции и переменные.
- Оптимизация — преобразования, улучшающие эффективность результирующего кода: удаление недостижимого кода, свёртка констант, разворачивание циклов, инлайнизация функций.
- Генерация кода — трансляция оптимизированного представления в машинный код целевой архитектуры (x86, ARM, RISC-V и др.).
¶Однопроходные и многопроходные компиляторы
Однопроходные компиляторы обрабатывают исходный текст за один проход, преобразуя его фрагменты по мере чтения. Такой подход прост и экономит память, но ограничивает возможности оптимизации и требует, чтобы объявления предшествовали использованию. Многопроходные компиляторы строят внутреннее представление программы и работают с ним на нескольких этапах, что позволяет выполнять более сложные преобразования. Большинство современных компиляторов — многопроходные.
¶JIT-компиляция
Компиляция во время выполнения (JIT, от англ. just-in-time) — метод, при котором отдельные фрагменты программы компилируются непосредственно в момент исполнения. Используется в виртуальных машинах Java (JVM), .NET CLR, в интерпретаторах JavaScript (V8, SpiderMonkey). JIT-компилятор сочетает преимущества интерпретации (портабельность, отсутствие стадии предварительной сборки) и компиляции (высокая скорость выполнения), компилируя «горячие» участки кода — те, которые выполняются наиболее часто.
¶Компиляция и интерпретация
Альтернатива компиляции — интерпретация, при которой исходный код выполняется построчно без предварительного перевода в машинный код. Интерпретатор проще в реализации и удобен для отладки, однако программы, как правило, работают медленнее. На практике часто используются гибридные схемы: код компилируется в промежуточное байт-кодное представление, которое затем исполняется интерпретатором или JIT-компилятором. Примеры таких языков — Python, Ruby, PHP.
¶Компиляторы и транспайлеры
Не все инструменты, переводящие код с одного языка на другой, являются классическими компиляторами. Транспайлер (компилятор с исходного языка на другой язык высокого уровня) генерирует читаемый код, а не машинный: например, TypeScript компилируется в JavaScript, CoffeeScript — также в JavaScript, Emscripten транслирует C и C++ в WebAssembly. Результат работы транспайлера обычно подвергается дальнейшей обработке стандартным компилятором целевого языка.
¶Известные компиляторы
| Компилятор | Язык | Разработчик |
|---|---|---|
| GCC | C, C++, Fortran, Ada | Проект GNU |
| Clang / LLVM | C, C++, Objective-C | LLVM Project, Apple |
| MSVC | C, C++ | Microsoft |
| rustc | Rust | Mozilla, сообщество Rust |
| javac | Java | Oracle |
| Go compiler | Go |
¶Стандарты и спецификации
Для ряда языков существуют официальные спецификации, которым обязаны следовать все компиляторы. Например, стандарт ISO C++ определяет семантику языка, а тестовый набор test suite (например, «Abi Tests» и «Compile Fail Tests») позволяет проверить корректность реализации. Отклонения от стандарта считаются ошибками компилятора, хотя на практике существуют расширения и диалекты (GNU C++, MSVC extensions).
¶Перекрёстная компиляция
Перекрёстная компиляция — создание исполняемых файлов для одной платформы (целевой) с использованием инструментов другой (хостовой). Широко применяется при разработке встраиваемых систем, прошивок, а также при сборке программ для ARM-устройств на x86-компьютерах. Кросс-компилятор содержит генератор кода, настроенный на целевую архитектуру, и набор библиотек целевой среды.
¶Роль в разработке ПО
Компиляция — ключевой этап процесса сборки (build) программного проекта. Системы сборки (Make, CMake, Ninja, Bazel) отслеживают зависимости между файлами и запускают компилятор только для изменившихся модулей, после чего линковщик объединяет объектные файлы в единый исполняемый модуль. Скорость компиляции крупных проектов — важная практическая проблема: например, полная сборка Chromium или LLVM занимает десятки минут даже на мощных машинах, что стимулирует разработку инкрементальных и распределённых систем сборки.
¶История
Первым работающим компилятором считается A-0, созданный Грейс Хоппер в 1952 году для машины UNIVAC I. Он переводил символический код в машинный. Развитие компиляторов тесно связано с созданием языков Fortran (1957, IBM), COBOL, ALGOL, что заложило основы современного понимания структуры компилятора и методов оптимизации.
¶Источники
- Дональд Кнут. «Основы программирования» (Том 1–3)
- Альфред Ахо, Мони Лам, Рави Сети, Jeffrey Ullman. «Компиляторы: принципы, технологии и инструменты»
- Steven Muchnick. «Advanced Compiler Design and Implementation»
- Спецификации языков C++, Rust, Java (официальные документации)
