Компиляция и линковка¶
Компиляция и линковка — это два последовательных этапа обработки исходного кода программы, в результате которых создаётся исполняемый файл или библиотека. Компиляция преобразует текст, написанный на языке программирования высокого уровня, в машинный код (или промежуточное представление), а линковка (компоновка) связывает отдельные объектные файлы и библиотеки в единый исполняемый модуль. Эти процессы являются основой сборки программного обеспечения в большинстве компилируемых языков (C, C++, Rust, Go, Pascal и других).
¶История
Первые компиляторы появились в 1950-х годах. Одним из первых был компилятор для языка Fortran, созданный командой IBM под руководством Джона Бэкуса (1957 год). Тогда компиляция и линковка часто выполнялись как единый этап, без явного разделения. С развитием модульного программирования и появлением раздельной компиляции (например, в языке C в 1970-х годах) возникла необходимость в отдельном этапе линковки. Линковщики (linkers) начали развиваться как самостоятельные инструменты, такие как ld (Unix) и LINK (MS-DOS). В 1980-х годах появились динамические библиотеки, что потребовало усложнения линковщиков для поддержки динамической компоновки во время выполнения.
¶Этапы сборки программы
Сборка программы из исходного кода обычно включает несколько стадий, хотя в современных средах разработки они могут быть автоматизированы.
¶Препроцессирование (для C/C++)
На этом этапе обрабатываются директивы препроцессора (например, #include, #define). Препроцессор вставляет содержимое заголовочных файлов, заменяет макросы и удаляет комментарии. Результат — чистый код на языке C/C++ без директив.
¶Компиляция
Компилятор преобразует исходный код (часто после препроцессирования) в объектный файл (обычно с расширением .o на Unix или .obj на Windows). Объектный файл содержит машинный код, но не является готовым к запуску: в нём присутствуют неразрешённые ссылки на внешние функции и переменные (например, вызовы printf или функций из других модулей). Компиляция выполняется для каждого исходного файла отдельно.
¶Линковка (компоновка)
Линковщик (компоновщик) собирает все объектные файлы и библиотеки, разрешает внешние ссылки (связывает вызовы функций с их реализациями), распределяет адреса в памяти и создаёт единый исполняемый файл (например, a.out, exe, dll или so). Линковка может быть статической или динамической.
¶Типы линковки
¶Статическая линковка
При статической линковке код из библиотек копируется непосредственно в исполняемый файл. Это делает программу самодостаточной (не требует наличия библиотек в системе), но увеличивает размер файла и усложняет обновление библиотек (нужно перекомпилировать программу). Пример: статическая библиотека .a (Unix) или .lib (Windows).
¶Динамическая линковка
При динамической линковке библиотеки (например, .so в Linux, .dll в Windows, .dylib в macOS) подключаются во время загрузки программы или во время выполнения. Исполняемый файл содержит только ссылки на библиотеки. Это уменьшает размер программы, позволяет обновлять библиотеки независимо, но требует их наличия в системе. Динамическая линковка бывает двух типов:
- Линковка во время загрузки (load-time linking): библиотеки загружаются автоматически при запуске программы.
- Линковка во время выполнения (runtime linking): программа сама загружает библиотеки через системные вызовы (например,
dlopenв Linux,LoadLibraryв Windows).
¶Виды компоновщиков
Компоновщики различаются по функциональности и платформе:
- GNU ld — стандартный компоновщик в Unix-подобных системах, часть пакета binutils.
- LLVM lld — быстрый компоновщик из проекта LLVM, поддерживает многие форматы (ELF, COFF, Mach-O).
- Microsoft LINK — компоновщик из Visual Studio, работает с форматом PE (Portable Executable).
- Gold — ещё один компоновщик от GNU, оптимизированный для скорости.
- Mold — современный сверхбыстрый компоновщик, написанный на C++.
¶Форматы объектных файлов
Объектные и исполняемые файлы имеют определённые форматы, которые описывают структуру данных:
- ELF (Executable and Linkable Format) — основной формат в Linux и многих Unix-системах.
- PE (Portable Executable) — формат Windows (исполняемые файлы
.exe, динамические библиотеки.dll). - Mach-O — формат macOS и iOS.
- COFF (Common Object File Format) — устаревший формат, использовался в Unix и ранних версиях Windows.
¶Процесс линковки в деталях
Линковщик выполняет следующие шаги:
- Сборка входных файлов: чтение объектных файлов и библиотек.
- Разрешение символов: поиск определений для всех неразрешённых ссылок (например, вызовов функций). Если символ не найден, возникает ошибка линковки.
- Секционирование: группировка кода, данных и других секций из разных объектных файлов.
- Релокация: корректировка адресов в машинном коде с учётом окончательного расположения секций в памяти.
- Генерация выходного файла: запись исполняемого файла или библиотеки.
¶Различия между компиляцией и линковкой
| Характеристика | Компиляция | Линковка |
|---|---|---|
| Входные данные | Исходный код (текст) | Объектные файлы, библиотеки |
| Выходные данные | Объектный файл | Исполняемый файл или библиотека |
| Разрешение ссылок | Частичное (внутри модуля) | Полное (между модулями) |
| Зависимость от платформы | Высокая (язык, архитектура) | Высокая (формат файла, ОС) |
| Ошибки | Синтаксические, типовые | Неразрешённые символы, дублирование |
¶Применение
Компиляция и линковка используются в большинстве компилируемых языков для создания:
- Исполняемых программ (приложения, утилиты).
- Библиотек (статических и динамических).
- Модулей ядра (драйверы, загружаемые модули).
- Встраиваемых систем (где важна оптимизация размера).
В интерпретируемых языках (Python, JavaScript) компиляция может отсутствовать или быть скрытой (например, JIT-компиляция), а линковка не применяется в классическом виде.
¶Интересные факты
- Первый компилятор Fortran содержал около 25 000 строк машинного кода и требовал 20 минут на компиляцию простой программы.
- В современных проектах на C++ (например, Chromium или LLVM) время линковки может достигать десятков минут из-за огромного количества объектных файлов.
- Существует техника «инкрементальной линковки», при которой перекомпоновываются только изменённые модули, что ускоряет разработку.
- В некоторых языках (например, Go) компиляция и линковка выполняются одной командой, но внутренне этапы разделены.
- Формат ELF был разработан в Unix System V и принят Linux как стандарт в 1990-х годах.
¶Источники
- Таненбаум Э. С. Архитектура компьютера. — 6-е изд. — СПб.: Питер, 2013.
- Дреппер Д. Линковка и загрузка. — O'Reilly Media, 2000.
- Документация GNU ld (GNU Binutils).
- Спецификация формата ELF (TIS Committee, 1995).
- Стандарт языка C (ISO/IEC 9899:2018).
BFOmetr — база данных и аналитика по компаниям России.
На главную BFOmetr →

