2016-10-27 8 views
2

Я только начал изучать язык программирования C в своем университете. У нас есть задача создать Makefile, который использует исполняемую программу (битва в моем случае) и компилируется только тогда, когда это необходимо. Моя проблема заключается в том, что она компилируется каждый раз, когда я использую команду make, и она не показывает «Является актуальной», как я хочу. У меня есть 2 объекта для компиляции (quest.o и thorgrim.o, и только quest.o должен быть создан, так как у нас есть thorgrim.o уже) в «битву». Вот мой код:Makefile компиляция каждый раз

CC=gcc 
EXE=battle 
CFLAGS=-Wall 

build: run 
run: quest.o 
    $(CC) $^ thorgrim.o -o $(EXE) 
    ./$(EXE) 
quest.o: quest.c 
    $(CC) -c $^ -o [email protected] 
clean: rm -rf quest.o $(EXE) 

Что я делаю неправильно? Я хочу, чтобы он собирался один раз, а затем отображался в актуальном состоянии, если я не коснусь квеста. Заранее спасибо!

+1

Ну, вы бежите и ссылка * в одной и той же цели *, так что нет никакого способа сделать одно без другого. Возможно, вы захотите иметь * compile * ← * link * ← * run * зависимость. – Biffen

+1

Ваша проблема: make переходит к компиляции 'run' и предполагает, что' run' является фактическим выходным файлом, созданным правилом, а не только тем, что вы создали. Следовательно, он не находит файл под названием 'run' и компилирует. – Blacksilver

+0

Ты мой герой! Через 7 часов это простое объяснение было единственным, что мне было нужно. Наш учитель сказал мне, что это слишком сложно, и я должен спросить на форуме университета. Еще раз спасибо, сэр! – Shavoks

ответ

1

Цель запуска зависит от файлов, но правило сборки не создает файл с именем «run». Лучше всего сделать что-то в этом направлении:

run: $(EXE) 
    ./$(EXE) 

$(EXE): $(OBJ) 
     $(CC) $(CFLAGS) -o [email protected] $+ 
+0

Я сделал то, что вы предложили, но не повезло. Он работает, но все еще компилируется. Большое спасибо! – Shavoks

0

Вы не делаете это должным образом.
Вот "шаблон Makefile":

CC=gcc 
none: prog #`make` -> `make prog` 

#make's default rules are fine here. 
prog: foo.o bar.o 

foo.o: foo.c head.h 

bar.o: bar.c head.h 

EDIT: Вы должны использовать whatever.o, неwhatever для объектных файлов, так что знает, чтобы пройти -c.

+0

У меня не может быть больше этих двух объектных файлов, и я не знаю, как использовать эти заголовки. Благодаря! – Shavoks

+0

замените 'foo' и' bar' соответствующими именами файлов. Добавление заголовка в цель просто говорит, что он должен перекомпилировать, если он изменился. Вы им не нужны. – Blacksilver

1

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

Первую, позволяет начать с определения ваших объектов

OBJS := quest.o thorgrim.o 

теперь вы можете создать шаблонное правило:

%.o: %.c 
    $(CC) $(CFLAGS) -MD -MP $< -c -o [email protected] 

Первая строка этого правила %.o:%.c говорит, что все, заканчивающееся .o зависит от файла с тем же именем, заканчивающимся на .c. Это не позволяет вам писать отдельное правило для каждого объектного файла. Обратите внимание, что для этого есть правило шаблона по умолчанию, но мы не будем здесь останавливаться.

Далее вы звоните $(CC) с номером $(CFALGS). Обратите внимание, что [email protected] теперь представляет имя файла .o, который вы генерируете, и $< представляет собой первую зависимость объекта (файл .c в этом случае).

