取决于 make 中的目录

发布于 2024-10-07 16:59:43 字数 826 浏览 9 评论 0原文

这是我之前的问题的后续问题: SO 4403861 因为建议的解决方案破坏了依赖关系,使得makefile没用。我不明白为什么。

我正在使用 gnu make 3.82 我有一个规则,如果 obj 目录已创建,则有效:

objdir:=../obj
$(objdir)/%.o: %.C
    $(COMPILE) -MM -MT$(objdir)/$(notdir $@) $< -o $(DEPDIR)/$(notdir $(basename $<).d )
    $(COMPILE) -o $(objdir)/$(notdir $@ ) -c $<

但是,如果 obj 目录不存在,则 make 失败。我希望 make 能够根据需要自动创建 ../obj,所以我添加了我认为非常简单的内容:

$(objdir)/%.o: %.C $(objdir)
    $(COMPILE) -MM -MT$(objdir)/$(notdir $@) $< -o $(DEPDIR)/$(notdir $(basename $<).d )
    $(COMPILE) -o $(objdir)/$(notdir $@ ) -c $<

$(objdir):
   if [ ! -d $(objdir) ] ; then mkdir $(objdir) ; fi

当我这样做时,make 每次都会强制编译。为什么?除非没有目录,否则 mkdir 不应该发生?为什么这个简单的更改会破坏依赖关系?

This is a followup to my earlier question: SO 4403861 because the suggested solutions broke the dependencies, making the makefile useless. I can't figure out why.

I am using gnu make 3.82
I have a rule that works if the obj directory has been created:

objdir:=../obj
$(objdir)/%.o: %.C
    $(COMPILE) -MM -MT$(objdir)/$(notdir $@) 
lt; -o $(DEPDIR)/$(notdir $(basename 
lt;).d )
    $(COMPILE) -o $(objdir)/$(notdir $@ ) -c 
lt;

However, if the obj directory isn't there, make fails. I wanted make to automatically create ../obj on demand, so I added what I thought was very simple:

$(objdir)/%.o: %.C $(objdir)
    $(COMPILE) -MM -MT$(objdir)/$(notdir $@) 
lt; -o $(DEPDIR)/$(notdir $(basename 
lt;).d )
    $(COMPILE) -o $(objdir)/$(notdir $@ ) -c 
lt;

$(objdir):
   if [ ! -d $(objdir) ] ; then mkdir $(objdir) ; fi

When I do so, make always forces the compile, every time. Why? The mkdir should not happen unless there is no directory? Why are dependencies destroyed by this simple change?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

热血少△年 2024-10-14 16:59:43

您还可以尝试使用仅限订单的先决条件。

您的问题有一个类似的例子。

 OBJDIR := objdir
 OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)
 
 $(OBJDIR)/%.o : %.c
         $(COMPILE.c) $(OUTPUT_OPTION) 
lt;
 
 all: $(OBJS)
 
 $(OBJS): | $(OBJDIR)
 
 $(OBJDIR):
         mkdir $(OBJDIR)

You also can try with Order-only prerequisites.

There is a similar example, of your question, available.

 OBJDIR := objdir
 OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)
 
 $(OBJDIR)/%.o : %.c
         $(COMPILE.c) $(OUTPUT_OPTION) 
lt;
 
 all: $(OBJS)
 
 $(OBJS): | $(OBJDIR)
 
 $(OBJDIR):
         mkdir $(OBJDIR)
ゃ懵逼小萝莉 2024-10-14 16:59:43

正如其他人所说,问题在于,每当添加或删除目录成员时,目录都会被视为“更改”,因此 make 会看到您的输出目录一直在更改,并重新运行您告诉它的所有编译取决于输出目录。

作为其他人描述的解决方法的替代方案,最近的 GNU make 版本支持“仅订单先决条件”。 手册中对仅限订购先决条件的描述包括如何使用它们创建目录的示例。

As others have said, the problem is that a directory is considered "changed" whenever directory members are added or removed, so make sees your output directory changing all the time, and reruns all the compilations which you have told it depend on the output directory.

As an alternative to the workarounds described by others, recent GNU make versions have support for "order-only prerequisites". The description of order-only prerequisites in the manual includes an example of how to use them for directory creation.

好听的两个字的网名 2024-10-14 16:59:43

某种哨兵文件可以很好地解决这个问题。允许您编写单个模式规则来创建所有文件夹,不存在任何恶意重新编译问题,并且 -j 安全。

OBJDIR := objdir/
OBJS := $(addprefix ${OBJDIR},foo.o bar.o baz.o)

all: ${OBJS}

${OBJDIR}%.o : %.c ${OBJDIR}.sentinel
     ${COMPILE.c} ${OUTPUT_OPTION} 
lt;

# A single pattern rule will create all appropriate folders as required
.PRECIOUS: %/.sentinel # otherwise make (annoyingly) deletes it
%/.sentinel:
     mkdir -p ${@D}
     touch $@

Some sort of sentinel file will solve this quite nicely. Allows you to write a single pattern rule to create all folders, does not have any rogue recompilation issues, and is -j safe.

OBJDIR := objdir/
OBJS := $(addprefix ${OBJDIR},foo.o bar.o baz.o)

all: ${OBJS}

${OBJDIR}%.o : %.c ${OBJDIR}.sentinel
     ${COMPILE.c} ${OUTPUT_OPTION} 
lt;

# A single pattern rule will create all appropriate folders as required
.PRECIOUS: %/.sentinel # otherwise make (annoyingly) deletes it
%/.sentinel:
     mkdir -p ${@D}
     touch $@
白况 2024-10-14 16:59:43

正如已经回答的那样,您不能将带有输出文件的目录作为依赖项,因为它每次都会更新。

一种解决方案(如上所述)是在每次构建之前放置一个 mkdir -p,如下所示:

objdir:=../obj
$(objdir)/%.o: %.C
    @mkdir -p $(objdir) $(DEPDIR) ...
    $(COMPILE) -MM -MT$(objdir)/$(notdir $@) 
lt; -o $(DEPDIR)/$(notdir $(basename 
lt;).d )
    $(COMPILE) -o $(objdir)/$(notdir $@ ) -c 
lt;

但我不喜欢这个解决方案,因为它强制多次运行额外的进程。但是,知道错误的原因后,还有另一种方法:

exe: dirs $(OBJ)

在构建可执行文件的主要目标中,只需在对象之前插入目标目录即可。因为它是按顺序命中的:

dirs:
    @mkdir -p $(objdir) $(DESTDIR) ...

并且这只在整个构建中执行一次,而不是每个文件执行一次。

As answered already, you cannot put a directory with output files as a dependency, because it is updated every time.

One solution (stated above) is to put a mkdir -p before each build, like this:

objdir:=../obj
$(objdir)/%.o: %.C
    @mkdir -p $(objdir) $(DEPDIR) ...
    $(COMPILE) -MM -MT$(objdir)/$(notdir $@) 
lt; -o $(DEPDIR)/$(notdir $(basename 
lt;).d )
    $(COMPILE) -o $(objdir)/$(notdir $@ ) -c 
lt;

But I don't love this solution, because it forces running an extra process lots and lots of times. However, knowing the reason for the error, there is another way:

exe: dirs $(OBJ)

In the primary target, the one building the executable, just insert a target dirs before the objects. Since it's hit in order:

dirs:
    @mkdir -p $(objdir) $(DESTDIR) ...

and this is only done once for the entire build, rather than once per file.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文