2014-12-17 4 views
1

Я создал Makefile для модульных тестов, который использует GCC с аргументами для создания профилирующих файлов (gcno) во время компиляции. Вот similified его часть, где компиляции и компоновки имеет место:Зависимости Makefile от нескольких файлов

UTEXE  = $(UTOBJSDIR)\$(UTUNIT).exe 
UTOBJS  = $(UTUUTSRC:.c=.o) $(UTUTSRC:.c=.o) $(UTCSRC:.c=.o) 
UTOBJSFULL = $(addprefix $(UTOBJSDIR)\,$(UTOBJS)) 
UTOBJSGCNO = $(addprefix $(UTOBJSDIR)\,$(UTOBJS:.o=.gcno)) 

$(UTOBJS): %.o: %.c $(UTMAKEDEP) 
    $(call report,Compiling $(*F).c) 
    $(MKDEP) $(MKDFLAGS) -o.o -f$(UTOBJSDIR)\$(*F).dep $(subst /,\,$<) 
    $(CC) -c $(CFLAGS) $(subst /,\,$<) -o $(UTOBJSDIR)/[email protected] 

$(UTOBJSGCNO): $(UTOBJS) $(UTMAKEDEP) 

utbuild: $(UTEXE) $(UTOBJSGCNO) $(UTOBJS) $(UTMAKEDEP) 

$(UTEXE): $(UTOBJSGCNO) $(UTOBJS) $(UTMAKEDEP) 
    $(call report,Linking to $(UTUNIT).exe) 
    $(LINK) $(UTOBJSFULL) $(LNKFLAGS) -o $(UTEXE) 

Он собирает все объектные и профильные файлы и ссылки вместе бинарный файл. Однако, когда я удаляю файл профиля (gcno) и снова вызываю «utbuild», он не будет повторно компилироваться для восстановления файла .gcno. Он пытается сделать ссылку снова, потому что gcno является для него префиксным, но он не выполняет компиляцию.

Я не знаю, как назвать этот случай, так что не удалось найти решение из Интернета. В основном один рецепт создает два файла, и я не знаю, как написать правило, которое повторно запускает рецепт, даже когда нужно восстановить только один файл.

Буду признателен за ссылки или подсказки.

+0

'$ (UTOBJSGCNO): $ (UTOBJS) $ (UTMAKEDEP)' сообщает, что * каждый * '.gcno' файл имеет * каждый *' .o' файл в качестве необходимого условия. Это почти наверняка не то, что вы хотите. –

+0

@ EtanReisner Да, он делает здесь избыток, но это не его вопрос, поскольку по его точному вопросу я думаю, что он просто нуждается в '.'. Трудно проверить, хотя бывало, что это немного беспорядок :) –

+0

первые 4 строки (некоторые макроопределения) должны использовать ': =', а не '=', поэтому макрос оценивается только один раз. – user3629249

ответ

-1

Правильный ответ, на мой взгляд, есть, не удаляет файлы .gcno. Если вам нужно «очистить», используйте make clean, но не просто удаляйте файлы.

«Сборка» - это конечный автомат со всеми файлами, составляющими «состояние». Не коррумпируйте государство!

Некоторые люди говорят, что вы должны удалять произвольные файлы, и сборка должна восстанавливаться. Мой ответ: если вы повредите файл .o вручную, скажем, добавьте 0 и 1, что сделает его непригодным (спасибо user3629249 за указание, что нужно уточнить, что я говорю о коррупции, а не преднамеренное редактирование). Должна ли сборка также оправиться от этого? Очевидно, что никакая система сборки в мире не восстановится, если вы коснетесь файла .o таким образом. Тогда зачем разрешать удаление файла, но не разрешать его изменять? Где вы проводите линию?

Проще говоря, любая коррупция не должна допускаться. Используйте только make clean, или еще лучше, напишите свой Makefile правильно, поэтому вам не нужно очищать период.


Весь Makefile имеет ряд проблем, вот как это должно выглядеть (я предполагаю, что это на Windows/DOS):

.SUFFIXES: 
UTEXE := $(UTOBJSDIR)\$(UTUNIT).exe 
UTOBJSFULL := $(addprefix $(UTOBJSDIR)\,$(subst /,\, $(UTUUTSRC:.c=.o) $(UTUTSRC:.c=.o) $(UTCSRC:.c=.o))) 
UTOBJSGCNO := $(UTOBJSFULL:.o=.gcno) 

.PHONY: utbuild all 
all: utbuild 
utbuild: $(UTEXE) $(UTOBJSGCNO) $(UTMAKEDEP) 

$(UTOBJSGCNO): %.gcno: %.o $(UTMAKEDEP) ; 

.SECONDARY: %\. 
%\.: Makefile 
    mkdir $* 

.SECONDEXPANSION: 

$(UTOBJSFULL): $(UTOBJSDIR)\%.o: %.c $(UTMAKEDEP) | $$(@D)\. 
    $(call report,Compiling $<) 
    $(MKDEP) $(MKDFLAGS) -o.o -f$(UTOBJSDIR)\$(*F).dep $< 
    $(CC) -c $(CFLAGS) $< -o [email protected] 

$(UTEXE): $(UTOBJSFULL) $(UTMAKEDEP) | $$(@D)\. 
    $(call report,Linking to $(@F)) 
    $(LINK) $(UTOBJSFULL) $(LNKFLAGS) -o [email protected] 
+1

Я как раз собирался обратиться к http://stackoverflow.com/q/27365859/258523 для справки для ответа здесь, но затем, посмотрев на ваш ответ, мне пришло в голову, что я думаю, что у него есть точная проблема, с которой он сталкивается Вот. Это не заставляет перестроить файл '$ (UTOBJS)' для файла '' $ (UTOBJSGCNO), когда только файл 'gcno' был удален. Не говоря уже о том, что каждый файл 'gcno' зависит от * каждого * .o' файла (но это уже проблема с файлом make OPs. –

