Makefile依赖于多个文件

问题描述 投票:1回答:3

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

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

我希望获得一些链接或提示。

c makefile dependencies
3个回答
1
投票

感谢所有评论。我尝试了无操作“;”和“:=”的结果相同。

我认为我需要退后一步,并解释为什么我问这个问题。这不仅仅在于手动删除或不删除gcno文件,还在于对如何编写可恢复任何丢失或过时文件的Makefile的一般理解。我的Makefile在少数地方有类似的情况,并且正在使用并行构建,因此当某些文件丢失时,会产生很多奇怪的错误。通常,它可以通过“清理”和“全部”解决,但我希望Makefile完美并很好地处理丢失的文件问题。

由于上面的示例在没有所有其余Makefile的情况下并不清楚,因此我进行了一个新的简单测试。

hello.c

#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 $@

$(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文件。这就是为什么我需要它是正确的。


0
投票

这里您唯一的选择是:

((如果您可以更改规则)]

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

至此:

%.exe %.gnco: $(OBJECTS)
           $(LINK) $(OBJECTS) $(LNKFLAGS) -o $(EXE)
           $(GENERATE_GNCO) $<

-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 $@

$(UTEXE): $(UTOBJSFULL) $(UTMAKEDEP) | $$(@D)\.
    $(call report,Linking to $(@F))
    $(LINK) $(UTOBJSFULL) $(LNKFLAGS) -o $@
© www.soinside.com 2019 - 2024. All rights reserved.