我已经为单元测试创建了一个Makefile,它使用带参数的GCC在编译期间创建分析文件(gcno)。以下是编译和链接的相似部分:
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)/$@
$(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 :(得分:1)
感谢所有评论。我试过no-op“;”和“:=”具有相同的结果。
我想我需要退一步解释为什么我问这个问题。这不仅仅是关于手动删除或不删除gcno文件,而是关于如何编写这样的Makefile来恢复任何丢失或过时的文件。我的Makefile在很少的地方有类似的情况,它使用并行构建,所以当一些文件丢失时,它会产生许多奇怪的错误。通常它是通过“干净”和“全部”解决的,但我希望Makefile是完美的并且很好地处理丢失的文件问题。
由于上面的例子没有Makefile的其余部分就不那么清楚,所以我做了一个新的简单测试。
<强>的hello.c 强>
#include <stdio.h>
int main()
{
printf("Hello world\n");
}
<强>生成文件强>
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 $@
$(EXE): $(OBJECTS)
$(LINK) $(OBJECTS) $(LNKFLAGS) -o $(EXE)
build: $(EXE)
“make build”创建以下文件:
现在,如果我删除“hello.gcno”并再次运行build,它会告诉我:
mingw32-make: Nothing to be done for 'build'.
目标是更新Makefile,以便make重新创建“hello.gcno”。它可能会在该过程中重新创建“hello.o”和“hello.exe”,但这不是问题。
编辑: 要明确一点:在真正的Makefile中,我真的非常需要.gcno文件。这不仅仅是一个额外的信息或要避免或可选择的东西。 Makefile构建单元测试可执行文件,运行它们并执行gcov以生成代码覆盖率信息,gcovr创建所有.gcov文件的报告。如果.gcno文件丢失,它将无法正常工作。另外 - 因为它是并行构建,所以依赖性应该绝对正确,以避免某些进程从较早开始并且它很棘手,因为覆盖报告具有来自两个“分支”的依赖性 - 来自编译阶段的.gcno文件和来自执行阶段的.gcda文件。所以这就是为什么我需要它是正确的。
答案 1 :(得分:0)
这里唯一的选择是:
(如果您可以更改规则)
lib2
对此:
pkglib
答案 2 :(得分:-1)
我认为正确答案是,不要自行删除任何.gcno
个文件。如果您必须&#34;清理&#34;,请使用make clean
,但不要只是删除文件。
&#34; build&#34;是一个状态机,所有文件构成一个&#34; state&#34;。不要破坏国家!
有人说,应该能够删除任意文件,并且构建应该恢复。我的回答是,如果你手动损坏一些.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 $@
$(UTEXE): $(UTOBJSFULL) $(UTMAKEDEP) | $$(@D)\.
$(call report,Linking to $(@F))
$(LINK) $(UTOBJSFULL) $(LNKFLAGS) -o $@