C Урок 20. MAKE. Наш первый Makefile. Часть 1

 

 

 

До сих пор мы для сборки нашей программы пользовались командным файлом, объединяющим в себе команды для препроцессинга, компиляции, ассемблирования, компоновки файлов в исполняемый файл. Так тоже делать можно и зачастую так и делается, если дело касается проектов, которые содержат в себе малое количество модулей, а также не требующих какой-то автоматизации процесса сборки.

Но для более грамотной работы с проектом существуют сценарии, работа с которыми осуществляется в утилите Make.

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

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

Так как мы работаем с системой сборки MinGW, основанной на системе GNU, соответственно, и утилита Make будет также из этой системы.

Авторами GNU make являются Richard Stallman и Roland McGrath. Начиная с версии 3.76, разработкой программы руководит Paul D. Smith.

Чтобы использовать Make, мы даём одноимённую команду в командной строке, либо добавляем её в среду разработки. Так как данная команда расположена в комплекте MinGW в виде исполняемого файла mingw32-make.exe, то мы будем использовать одноимённую команду «mingw32-make». Можно конечно сделать дубликат в папке с данной утилитой и назвать её make.exe для упрощения ввода команды, только мы этого делать не будем во избежание конфликтов имён с другими подобными утилитами, которые вполне могут быть использованы в наших операционных системах. В качестве параметра к данной команде используется обычно имя файла сценария и при этом перед именем данного файла используется ключ -f. Но если назвать файл сценария Makefile или makefile, то никаких ключей и параметров не потребуется, так как это имя файла сценария по умолчанию для make.

В файле сценария обязательно должно присутствовать хотя бы одно правило.

Правило состоит из цели, зависимостей или пререквизитов, обязательных для достижения цели, а также одной или нескольких команд, которые для достижения данной цели будут выполняться.

 

 

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

В качестве команд используются обычные команды оболочки Shell. Все используемые команды будут выводиться в командной строке. Если же мы ходим, чтобы тексты команд не выводились в консоли, то мы используем перед командой символ '@'.

Когда мы запускаем утилиту make с командной строки, то помимо имени файла с ключом мы можем указать имя цели, которую мы хотим выполнить в сценарии. Если не ввести имя цели, то выполнится либо цель с именем all либо самая первая в файле сценария цель.

В качестве пререквизитов (зависимостей) как правило используются другие цели, представляющие собой, как правило, имена файлов. Также могут использоваться и фиктивные цели. Но об этом не в данном уроке.

Чтобы было немного понятнее, давайте поработаем всё-таки с утилитой Make на практике.

Создадим проект, как и прежде, из проекта прошлого занятия с именем MYPROG19 и присвоим ему имя MYPROG20.

Файл build.cmd можно будет теперь удалить. clean.cmd пока оставим.

Тексты исходников не трогаем. Задача наше сегодня — не писать новый код, а использовать существующий, но собрать его мы должны уже с помощью утилиты Make.

Все лишние файлы из папки с нашей программой должны быть удалены, должны остаться только файлы с исходными текстами. Если это не так, то дадим команду clean.

Откроем файл main.c и закомментируем последний код

 

 

А в самом начале вот этот код раскомментируем

 

 

Создадим файл с именем Makefile в каталоге с нашей программой добавим в него вот такой текст

 

 

Мы описали здесь наше первое правило. Не забываем про табуляторы перед командами.

Имя цели у нас main.o, следовательно нашей целью является создание одноимённого файла. Зависимостью служит файл main.c, который должен существовать.

Затем с новой строки, используя табуляцию, мы вводим знакомые нам команды, которые сформируют нам необходимые файлы.

Казалось бы, зачем всё это нужно, если безо всякой цели данные команды и так нам всё сделают. А это мы увидим позже.

Сохраним наш первый файл сценария и введём команду mingw32-make в нашей консоли

 

 

Мы видим текст наших команд в консоли.

Также мы видим, что в каталоге с нашей программой появились сформированные файлы

 

 

Но у нас нет исполняемого файла. Его нет, так как мы его не создавали.

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

 

 

