# В линкере нет никакой магии

(В оригинале - The Linker Is not a Magical Program)

Удручающе часто (в последний раз – буквально перед написанием этой статьи) программисты представляют процесс преобразования исходного кода в исполняемый файл как-то вот так:

1. Написать (или исправить) исходный код
2. Скомпилировать исходный код в объектные файлы
3. Происходит какое-то чудо
4. Появляется исполняемый файл

На шаге 3, конечно же, происходит линковка. Что же меня в этом так раздражает? Я работал в техподдержке десятилетиями, и постоянно получаю вопросы вроде:

* Линкер сообщает что переменная определена более одного раза
* Линкер сообщает что переменная является неразрешимым символом
* Почему исполняемый файл такой большой.

И все это в перемешку со словами «кажется», «каким-то образом» и с ощущением непередаваемой сложности в голосе. Словно процесс линковки – это что-то столь магическое, что понять его могут только маги и чародеи. Процесс компиляции не вызывает столько вопросов – похоже, что программисты более осведомлены о том, как работают компиляторы, или по крайней мере знают, для чего они нужны.

Линкер – на удивление простая и незатейливая программа. Все, что она делает – это соединяет вместе секции кода и данных из объектных файлов, связывает символьные ссылки с их определениями, выбрасывает неиспользуемые символы из библиотеки и записывает исполняемый файл. И все. Никакой магии. Самая большая и сложная часть – это декодирование и генерирование ужасно переусложненных форматов файлов, что, однако, не меняет самой сущности линкера.

Пусть, например, линкер сообщает, что переменная определена более одного раза. Многие языки имеют как декларации, так и определения. Декларации обычно помещаются в заголовочные файлы:

```
extern int iii;
```

Таким образом создаются внешние ссылки на символ iii. Определение же создает само хранилище для этого символа, появляясь обычно непосредственно в коде, и выглядит примерно вот так:

```
int iii = 3;
```

И таких определений может быть только одно. А что, если определение появится в более чем одном файле?

```
// File a.c
int iii = 3;
```

```
// File b.c
double iii(int x) { return 3.7; }
```

Линкер сообщит о том, что символ iii определен более одного раза.

Если же iii встречается только в виде деклараций, то линкер сообщит о том, что iii является неразрешенной ссылкой.

Чтобы определить, почему размер исполняемого файла такой, каким получился, нужно взглянуть на файл .map, обычно генерируемый линкером. Этот файл – ничего более, чем список всех символов в исполняемом файле вместе с их адресами в памяти. Это покажет вам, какие модули были добавлены, и размеры каждого модуля. Теперь вы знаете, что «раздуло» ваш исполняемый файл. Часто вы не будете представлять, какая часть и где использует тот или иной «непонятный» модуль. Чтобы выяснить это, просто удалите подозрительный модуль из библиотеки и еще раз запустите сборку. Неразрешенные символы покажут, кто ссылается на этот модуль.

И хотя не всегда сообщения линкера столь просты и очевидны, в них нет ничего магического. Механизм всего этого очень простой, вам всего лишь нужно уточнить детали в каждом конкретном случае.

Автор оригинала - [Walter Bright](http://creativecommons.org/licenses/by/3.0/us/)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://97-things-every-x-should-know.gitbook.io/97-things-every-programmer-should-know/ru/thing_03.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