-MD и -MP используются для автоматической генерации файлов зависимостей - для каждого .c файла он также создаст .d файл, в котором перечислено зависимости (.h файлов), что ваш источник требует, чтобы построить. У вас должно быть -include файлы зависимостей для его работы. (см. https://gcc.gnu.org/onlinedocs/gcc-4.3.1/gcc/Preprocessor-Options.html для более подробной информации о том, что они делают). Таким образом, если вы измените файл заголовка, он автоматически перестроит необходимые файлы .o. Сказав это, вы должны включить эти .D файлов в Makefile:

-include $(OBJS:.o=.d) 

Это будет включать .D файлы, как если бы кто-то вырезать и вставить код в свой Makefile.$(OBJS:.o=.d) просто приказывает сделать взять OBJS и заменить все .o на .d. Обратите внимание на - перед включением. Это говорит о том, что не стоит беспокоиться о том, что файл не существует (как это будет в случае вашей первой сборки ...).

Хорошо, теперь, когда у вас есть ваши .o файлы построили, вы должны построить свою программу:

$(EXE): $(OBJS) 
    $(CC) $^ -o [email protected] 

Добавить правило и комментарии по умолчанию, и вы сделали. Итак, в общем, ваш make-файл будет выглядеть примерно так:

CC:=gcc 
EXE:=battle 
CFLAGS:=-Wall 
OBJS:=quest.o thorgrim.o 

%.o: %.c 
    $(CC) $(CFLAGS) -MD -MP $< -c -o [email protected] 

$(EXE): $(OBJS) 
    $(CC) $^ -o [email protected] 

clean: 
    rm -f $(OBJS) $(EXE) 

-include $(OBJS:.o=.d) 

EDIT: забыли правильное правило - добавив, что.

+0

Как я понял, первоначальная задача состояла в том, чтобы выполнить «битву» (и при необходимости перестроить). В таком случае нам понадобится добавить default target 'run: $ (EXE)' ./$ (EXE) '(как сказано в другом комментарии выше) –

+0

Да ... Я не включил это. Мне не нравится, когда make-файлы запускают конечные программы - это работа скрипта (или самой программы ...). Если вы хотите сделать один лайнер, вы можете запустить 'make &&./Battle' – John

0

EDIT: добавлен $ (EXE) в качестве зависимости к run мишени

следующий Makefile показывает, как это должно быть записано

При создании любого макроса, те в результате содержание не изменится, всегда использовать :=, а не =, так что макрос оценивается только один раз

При создании макроса для исполняемого файла всегда включайте полный путь к исполняемому файлу, поэтому исполняемый файл всегда выполняется независимо от других изменений в вашей системе и/или окружении «PATH»

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

CC := /usr/lib/gcc 
RM := /usr/lib/rm -f -r 

EXE := battle 
CFLAGS := -Wall -Wextra -Wconversion -std=gnu99 -c 

# macro with all the source names 
SRCS := thorgrim.c quest.c 

# macro with all the object file names 
OBJS := $(SRCS:.c=.o) 

# always include a .PHONY statement for any targets 
# that do not produce a file of the same name 
.PHONY : all clean run 

# 'all' is the typical first target 
all: run 

# implied compile rule/recipe 
%.o:%.c 
<tab>$(CC) $(CFLAGS) -o [email protected] $< 

# the macro 'LFLAGS' is part of the default macros 
# link the objects into an executable 
$(EXE): $(OBJS) 
<tab>$(CC) $^ -o [email protected] $(LFLAGS) 

# execute the executable 
run: $(EXE) 
<tab>./$(EXE) 


clean: 
<tab>$(RM) quest.o $(EXE) 

Примечание: замените <tab> с фактическим символом табуляции

+0

Несколько быстрых комментариев: hardcoding абсолютный путь может сделать код менее портативным (другие люди могут устанавливать свои инструменты в других местах, или они могут ХОТИТЬ использовать gcc, который находится на своем пути, а не по умолчанию ...). Для rm вы должны скорее «$ (RM) $ (OBJS) $ (EXE)» и пропустить «-r», если это необходимо. Правило 'run' должно, вероятно, зависеть от' $ (EXE) '. – John

+0

нет, первая цель не должна зависеть от '$ (EXE)', потому что OP хочет выполнить программу. в отношении '-r', OP использовал его, и я не вижу причин не следовать примеру OPs, когда это возможно. Я согласен с тем, что в текущем сценарии нет необходимости. – user3629249

+0

НЕ кодирование пути к требуемой системной утилите приведет к тому, какая версия исполняемой утилиты будет зависеть от переменной среды PATH. Это может/приведет к серьезной проблеме, когда другие наборы инструментов доступны через переменную среды «PATH», которая будет использоваться, будет зависеть от порядка записей в переменной. Плохая идея зависеть от переменной среды PATH при создании портативного кода. – user3629249

Смежные вопросы