2013-05-24 2 views
9

Я учу, как настроить make-файлы и столкнулся с проблемой. Чтобы продемонстрировать это, я создал простой «проект», состоящий из исходных файлов main.m и test.m.Makefile всегда перекомпилирует файл

Я пытаюсь настроить сделать, чтобы скомпилировать эти файлы (только если нечто изменилось), а также хранить объектные файлы где-нибудь еще (здесь build/)

Мой Makefile:

OBJ = ./build 

SOURCES=main.m test.m 
OBJECTS=$(addprefix $(OBJ)/,$(SOURCES:.m=.o)) 
EXECUTABLE=test 

all: $(EXECUTABLE) 

$(EXECUTABLE): $(OBJECTS) 
     gcc $(OBJECTS) -o $(EXECUTABLE) 

$(OBJECTS): $(OBJ)/%.o: %.m build/ 
     gcc -c $< -o [email protected] 

build/: 
     mkdir build 

Когда я бегу это в первый раз (с только Makefile и источников в текущем каталоге) это то, что я ожидаю, что это сделать:

gcc -c main.m -o build/main.o 
gcc -c test.m -o build/test.o 
gcc ./build/main.o ./build/test.o -o test 

Однако, если я бегу make еще раз:

gcc -c main.m -o build/main.o 
gcc ./build/main.o ./build/test.o -o test 

Что я сделал не так? Также отмечаем, что любые другие ошибки в Makefile оцениваются, поскольку я пытаюсь научиться создавать «хорошие» Make-файлы.

EDIT:

То, что я заметил из make -d:

Finished prerequisites of target file `build/main.o'. 
Prerequisite `main.m' is older than target `build/main.o'. 
Prerequisite `build/' is older than target `build/main.o'. 
No need to remake target `build/main.o'. 

и

Finished prerequisites of target file `build/test.o'. 
Prerequisite `test.m' is older than target `build/test.o'. 
Prerequisite `build/' is newer than target `build/test.o'. 
Must remake target `build/test.o'. 
+0

Я думаю, что вы просто не хотите '/' 'прилагается к build' в пару мест. Позвольте мне попробовать это здесь. Вы можете использовать 'make -d', чтобы увидеть, как' make' принимает решения о том, что нужно строить, если это помогает. –

+0

Спасибо. Однако маршрут 'make -d' займет некоторое время, когда он выводит 927 строк информации :) – varesa

+0

Вы можете успокоить это, избавившись от такого количества неявных правил, как posisble. Я просто попробовал ваш make-файл здесь, хотя и с простым тестовым проектом, и, похоже, он работал так, как ожидалось. То есть, во втором запуске я просто получаю 'make: ничего не делать для 'all'''. –

ответ

9

Ваш make -d выход показывает, что make думает ваш каталог сборки был обновлен, и так, что потребности в файл для восстановления.

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

Вы можете решить эту проблему, сделав buildзаказ только предпосылкой путем добавления | к этому правилу:

$(OBJECTS): $(OBJ)/%.o: %.m | build 

Я тоже удалил /, так как оно не было ничего делать.

Так как вы просили, некоторые другие редакционные примечания:

  1. Добавить clean цель. Что-то вроде:

    clean: 
        rm -rf $(EXECUTABLE) $(OBJ) 
    
  2. Вам не нужен ./ при установке OBJ. Достаточно OBJ = build.

  3. / на build, как указано выше. Но это не имеет большого значения, так как вы все равно не должны ссылаться на него. Repalce build с $(OBJ) везде, где вы его видите.

  4. mkdir не работает, если каталог уже существует.Вы, вероятно, следует префикс эту команду с -:

    $(OBJ): 
        -mkdir $(OBJ) 
    

    Обратите внимание, что я сделал замену с $(OBJ), что я говорил в # 3 выше.

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

    DEPFILES = $(addprefix $(OBJ)/,$(SOURCES:.m=.d)) 
    

    Затем получить компилятор генерировать их, добавив -MMD флаг:

    gcc -MMD -c $< -o [email protected] 
    

    И наконец, включить их в Makefile, если они доступны, по добавив строку в конце вашего Makefile:

    -include $(DEPFILES) 
    
+0

Значит, это было в основном 'make' создание объектных файлов в' build/', которые заставляли его обновлять и принудительно перекомпилировать? – varesa

+0

Это так. Это не происходит на моей машине, но я думаю, что поведение может быть зависимым от файловой системы. –

+0

Или это может также иметь какое-то отношение к параметрам монтирования, главным образом тем, кто говорит об этом, когда он должен обновлять временные метки. – varesa

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