+1

Собственно, после редактирования файла .o вызов make должен быть перестроен исполняемый файл (редактирование файла .o не так уж сложно, если вы знаете, что вы делаете). В тот же день, много лет назад, мы часто делали редактирование объектных файлов, так как полная компиляция привязывала машину мэйнфрейма для слишком долго. – user3629249

+0

@ user3629249 Я согласен с тобой. Вы неправильно поняли мой ответ. Я согласен, что если вы намеренно и правильно отредактируете файл '.o', тогда вы хотите, чтобы система сборки перестраивала библиотеку, используя это. было о чем-то совершенно другом. Предположим, что вы должны были сорвать файл '.o', что делает его непригодным для использования. Возможно, следует ожидать, что система сборки будет _recover_ от этого, а это значит, перестроить файл' .o' правильно. », нельзя ожидать этого. Аналогично, не следует ожидать восстановления f из-за пользовательской халатности. –

1

спасибо за все комментарии. Я пробовал no-op ";" и ": =" с тем же результатом.

Думаю, мне нужно сделать один шаг назад и объяснить, почему я задал этот вопрос. Речь идет не только об удалении или не удалении gcno-файлов вручную, это общее понимание того, как писать такой Makefile, который восстанавливает любой отсутствующий или устаревший файл. Мой файл Makefile имеет похожие случаи в нескольких местах, и он использует параллельную сборку, поэтому, когда какой-то файл пропадает, он дает много странных ошибок. Обычно он решается «чистым» и «все», но мне бы хотелось, чтобы Makefile был идеальным и отлично справлялся с недостающими файлами.

Как вышеприведенный пример не так ясен без остальной части Makefile, тогда я сделал новый простой тест.

привет.с

#include <stdio.h> 

int main() 
{ 
    printf("Hello world\n"); 
} 

Makefile

CCDIR = C:\tools\MinGW 
CCBINDIR = $(CCDIR)\bin 
CCINCDIR = $(CCDIR)\include;$(CCDIR)\lib\gcc\mingw32\4.8.1\include 
CCLIBDIR = $(CCDIR)\lib;$(CCDIR)\lib\gcc\mingw32\4.8.1 

# Overcome "missing dll file" messages on Windows 
CC  = set PATH=%PATH%;$(CCBINDIR)& $(CCBINDIR)\gcc.exe 
LINK  = set PATH=%PATH%;$(CCBINDIR)& $(CCBINDIR)\gcc.exe 

# Compile and link for code coverage 
CFLAGS = -fprofile-arcs -ftest-coverage -g3 -O0 $(addprefix -I,$(CCINCDIR)) 
LNKFLAGS = -fprofile-arcs -ftest-coverage -static -static-libgcc $(addprefix -L,$(CCLIBDIR)) 

OBJECTS = hello.o 
EXE  = hello.exe 

$(OBJECTS): %.o: %.c 
    $(CC) -c $(CFLAGS) $(subst /,\,$<) -o [email protected] 

$(EXE): $(OBJECTS) 
    $(LINK) $(OBJECTS) $(LNKFLAGS) -o $(EXE) 

build: $(EXE) 

"сделать сборку" создает следующие файлы:

  • hello.o
  • hello.gcno
  • hello.exe

Теперь, если я удалить «hello.gcno» и запустить воссоздам он говорит мне:

mingw32-make: Nothing to be done for 'build'. 

Цель состоит в том, чтобы обновить Makefile так, что делают воссоздает «hello.gcno». Вероятно, он снова заново создаст «hello.o» и «hello.exe» во время этого процесса, но это не проблема.

Редактировать: Просто, чтобы быть ясным: в реальном Makefile мне действительно нужны файлы .gcno. Это не просто дополнительная информация или что-то, что можно избежать или сделать необязательным. Makefile создает исполняемые файлы единичного теста, запускает их и выполняет gcov для генерации информации о покрытии кода, а gcovr создает отчет обо всех файлах .gcov. Если файл .gcno отсутствует, он не будет работать. Кроме того, поскольку это параллельная сборка, зависимости должны быть абсолютно правильными, чтобы избежать некоторого процесса, начинающегося ранее, и это сложно, потому что в отчете покрытия есть зависимости, поступающие из двух «ветвей» - .gcno-файлов из этапа компиляции и .gcda-файлов с этапа выполнения. Вот почему мне нужно, чтобы это было правильно.

+0

Почему это цель, «восстановить любой недостающий файл»? Это просто не разумная цель. Вам нужно рассматривать сборку как «целую», а не коллекцию файлов. Все, все файлы, каталоги, отметки времени, это ваша сборка. Если вы повредите свою сборку, правильное средство - это «очистить» и начать все заново. Makefile, который может исправить все коррупции, которые могут произойти, не является «правильным», как вы думаете, вместо этого «невозможно». Почему вы хотите «исправить» какое-либо произвольное подмножество сбоев (отсутствующих файлов), не исправляя других? –

+0

Хороший способ думать о сборке - это «машина состояния» (хотя и не конечная). «Штатами» являются содержимое и временные метки файлов. Если вы выполняете одно из разрешенных действий, машина правильно выбирает новое состояние. Каковы допустимые действия? Касание/редактирование/добавление/удаление ваших источников и цели 'make'. Вот и все. Не допускается удаление произвольных файлов. –

+1

Хорошо, я вижу вашу точку зрения, но просто из интереса - как вы объясните, что когда вы удаляете объектный файл, а затем «make build» перекомпилирует его? Можете ли вы назвать это побочным эффектом или это нормальное поведение? –

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