Makefile 执行另一个目标

我有一个类似这样的 makefile 结构:

all :
compile executable


clean :
rm -f *.o $(EXEC)

我意识到,在运行“ make all”之前,我一直在终端中运行“ make clean”,然后是“ clear”。在尝试筛选讨厌的 C + + 编译错误之前,我希望有一个干净的终端。所以我试图增加第三个目标:

fresh :
rm -f *.o $(EXEC)
clear
make all

这可以工作,但是它运行第二个 make 实例(我相信)。有没有一种正确的方法可以在不运行 make 的第二个实例的情况下获得相同的功能?

202951 次浏览

实际上您是对的: 它运行另一个 make 实例。 一个可能的解决办法是:

.PHONY : clearscr fresh clean all


all :
compile executable


clean :
rm -f *.o $(EXEC)


fresh : clean clearscr all


clearscr:
clear

通过调用 make fresh,首先得到 clean目标,然后是运行 clearclearscreen,最后是运行 allall

8月4日编辑

在使用 make 的 -j选项进行并行构建的情况下会发生什么? 有一种方法可以修改订单,制造手册第4.2节:

但是,偶尔会出现这样的情况,即希望对要调用的规则强制执行特定的顺序,而不强制在执行其中一个规则时更新目标。在这种情况下,您需要定义仅限于订单的先决条件。可以通过在先决条件列表中放置一个管道符号(|)来指定仅限于订单的先决条件: 管道符号左侧的任何先决条件都是正常的; 右侧的任何先决条件都是仅限于订单的: 目标: 正常-先决条件 | 仅限于订单-先决条件

当然,正常的先决条件部分可能是空的。此外,您仍然可以为同一个目标声明多行先决条件: 它们被适当地追加。请注意,如果将同一个文件声明为普通的和只有订单的先决条件,则普通先决条件具有优先权(因为它们是仅有订单的先决条件行为的严格超集)。

因此 makefile 变成

.PHONY : clearscr fresh clean all


all :
compile executable


clean :
rm -f *.o $(EXEC)


fresh : | clean clearscr all


clearscr:
clear

12月5日编辑

运行多个 makefile 实例并不是什么大问题,因为任务中的每个命令都将是 sub-shell。但是您可以使用 call function获得可重用的方法。

log_success = (echo "\x1B[32m>> $1\x1B[39m")
log_error = (>&2 echo "\x1B[31m>> $1\x1B[39m" && exit 1)


install:
@[ "$(AWS_PROFILE)" ] || $(call log_error, "AWS_PROFILE not set!")
command1  # this line will be a subshell
command2  # this line will be another subshell
@command3  # Use `@` to hide the command line
$(call log_error, "It works, yey!")


uninstall:
@[ "$(AWS_PROFILE)" ] || $(call log_error, "AWS_PROFILE not set!")
....
$(call log_error, "Nuked!")

如果你从你的“新鲜”目标中删除了 make all行:

fresh :
rm -f *.o $(EXEC)
clear

您可以简单地运行命令 make fresh all,它将作为 make fresh; make all执行。

有些人可能认为这是 make 的第二个实例,但是它肯定不是 make 的子实例(make 中的 make) ,这似乎是您尝试的结果。

你已经有了一个连续的解决方案,可以重写为:

fresh:
$(MAKE) clean
clear
$(MAKE) all

这是正确且非常安全的方法。

使用适当的依赖关系图,在 GNU make 中可以顺序执行目标:

fresh: _all
_all: _clear
Recipe for all
_clear: _clean
Recipe for clear
_clean:
Recipe for clean

上述规则定义了以下依赖关系图: fresh <-_all <-_clear <-_clean,它保证了以下配方执行顺序: Recipe for cleanRecipe for clearRecipe for all

食谱可以通过以下方式与多个目标共享:

target1 target2 target…:
recipe1

将您的脚本与上述概念合并会产生以下结果:

all _all :
compile executable
clean _clean :
rm -f *.o $(EXEC)
clear _clear :
clear
fresh: _all
_all: _clear
_clear: _clean

使用 https://github.com/pkoper/mk/中的 chains.mk,你可以写:

all all@fresh :
compile executable
clean clean@fresh :
rm -f *.o $(EXEC)
clear clear@fresh :
clear


@fresh = clean clear all
include chains.mk


fresh: @fresh

或者更好:

all: compile


@fresh = clean clear compile
include chains.mk


fresh: @fresh


compile compile@fresh:
compile executable
clear clear@fresh:
clear
clean clean@fresh:
rm -f *.o $(EXEC)