В качестве цели у нас будет имя исполняемого файла нашей программы. Пререквизитом или зависимостью будет цель main.o, чтобы данная цель тоже выполнилась. А затем идёт команда компоновки. Хотя у нас в папке с программой есть ещё модули, но мы их пока не используем. Недаром я расскомментировал самый первый код, где мы не используем функции, реализация которых находится в других модулях.

Сохраним наш сценарий и запустим утилиту, только перед этим дадим команду clean, чтобы остальные файлы у нас тоже сформировались

 

 

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

 

 

Посмотрим, что в папке с проектом также появился и исполняемый файл

 

 

Запустим его, чтобы убедиться, что всё работает

 

 

Отлично! Сценарий работает!

Теперь давайте удалим только исполняемый файл myprog20.exe и запустим утилиту

 

 

И что же мы видим? А видим мы то, что у нас выполнилась только команда линковки и создания исполняемого файла. Объектный файл, а также ассемблерный, заново не пересоздаются, так как в правиле их создания не произошло изменение зависимости, которой является файл main.c. Вот оно — поистине главное преимущество утилиты make. Она не пересоздаёт то, что не изменилось. На всякий случай можно запустить программу на выполнение, которая, я уверен, что нормально выполнится.

Давайте теперь в файле main.c закомментируем наш раскомментированный код и раскомментируем следующий

 

 

Сохраним изменения и запустим утилиту

 

 

У нас опять выполнились все три команды, так как содержимое файла main.c изменилось, вследствие чего изменились и объектный с ассемблерном файлом, а так как изменился объектный файл, являющийся зависимостью первой целью, то первое правило тоже выполнилось. Теперь мы, надеюсь, начали немного понимать смысл сценария. Если бы не было правил, а были бы просто команды, то они бы выполнялись всегда независимо от изменений. Это ничего, когда мало файлов, а вот когда их огромное количество, то сценарий даёт огромный выигрыш во времени сборки.

Теперь закомментируем предыдущий код и раскомментируем следующий

 

 

Теперь мы должны подключить к сборке следующий модуль, так как используются его функции. Сохраним изменения в main и перейдём к Makefile.

Во-первых, чтобы немного отвлечься, давайте познакомимся с использованием переменных в сценариях.

Переменная в сценариях представляет собой имя, определенное в файле сценария для представления строки текста, называемой значением переменной. Далее, по запросу, эти значения могут быть подставлены в нужные места файла сценария (например, в имена целей, имена зависимостей, команды и т.д.).

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

Именем переменной может быть любая последовательность символов, не содержащая :, #, = и начальных или конечных пробелов. Однако, рекомендуется избегать использования имен переменных, содержащих символы, отличные от букв, цифр и символа подчеркивания. Во-первых, такие имена в будущем могут получить какое-либо специальное значение, и, во-вторых, не все интерпретаторы командной строки смогут передать (через переменные среды) такие переменные «порожденным» копиям make.

Имена переменных чувствительны к регистру.

Чтобы обратиться к переменной, мы используем символ $ и скобки, в которые заключено имя переменной. Например, чтобы использовать переменную с именем VAR_NAME, мы пишем $(VAR_NAME).

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

Добавим переменную в самом верху нашего сценария Makefile

 

 

Теперь вместо gcc в нашем сценарии мы будем использовать нашу переменную и Makefile теперь примет вот такой вид

 

 

Добавим в самом низу Makefile правило для сборки нашего арифметического модуля

 

 

Также добавим в главное правило ещё одну зависимость — объектный файл модуля. Также добавим этот объектный файл и в команду этого правила

 

myprog20.exe: main.o ariph.o
$(CC) -o myprog20.exe main.o ariph.o

 

Сохраним сценарий, очистим от файлов с помощью команды clean наш каталог и запустим утилиту

 

 

Всё собралось. Проверим работоспособность

 

Всё работает.

Закомментируем предыдущий код и раскомментируем следующий

 

 

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

 

Предыдущий урок Программирование на C Следующая часть

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

C MAKE. Наш первый Makefile

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*