makefile执行另一个目标

sas*_*740 103 makefile

我有一个这样的makefile结构:

all : 
    compile executable

clean :
    rm -f *.o $(EXEC)
Run Code Online (Sandbox Code Playgroud)

我意识到在运行"make all"之前,我一直在我的终端中运行"make clean"然后"clear".在尝试筛选令人讨厌的C++编译错误之前,我喜欢有一个干净的终端.所以我尝试添加第三个目标:

fresh :
    rm -f *.o $(EXEC)
    clear
    make all
Run Code Online (Sandbox Code Playgroud)

这是有效的,但这会运行make的第二个实例(我相信).有没有正确的方法来获得相同的功能而不运行第二个make实例?

Dac*_*cav 147

实际上你是对的:它运行另一个make实例.一个可能的解决方案是:

.PHONY : clearscr fresh clean all

all :
    compile executable

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

fresh : clean clearscr all

clearscr:
    clear
Run Code Online (Sandbox Code Playgroud)

通过调用make fresh你先获得clean目标,然后clearscreen运行clear,最后all完成工作.

编辑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
Run Code Online (Sandbox Code Playgroud)

编辑12月5日

运行多个makefile实例并不是什么大问题,因为任务中的每个命令都是子shell.但是你可以使用call函数获得可重用的方法.

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!")
Run Code Online (Sandbox Code Playgroud)

  • @ sas4740:基本上所有内容都遵循`.PHONY:`被视为一些始终执行的关键字,而非虚假目标则是文件. (4认同)
  • "仅限订单的先决条件"是独立的 (3认同)
  • 我看不出“干净”先于“全部”的保证在哪里?您把它们从| 不能使它们按顺序执行。仅订单依赖性意味着在执行此操作后不必不必要地更新目标。它与依存元素的排序无关...还是? (2认同)
  • 你是对的@CygnusX1,仅顺序依赖关系与按特定顺序执行依赖关系无关;仅将依赖项排序在引用它的目标之前。这个答案的“编辑 8 月 4 日”部分是错误的。 (2认同)

Pio*_*per 23

您已经有了一个顺序解决方案,可以将其重写为:

\n
fresh:\n    $(MAKE) clean\n    clear\n    $(MAKE) all\n
Run Code Online (Sandbox Code Playgroud)\n

这是正确的,也是非常安全的做法。

\n

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

\n
fresh: _all\n_all: _clear\n    Recipe for all\n_clear: _clean\n    Recipe for clear\n_clean:\n    Recipe for clean\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

可以使用以下方法与多个目标共享配方:

\n
target1 target2 target\xe2\x80\xa6:\n    recipe1\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n
all _all : \n    compile executable\nclean _clean :\n    rm -f *.o $(EXEC)\nclear _clear :\n    clear\nfresh: _all\n_all: _clear\n_clear: _clean\n
Run Code Online (Sandbox Code Playgroud)\n

使用https://github.com/pkoper/mk/chains.mk中的语法糖,您可以编写:

\n
all all@fresh :\n    compile executable\nclean clean@fresh :\n    rm -f *.o $(EXEC)\nclear clear@fresh :\n    clear\n\n@fresh = clean clear all\ninclude chains.mk\n\nfresh: @fresh\n
Run Code Online (Sandbox Code Playgroud)\n

或更好:

\n
all: compile\n\n@fresh = clean clear compile\ninclude chains.mk\n\nfresh: @fresh\n\ncompile compile@fresh:\n    compile executable\nclear clear@fresh:\n    clear\nclean clean@fresh:\n    rm -f *.o $(EXEC)\n
Run Code Online (Sandbox Code Playgroud)\n


cod*_*ugh 6

如果您make all从"新鲜"目标中删除了该行:

fresh :
    rm -f *.o $(EXEC)
    clear
Run Code Online (Sandbox Code Playgroud)

您只需运行命令即可make fresh all执行make fresh; make all.

有些人可能会认为这是make的第二个实例,但它肯定不是make的一个子实例(make内部的make),这是你的尝试似乎导致的.