В предыдущей части нашего занятия мы познакомились с утилитой make и уже написали небольшой сценарий, позволяющий нам прочувствовать принцип раздельной компиляции проекта.
Так как здесь используется другой модуль, аналогично подключим и его сборку в Makefile, написав в самом низу правило
1 2 3 |
utils.o: utils.c $(CC) -O0 -g3 -Wall -c utils.c $(CC) -masm=intel -g3 -Wall -c utils.c -S |
Также не забываем добавить объектный файл в главное правило
myprog20.exe: main.o ariph.o utils.o
$(CC) -o myprog20.exe main.o ariph.o utils.o
Опять очистим папку и соберём наш проект
Запустим программу
Всё отлично работает!
Закомментируем код и раскомментируем следующий
1 2 3 4 5 6 7 8 9 10 11 12 |
char str1[35] = {}; int a = 0b00111000, b = 0b10000010, c = 0b01000001; int_to_binary(a, str1); printf ("Value is %srn", str1); int_to_binary(b, str1); printf ("Value is %srn", str1); int_to_binary(c, str1); printf ("Value is %srn", str1); printf("==========rn"); int res = a | b ^ c; int_to_binary(res, str1); printf ("Value is %srn", str1); |
Сохраним изменения и запустим утилиту без предварительной очистки каталога
Как мы видим, выполнилось у нас правило сборки модуля main и главное правило. Вот она — раздельная компиляция! Уже не мнимая, как в случае с командными файлами.
Запустим нашу программу
Всё отлично работает.
Но кое-что мы забыли. Сейчас объясню что.
Давайте попробуем внести изменения в какой-нибудь заголовочный файл, например в utils.h. Закомментируем в нём прототип функции
1 |
//void int_to_binary(int x, char* in_str); |
Сохраним изменения.
Теперь главный модуль не будет ничего знать о существовании данной функции и проект наш не должен собраться и должен дать ошибку. Попробуем его собрать
Проект не пересобрался, так как утилита make не заметила, что у нас вообще что-то изменилось. Обычно в этих случаях кто-то производит очистку и полностью пересобирает проект. Кто-то впадает в отчаяние и возвращается к командной сборке, и перестаёт пользоваться make. Мы, конечно же, так поступать не будем, а добавим соответствующие зависимости. Чтобы отследить изменения в наших header-файлах мы должны их добавить в зависимости в правила сборки тех модулей, к которым они подключены директивой include. Давайте так и поступим. После этого наш Makefile примет следующий вид
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
CC = gcc myprog20.exe: main.o ariph.o utils.o $(CC) -o myprog20.exe main.o ariph.o utils.o main.o: main.c main.h ariph.h utils.h $(CC) -O0 -g3 -Wall -c main.c $(CC) -masm=intel -g3 -Wall -c main.c -S ariph.o: ariph.c ariph.h $(CC) -O0 -g3 -Wall -c ariph.c $(CC) -masm=intel -g3 -Wall -c ariph.c -S utils.o: utils.c utils.h $(CC) -O0 -g3 -Wall -c utils.c $(CC) -masm=intel -g3 -Wall -c utils.c -S |
Сохраним файл сценария и снова попробуем пересобрать проект
Вот теперь всё заметилось и модуль main у нас хоть и собрался, но было выдано предупреждение. Просто, компилятор gcc так устроен и не только он, что если нет прототипа, реализация используемых функций все равно ищется в других модулях. Поэтому она нашлась и проект наш всё же собрался.
Поэтому нам надо изменить как-то заголовочный файл, чтобы сгенерировалась именно ошибка.
Давайте в нём подключим какой-нибудь несуществующий заголовочный файл
1 2 |
#include <string.h> #include "file01.h" |
Сохраним и ещё раз попробуем пересобрать наш проект
Теперь другое дело. Мы увидели ошибку, хотя мы не очищали весь проект, а также остальные правила у нас не выполнялись, т.к. в их зависимостях не было изменений. Также у нас не произошла линковка из-за ошибки в выполнении правила цели main.o.
В папке с программой у нас остались старые версии файлов main.o и исполняемого файла. Их, конечно, можно удалять каждый раз при выполнении соответствующих правил, но, думаю, незачем. Так как если мы увидим ошибку, то мы её начнём устранять, а не пытаться выполнить старые версии программы.
Удалим подключение несуществующего файла из utils.h, раскомментируем прототип, сохраним изменения и пересоберём наш код. Код теперь нормально соберётся.
Таким образом, мы теперь следим за изменениями также и в заголовочных файлах.
Для полноты картины осталось добавить цель для очистки содержимого каталога с программой.
Добавим такую цель в самом низу сценария
1 2 |
clean: del -rf *.s *.o *.exe |
Чтобы нам отдельно выполнить то или иное правило, мы должны в команде прописать его цель.
Так и поступим, чтобы проверить работу правила очистки
Также посмотрим в каталоге с программой, что файлы удалились
Отлично, на всякий случай ещё раз попробуем пересобрать проект и проверить работу программы
Всё отлично собирается и исполняется.
Теперь мы можем удалить из каталога с проектом файл clean.cmd, он также больше не нужен.
Итак, на данном занятии мы познакомились с работой утилиты Make, с помощью которой нам удалось собрать наш проект, а также увидеть ряд преимуществ использования утилиты Make по сравнению с командной сборкой, в частности то, что принцип раздельной компиляции здесь реализован полностью. Это было только первое знакомство. Не знаю, возможно, будут ещё отдельные уроки по данной утилите, а, возможно, с другими возможностями утилиты Make мы будем знакомиться в процессе написания и наших следующих проектов с целью углубления наших знаний очень интересного и увлекательного языка программирования C.
Всем спасибо за внимание!
Предыдущая часть Программирование на C Следующий урок
Смотреть ВИДЕОУРОК (нажмите на картинку)
Клвссно, спасибо за урок! Все получилось.
Классно,все получилось! Спасибо за урок.