Все этапы компиляции на языке C

Что такое компиляция в программировании?

Компиляция — это преобразование исходного кода (удобочитаемого человеком) в машинный код (исполняемый компьютером). … Компилятор берет рецепт (код) для новой программы (написанной на языке высокого уровня) и преобразует этот код в новый язык (машинный язык), понятный самому компьютеру.

этапы компиляции:

  1. Предварительная обработка.

Во время компиляции программы на C компиляция начинается с предварительной обработки директив (например, #include и #define). Препроцессор (cpp — c preprocessor) на самом деле является отдельной программой, но он вызывается компилятором автоматически. Например, команда #include ‹stdio.h› в строке 1 файла helloworld.c сообщает препроцессору прочитать содержимое системного заголовочного файла stdio.h и вставить его непосредственно в текст программы. В результате получается другой файл, обычно с суффиксом .i. На практике предварительно обработанный файл не сохраняется на диск, если не используется параметр -save-temps.

Это первый этап процесса компиляции, на котором раскрываются директивы препроцессора (наиболее распространены макросы и заголовочные файлы). Для выполнения этого шага gcc выполняет внутреннюю команду.

[root@host ~]# cpp helloworld.c › helloworld.i

В результате получается файл helloworld.i, содержащий исходный код со всеми развернутыми макросами. Если вы выполните приведенную выше команду изолированно, то файл helloworld.i будет сохранен на диск, и вы сможете просмотреть его содержимое с помощью vi или любого другого редактора, который есть на вашем компьютере с Linux.

2. Компиляция.

На этом этапе происходит собственно компиляция. Компилятор (ccl) переводит helloworld.i в helloworld.s. Файл helloworld.s содержит ассемблерный код. Вы можете явно указать gcc преобразовать helloworld.i в helloworld.s, выполнив следующую команду.

[root@host ~]# gcc -S helloworld.i

Параметр командной строки -S указывает компилятору преобразовать предварительно обработанный код в язык ассемблера без создания объектного файла. После создания helloworld.s вы можете увидеть содержимое этого файла. Глядя на ассемблерный код, вы можете заметить, что ассемблерный код содержит вызов внешней функции printf.

3.Assembly
Здесь ассемблер (as) переводит helloworld.s в инструкции машинного языка и генерирует объектный файл helloworld.o. Вы можете вызвать ассемблер самостоятельно, выполнив следующую команду.

[root@host ~]# как helloworld.s -o helloworld.o

Приведенная выше команда сгенерирует helloworld.o, как указано с опцией -o. И полученный файл содержит машинные инструкции для классического «Hello World!» программа с неопределенной ссылкой на printf.

4. Связывание

Это завершающий этап компиляции «Hello World!» программа. На этом этапе объектные файлы связываются для создания окончательного исполняемого файла. Исполняемому файлу требуется много внешних ресурсов (системные функции, библиотеки времени выполнения C и т. д.). Что касается нашего «Hello World!» вы заметили, что она вызывает функцию printf для вывода на консоль сообщения «Hello World!». Эта функция содержится в отдельном предварительно скомпилированном объектном файле printf.o, который нужно каким-то образом объединить с нашим файлом helloworld.o. Компоновщик (ld) выполняет эту задачу за вас. В конечном итоге создается исполняемый файл helloworld. Теперь он готов к загрузке в память и выполнению системой.

Фактическая команда ссылки, выполняемая компоновщиком, довольно сложна. Но все же, если вы достаточно увлечены, вы можете выполнить следующую команду, чтобы создать исполняемый файл helloworld самостоятельно.

[root@host ~]# ld -dynamic-linker /lib64/ld-linux-x86–64.so.2 /usr/lib64/crt1.o /usr/lib64/crti.o /usr/lib64/crtn.o helloworld.o /usr/lib/gcc/x86_64-redhat-linux/4.1.2/crtbegin.o -L /usr/lib/gcc/x86_64-redhat-linux/4.1.2/ -lgcc -lgcc_eh -lc -lgcc -lgcc_eh /usr/lib/gcc/x86_64-redhat-linux/4.1.2/crtend.o -o helloworld
И вы можете поприветствовать вселенную следующим образом:

[root@host ~]# ./helloworld

Выход:

Привет, мир!

Я выполнил приведенную выше команду в системе x86_64 с gcc 4.1.2. Возможно, приведенная выше команда не работает в вашей системе. Все дело в том, что где находятся библиотеки?

Вам не нужно напрямую вводить сложную команду ld — весь процесс компоновки прозрачно обрабатывается gcc при вызове, как показано ниже.

[root@host ~]# gcc helloworld.c -o helloworld

В течение всего процесса компиляции наряду с файлом исходного кода задействованы и другие файлы. Если вы видите самый первый оператор helloworld.c, это #include ‹stdio.h› (включает заголовочный файл). Точно так же при компиляции программы на C вам приходится работать со следующими типами файлов.