Этапы сборки программы си

Компиляция программы на языке C представляет собой многоэтапный процесс. На общем уровне процесс можно разделить на четыре отдельных этапа: предварительная обработка, компиляция, сборка и связывание .

В этом посте я пройдусь по каждому из четырех этапов компиляции следующей программы на C:

/* * «Hello, World!»: A classic. */ #include int main(void) < puts(«Hello, World!»); return 0; >

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

Первый этап компиляции называется предварительной обработкой. На этом этапе строки, начинающиеся с символа # , интерпретируются препроцессором как команды препроцессора. Эти команды образуют простой макроязык со своим собственным синтаксисом и семантикой.

Этот язык используется для уменьшения количества повторений в исходном коде за счет предоставления функций для встроенных файлов, определения макросов и условного пропуска кода.

Прежде чем интерпретировать команды, препроцессор выполняет некоторую начальную обработку. Это включает в себя объединение непрерывных строк (строки, заканчивающиеся на ) и удаление комментариев.

A 05 Компиляция и линковка (Васюков А.В., 2019)

Чтобы распечатать результат этапа предварительной обработки, передайте параметр -E в gcc:

gcc -E hello_world.c

Учитывая «Hello, World!» Например, выше, препроцессор создаст содержимое заголовочного файла stdio.h , объединенного с содержимым файла hello_world.c , лишенного начального комментария:

Сборник

Второй этап компиляции довольно путано называется компиляцией. На этом этапе предварительно обработанный код транслируется в инструкции сборки, характерные для целевой архитектуры процессора. Они образуют промежуточный читаемый человеком язык.

Существование этого шага позволяет коду C содержать встроенные ассемблерные инструкции и использовать разные ассемблеры.

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

Чтобы сохранить результат этапа компиляции, передайте параметр -S в gcc:

gcc -S hello_world.c

Это создаст файл с именем hello_world.s , содержащий сгенерированные инструкции по сборке.

сборка

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

Чтобы сохранить результат этапа сборки, передайте параметр -c в gcc:

gcc -c hello_world.c

Выполнение приведенной выше команды создаст файл с именем hello_world.o , содержащий объектный код программы.

Связывание

Объектный код, сгенерированный на этапе сборки, состоит из машинных инструкций, понятных процессору, но некоторые части программы вышли из строя или отсутствуют. Чтобы создать исполняемую программу, необходимо переставить существующие части и заполнить недостающие. Этот процесс называется связыванием.

Читайте также:
Составить программу вычисления значения функции у от аргумента х

Сборка проекта С++

Компоновщик упорядочит части объектного кода так, чтобы функции в одних частях могли успешно вызывать функции в других. Также будут добавлены части, содержащие инструкции для библиотечных функций, используемых программой. В случае «Hello, World!» программа, компоновщик добавит объектный код для функции puts .

Результатом этого этапа является окончательная исполняемая программа. При запуске без параметров cc назовет этот файл a.out . Чтобы назвать файл по-другому, передайте параметр -o в gcc:

gcc -o hello_world hello_world.c

Источник: digitrain.ru

Этапы сборки программы си

Лекция 18. Сборка Си-программы

Лекция из курса:

Поделиться:

Лекция 18. Сборка Си-программы

1 / Загрузка

Скачать конспект лекции

Предыдущая лекция

Лекция 17. Элементы системы программирования

Следующая лекция

Лекция 19. Динамические библиотеки. Динамическое связывание

Работа с утилитой make

Для понятности я опишу логику работы утилиты make с этим Makefile: сначала проверяется наличие файла main.o – первой зависимости у цели kv. Если его нет, то выполняется его компиляция, если есть, то проверяется, не был ли изменен файл main.c с момента последней его компиляции (вот зачем нужно указывать main.c как зависимость для main.o!). Если он был изменен, он компилируется заново. Если же он не был изменен, то просто пропускается; таким образом при повторной сборке можно значительно сократить затрачиваемое время.

Далее та же проверка происходит и для kvadrat.o, и как только будут получены main.o и kvadrat.o, включающие все изменения в исходном коде, начнется сборка исполняемого файла.

Итак, сохраните Makefile и запустите make. Должны появиться два .o-файла и сам исполняемый файл kv. Для проверки запустите его:

Теперь давайте добавим в Makefile еще одну цель: clean. При вводе make clean должны удаляться три полученных в результате компиляции файла. Допишите в конец Makefile такие строки:

Сохранив Makefile, введите make clean. Все три двоичных файла будут удалены.

Теперь создадим последнюю цель – install. Она будет служить для копирования двоичного файла программы в системный каталог.

