#c #ubuntu #makefile
#c #ubuntu #makefile
Вопрос:
Здравствуйте, мне трудно разобраться в makefiles. Я играю с ними, чтобы лучше понять их, но вот проблема:
all: main
main: main.o funcIO.o funcMan.o
$(CC) -o $@ $^
----------------------------------
funcIO.o: funcIO.c
$(CC) -c -o funcIO.o funcIO.c
funcMan.o: funcMan.o
$(CC) -c -o funcMan.o funcMan.c
Это работает независимо от того, есть ли все, что находится ниже выделенной строки, или нет. Мне сказали, что это правильный способ написания makefiles, но почему он работает без целевых объектов funcIO.o и funcMan.o, и если это работает без них, зачем мы их пишем? Можете ли вы объяснить это так, как будто мне 5 лет?
Спасибо за ваше время!
Комментарии:
1. Поскольку они уже существуют в папке сборки, вы, вероятно, не удаляли их между сборками.
2. В качестве альтернативы вы можете использовать современную среду IDE для программирования, которая делает все это за вас, и вместо этого сосредоточиться на реальном программировании. Создание файлов ушло в прошлое, из консольной эры, которая закончилась около 30 лет назад.
3. @Lundin согласен, или просто скомпилируйте все одним вызовом компилятора. Компьютеры быстры.
4. make по умолчанию содержит набор неявных правил. make, CMake и другие инструменты сборки не являются «вещью из прошлого». И это не консольное программирование. С переносом всех типов компьютеров в облако, работающих на «машинах», имеющих только текстовую консоль, многие задачи возвращаются к текстовому вводу-выводу с использованием JSON, YAML, XAML или чего-либо еще. И проекты становятся все больше и больше, насчитывая сотни, даже тысячи файлов. Таким образом, интеграция с make или CMake является обязательной для ВСЕХ IDE. например, посмотрите на Visual Studio и посмотрите уровень встроенной поддержки CMake, ninja, NMAKE. И скомпилировать все — это не вариант.
5. @ Lundin Может быть, я использую Makefiles, потому что это то, что используется на работе. Они, конечно, не ушли в прошлое.
Ответ №1:
Предполагая, что вы используете GNU Make (это может быть то же самое для других Make), это работает благодаря встроенным правилам. Make уже знает, как скомпилировать исходный файл C, и, если вы не укажете иное, он применяет к нему этот рецепт:
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $@ $<
$@
является целью правила (имя файла .o
файла) и $<
является первым предварительным условием (имя файла .c
). Другие переменные имеют разумные значения по умолчанию (в основном пустые).
Ответ №2:
Правильный способ использования Makefiles — это сделать их как можно меньше. Makefiles предназначены для определения зависимостей и только случайно могут быть использованы для сборки программ. Вот как я бы переписал ваш Makefile:
all: main
main: main.o funcIO.o funcMan.o
И я поместил туда all
цель только потому, что она была у вас с самого начала. Make имеет список встроенных правил, которые знают, как создавать вещи, учитывая определенные файлы в качестве входных данных. Если вы запросите у него .o
файл, он будет искать файл с тем же именем, но с расширением .c
, .cpp
, .f77
и т.д., и запустит правило, которое создает то, что вы просили, используя этот необходимый файл. Вам даже не нужно указывать, как их создавать, они предоставляются бесплатно! Это более сложные взаимосвязи (такие как конечный двоичный файл), которые необходимо прописать, как показано в моем примере выше. Существует аналогичное правило для создания двоичного файла из .o
файлов (при условии, что один из них имеет то же имя, что и двоичный файл, что и ваш), поэтому вам не нужно указывать какие-либо задачи, только зависимости. Вы можете контролировать, как они выполняются, установив специальные флаги:
CFLAGS = -Wall -Wextra -Wpedantic
main: main.o funcIO.c funcMan.o
main: LDLIBS = -lm
Эта версия создает каждый файл, скомпилированный на C, с их помощью CFLAGS
и создает main
во время компоновки в -lm
математической библиотеке.
Если вы создаете обычные программы на C, я настоятельно рекомендую этот подход. Укажите предварительные условия конечного двоичного файла и управляйте сборками с помощью этих переменных Make.