Makefile依赖于多个文件

时间:2014-12-17 15:10:41

标签: c makefile dependencies multiple-files

我已经为单元测试创​​建了一个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是它的先决条件,但它不会进行编译。

我不知道如何命名这个案例因此无法从互联网上找到解决方案。基本上一个配方创建两个文件,我不知道如何编写重新运行配方的规则,即使只需要重新创建一个文件。

我会很感激一些链接或提示。

3 个答案:

答案 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.o
  • hello.gcno
  • 用hello.exe

现在,如果我删除“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 $@