Тут есть несколько вариантов. Во-первых, можно сделать так, чтобы при выполнении make install проверялось, была ли уже скомпилирована программа, и если нет, то перед установкой выполнялась бы ее компиляция (логично, не правда ли?). Это можно сделать, указав kv в качестве зависимости.

Читайте также:
Как узнать об обновлениях программ

Во-вторых, для копирования программы в системный каталог можно использовать или традиционный метод – утилиту cp, а можно – специально предназначенную для этого программу install. Она может при установке заодно изменять права доступа к программе, удалять из нее отладочную информацию (но мы это уже предусмотрели при помощи команды strip); нам же понадобится такая возможность, как автоматическое создание каталогов по указанному пути.

Возможно, это звучит запутанно, так что я поясню. Мы установим программу в каталог /opt/kv/ (каталог /opt предназначен для хранения пользовательских программ, необязательных для функционирования системы). Разумеется, этого каталога еще не существует, поэтому, если бы мы использовали для установки команду «cp kv /opt/kv/», это привело бы к ошибке. Если же использовать команду install с ключом -D, она автоматически создаст все отстутствующие каталоги. Кроме того, нам нужно будет сделать так, чтобы никто, кроме root, не мог выполнять программу, а смог только считывать ее файл (права доступа r-xr—r—, или 544 в восьмеричном виде).

Добавьте в конец Makefile следующие строки:

install -D -m 544 kv /opt/kv/kv

Запустите make install, затем введите команду:

чтобы убедиться в правильности установки.

После параметра -m у команды install указываются права доступа, предпоследним параметром – файл, который нужно скопировать, последним параметром является каталог назначения с именем файла (т.е. исполняемый файл можно установить под другим именем, введя, например, /opt/kv/program_name в качестве последнего параметра).

Теперь поговорим о переменных. Представьте, что вам нужен Makefile для более сложного проекта, где в каталог назначения копируется одновременно несколько файлов. Вы укажете путь установки для каждого из них, например, так:

install /opt/kv/file2 и т.д.

Но вдруг вам потребовалось изменить путь установки. Вам придется поменять параметр у каждой команды. И хотя это можно сделать относительно быстро при помощи команды «заменить» в текстовом редакторе, проще всего определить переменную один раз в начале Makefile и потом использовать ее (при необходимости изменяя только ее значение). Добавьте в начало Makefile определение переменной:

И затем измените команду install таким образом:

Читайте также:
Как создать свой мультизагрузочный диск с программами

install -D -m 544 kv $(INSTALL_PATH)/kv

На что здесь нужно обратить внимание:

  • в объявлении переменной указывается просто ее имя, а когда вы ее используете – знак $ и имя;
  • если имя переменной состоит более чем из одного символа, при ее использовании нужно заключать такое имя в скобки;
  • нужно или нет ставить косую черту в значении переменной (/opt/kv/ или /opt/kv)? Ответ: лучше перестраховаться и поставить. Как вы можете заметить, в команде установки косая черта идет подряд дважды: /opt/kv//kv (одна косая черта из значения переменной, другая – из записи $(INSTALL_PATH)/kv). Это не приведет к ошибке – вы можете поставить символ «/» хоть десять раз подряд. А вот если забудете поставить ее хотя бы один раз, то результаты, ясное дело, будут отличаться от ожидаемых.

Теперь рассмотрим такой момент: допустим, нужно выполнить некоторую команду и присвоить переменной выводимое этой командой значение. Например, если для разных версий ядра Linux существуют разные версии вашей программы. В таком случае при выполнении установки программы на системе с ядром 2.6.1 можно установить ее в каталог /opt/kv/2.6.1/, а если система запущена с ядром 2.4.24 – в каталог /opt/kv/2.4.24/. Версию ядра можно определить при помощи команды uname -r (попробуйте выполнить ее, чтобы посмотреть вашу версию ядра). Вопрос в том, как же передать полученное значение переменной? Очень просто:

INSTALL_PATH = /opt/kv/`uname -r`/

Теперь установка будет производиться в каталог /opt/kv/версия_вашего_ядра/. Обратите внимание на косые кавычки: они вводятся при помощи Shift+~ (крайняя левая клавиша в ряду кнопок с цифрами).

И последнее: а ведь make может использоваться не только для компиляции программ! Например, можно использовать Makefile для сборки документации, да и вообще для автоматизации любой работы. Для примера можно создать программу, которая по команде make автоматически определяет, какие из трех файлов с именами «1», «2», «3» изменились, и при необходимости выполняет их резервное копирование в каталог backup, а по окончании работы выводит сообщение «Backup completed»:

backup: backup/1 backup/2 backup/3

Домашнее задание для вас: разберитесь, как работает этот пример, а к первому добавьте цель uninstall, так, чтобы при выполнении команды make uninstall установленная программа удалялась.

Источник: samag.ru

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru