У вашего Makefile
нет информации о зависимостях, включенной в форму Правила . Правила - это строки, начинающиеся в левом столбце (в столбце 0) и имеющие разделитель :
между целями (объекты, которые будут построены) и реквизитами (объекты, предоставленные правилу)
Make выполняет цепочку правил, поэтому цель не может быть построена раньше, чем ее предпосылки, поэтому хорошей отправной точкой будет:
ex1.exe: ex1.o
это означает, что ex1.exe
(первая цель в вашем Makefile
) зависит от ex1.o
(скомпилированный объект) .... но как. Вы добавляете команды чуть ниже, но вставляете перед командной строкой символ табуляции:
[tab char]gcc -Wall -g ex1.o -o ex1.exe
Прежде всего, посмотрите, как команда принимает ex1.o
в качестве ввода для gcc
и генерирует (с помощью опции -o
) файл ex1.exe
.
Смысл всего этого в том, что вам всегда не хватает ex1.exe
, или он оказывается модифицированным (начиная с даты его изменения в файле) до обязательного условия (ex1.o
), в котором будет использоваться эта команда.
Теперь, как мы скомпилируем объектный файл? (в вашем Makefile это делается напрямую)
ex1.o: ex1.c
$(CC) $(CFLAGS) -c -o $@ $<
эта строка нуждается в дополнительных пояснениях (хотя, если вы ее не используете, она автоматически предоставляется программой make
). Она использует переменные подстановки: $(CC)
расширяется до компилятора C по умолчанию (обычно cc
, но Вы можете изменить это). $(CFLAGS)
- это переменная, которую вы определили поверх Makefile
, и она расширяется до параметров компилятора, обычно используемых для компиляции программ. $@
расширяется целевым файлом (в данном случае файлом ex1.o
), а $<
расширяется до левой предпосылки правой части правила. Это правило, которое очень распространено для компиляции файлов C в объектные файлы, автоматически генерируется для вас make
, и больше можно создать в make
advanced used (я не буду вводить здесь, из-за количества места нужно) просто сказать, что это можно записать так:
.c.o:
$(CC) $(CFLAGS) -c -o $@ $<
, что означает: любой файл с расширением .o
может быть создан из файла с тем же именем, но с расширением .c
с помощью следующей командной строки ниже. Это автоматически приводит к зависимости каждого .o
файла от файла с тем же именем, но с расширением .c
, и предварительно загружается в make
.
Итак, ваш самый простой Makefile
может быть:
CFLAGS=-Wall -g
src=ex1.c
ex1.exe: $(src)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(src)
Как вы видите, я использовал переменную src
для описания исходных файлов C, используемых для компиляции моей программы. Зависимость будет выдана только , когда вы изменили какие-либо или предварительные условия (сейчас есть только одна, на ex1.c
, но может быть и больше), и так как я делаю компиляцию и компоновку в одной и той же компиляции, я необходимо передать флаги компиляции и флаги ссылки (не используется, вы можете удалить ссылку на $(LDFLAGS)
здесь) Действительно, вы могли бы написать:
ex1.exe: ex1.c
cc -g -Wall -o ex1.exe ex1.c
clean:
rm -f ex1.exe
Итак, действие по умолчанию - создать ex1.exe
, который зависит от ex1.c
(поэтому только при изменении ex1.c
перекомпилируется ex1.exe
. Чтобы скомпилировать его, просто выполните:
make ex1.exe
или
make
, который будет использовать первое правило по умолчанию Makefile
.
clean
является поддельной целью (нет файла с именем clean
для генерации), поэтому при использовании
make clean
связанная с ним команда всегда выполняется. make
удаляет целевые файлы (так как удаляет все созданные файлы), поэтому при следующем запуске make
он заново создаст все файлы, выполнив необходимые компиляции.
ОБЩЕЕ ИСПОЛЬЗОВАНИЕ
Для простых программ, скажем, нескольких исходных .c
файлов и некоторых .h
файлов, с отдельной компиляцией каждого (опция -c
при компиляции) и связыванием, я обычно использую этот подход (определение объектных файлов требуется для каждой целевой программы в отдельной переменной)
# makefile for programs foo and bar.
targets = foo bar
TOCLEAN = $(TARGETS) # this variable stores what should be erased on clean target. Here we store the programs to erase.
foo_objs = a.o b.o c.o
TOCLEAN += $(foo_objs) # here, we add the objects of foo
foo: $(foo_objs)
$(CC) $(LDFLAGS) -o $@ $(foo_objs)
bar_objs = d.o e.o f.o
bar_libs = -lm -lintl -lX
TOCLEAN += $(bar_objs) # here we add the objects of bar
bar: $(bar_objs)
$(CC) $(LDFLAGS) -o $@ $(bar_objs) $(bar_libs)
clean:
rm -f $(TOCLEAN)
a.o b.o c.o: a.h b.h c.h globals.h
b.o c.o d.o e.o f.o: my_defs.h
(как вы видите, зависимость от заголовочных файлов относится к скомпилированному объекту - не к исходному файлу .c
... исходный файл создает зависимость, но это объектный файл, который должен быть воссоздан в если изменен включенный файл, а не включающий файл .c
)