Открыть сервис

Компиляция и линковка

Компиляция и линковка — это два последовательных этапа обработки исходного кода программы, в результате которых создаётся исполняемый файл или библиотека. Компиляция преобразует текст, написанный на языке программирования высокого уровня, в машинный код (или промежуточное представление), а линковка (компоновка) связывает отдельные объектные файлы и библиотеки в единый исполняемый модуль. Эти процессы являются основой сборки программного обеспечения в большинстве компилируемых языков (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.

Процесс линковки в деталях

Линковщик выполняет следующие шаги:

  1. Сборка входных файлов: чтение объектных файлов и библиотек.
  2. Разрешение символов: поиск определений для всех неразрешённых ссылок (например, вызовов функций). Если символ не найден, возникает ошибка линковки.
  3. Секционирование: группировка кода, данных и других секций из разных объектных файлов.
  4. Релокация: корректировка адресов в машинном коде с учётом окончательного расположения секций в памяти.
  5. Генерация выходного файла: запись исполняемого файла или библиотеки.

Различия между компиляцией и линковкой

ХарактеристикаКомпиляцияЛинковка
Входные данныеИсходный код (текст)Объектные файлы, библиотеки
Выходные данныеОбъектный файлИсполняемый файл или библиотека
Разрешение ссылокЧастичное (внутри модуля)Полное (между модулями)
Зависимость от платформыВысокая (язык, архитектура)Высокая (формат файла, ОС)
ОшибкиСинтаксические, типовыеНеразрешённые символы, дублирование

Применение

Компиляция и линковка используются в большинстве компилируемых языков для создания:

  • Исполняемых программ (приложения, утилиты).
  • Библиотек (статических и динамических).
  • Модулей ядра (драйверы, загружаемые модули).
  • Встраиваемых систем (где важна оптимизация размера).

В интерпретируемых языках (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 →