【问题标题】:Why does my target always get recompiled, even if nothing has changed in code?为什么我的目标总是重新编译可执行文件,即使代码没有任何变化?
【发布时间】:2019-09-22 19:36:02
【问题描述】:

我几乎是编写 Makefile 的新手,对于可能出现的小错误,我深表歉意。 即使源代码没有任何变化,我的 Makefile 也会不断重新编译可执行文件 (.out)。 目标对其他对象有一些依赖。无论如何,这些对象不会重新编译相关的源文件(就像它应该的那样)。 那么为什么目标要重新编译 .out 文件呢?

任何其他建议将不胜感激。

# -*- Makefile -*-

CC:= nvcc
CFLAGS:= -std=c++14 -g -DMEASURES
ALLFLAGS:= $(CFLAGS) -Iinclude/ 
LOWPAR:= $(ALLFLAGS) -DLOWPAR


BIN:=bin/
SRC:=src/
INCLUDE:=include/


.PHONY: future managed stream clean

####DEVICE####
#cos future, stream, managed
future: $(BIN)main_cos.o $(BIN)farmkernels.o $(BIN)cudaUtils.o
    $(CC) $(ALLFLAGS) $(BIN)main_cos.o $(BIN)farmkernels.o $(BIN)cudaUtils.o -o $(BIN)future.out

managed: $(BIN)main_cos.o $(BIN)farmkernels.o $(BIN)cudaUtils.o
    $(CC) $(ALLFLAGS) $(BIN)main_cos.o $(BIN)farmkernels.o $(BIN)cudaUtils.o -o $(BIN)managed.out

stream: $(BIN)main_cos.o $(BIN)farmkernels.o $(BIN)cudaUtils.o
    $(CC) $(ALLFLAGS) $(BIN)main_cos.o $(BIN)farmkernels.o $(BIN)cudaUtils.o -o $(BIN)stream.out


$(BIN)main_cos.o: $(SRC)main_cos.cpp $(INCLUDE)cosFutStr.h $(INCLUDE)cudaUtils.h
    $(CC) $(ALLFLAGS) -c $(SRC)main_cos.cpp -D$(shell echo $(MAKECMDGOALS) | tr a-z A-Z) -o $(BIN)main_cos.o

$(BIN)farmkernels.o:  $(SRC)farmkernels.cu $(INCLUDE)cosFutStr.h $(INCLUDE)cudaUtils.h
    $(CC) $(ALLFLAGS) -c $(SRC)farmkernels.cu -o $(BIN)farmkernels.o

$(BIN)cudaUtils.o: $(SRC)cudaUtils.cpp  $(INCLUDE)cudaUtils.h
    $(CC) $(ALLFLAGS) -c $(SRC)cudaUtils.cpp -o $(BIN)cudaUtils.o

####clean####
clean:
    rm -f $(BIN)*.o 
    rm -f $(BIN)*.out

例如当我输入时

make future

第一次编译所有内容时:

nvcc -std=c++14 -g -DMEASURES -Iinclude/  -c src/main_cos.cpp -DFUTURE -o bin/main_cos.o
nvcc -std=c++14 -g -DMEASURES -Iinclude/  -c src/farmkernels.cu -o bin/farmkernels.o
nvcc -std=c++14 -g -DMEASURES -Iinclude/  -c src/cudaUtils.cpp -o bin/cudaUtils.o
nvcc -std=c++14 -g -DMEASURES -Iinclude/  bin/main_cos.o bin/farmkernels.o bin/cudaUtils.o -o bin/future.out

如果我不更改代码中的任何内容并立即重新键入 make future,我希望类似“无事可做...”。 但我得到的是:

nvcc -std=c++14 -g -DMEASURES -Iinclude/  bin/main_cos.o bin/farmkernels.o bin/cudaUtils.o -o bin/future.out

【问题讨论】:

  • 相当,但并非完全无关:stackoverflow.com/a/32782220/1848654
  • @melpomene: linux 似乎比c++ 更适合这个问题。由于依赖关系确定取决于时间戳,因此文件系统可能是相关的(不是,但我们不希望询问者知道这一点)。此外,操作系统肯定会影响正在使用的make 版本。
  • @BenVoigt 标签描述说“仅当您的问题与使用 Linux API 或 Linux 特定行为的编程有关时才使用此标签”。我认为它不适用于这里。如果您在例如BSD 或 Mac OS。
  • @melpomene:当你问这个问题时,你不知道该行为是否是特定于 linux 的。
  • @BenVoigt 是的,但我知道不是,所以我删除了标签。 :-)

标签: linux makefile cuda rebuild


【解决方案1】:

为什么目标总是重新编译?

您已指出future 是“虚假目标”。这意味着:

  • future 与实际文件不对应,即
  • Make 无法检查日期以确定 future 是否是最新的,因此
  • future 永远不会是最新的,因此
  • 无论何时构建future,都必须为其执行命令

您的链接命令列在future 目标下;所以它每次都会重新运行。

有关.PHONY的更深入解释,请参阅:What is the purpose of .PHONY in a makefile?

为什么你可以这样做

两种选择:

  1. 使用文件目标。您的future 目标的命令会生成$(BIN)future.out,对吗?因此,将其替换为 $(BIN)future.out 目标,然后构建它。
  2. 添加一个$(BIN)future.out 目标,但为了方便起见,不要直接构建它——让future 目标依赖它,就像@BenVoigt 建议的那样:

    .PHONY: future other_pho ny_target s_here
    
    future: $(BIN)future.out
    
    $(BIN)future.out: $(BIN)main_cos.o $(BIN)farmkernels.o $(BIN)cudaUtils.o
        $(CC) $(ALLFLAGS) $(BIN)main_cos.o $(BIN)farmkernels.o $(BIN)cudaUtils.o -o $(BIN)future.out
    

【讨论】:

  • 作为初学者,我不知道 .PHONY 目标中的“未来永远不会是最新的”!关于您提出的解决方案,对我来说,第二个(@BenVoigt)是正确的。因为目标名称(例如 future)随后在对象中用作 c++ 宏:-D$(shell echo $(MAKECMDGOALS) | tr a-z A-Z)
  • @MariaChiaraCecconi:没有像“未来永远不会是最新的”这样的规则。它不是规则,而是您设计的结果。您永远不会创建名为“future”的文件,因此没有文件时间戳。因此make比较文件时间戳时,发现“future”缺失,需要重建。 .PHONY 还会导致时间戳被忽略,如果有的话(也就是说,也没有“假目标不对应于实际文件”的规则),尽管不对应于实际文件的目标应该是假的,不需要反过来。
【解决方案2】:

您明确告诉make 始终在不考虑依赖时间戳的情况下进行重建:

.PHONY: future managed stream clean

make 正在按照您的要求进行操作。


如果您想要好的命名目标而不导致重建,请不要为命名目标编写规则。相反,给他们依赖。正如您已经注意到的,.PHONY 不会强制重建所有依赖项,它只运行直接规则。

.PHONY: future managed stream clean

future: $(BIN)future.out

$(BIN)future.out: $(BIN)main_cos.o $(BIN)farmkernels.o $(BIN)cudaUtils.o
    $(CC) $(ALLFLAGS) $+ -o $@

(也根据“不要重复自己”的原则使用自动变量)

【讨论】:

  • 非常有用的解决方案!而且我不知道自动变量,所以我读了一些关于它的东西。我发现$+“就像$^,但不止一次列出的先决条件按照它们在makefile中列出的顺序重复。这主要用于链接命令,其中重复库文件名是有意义的一个特定的命令。”所以我问自己在我的情况下使用$^ 是否相同。为什么专门使用$+
  • @MariaChiaraCecconi:因为它是一个链接命令,如果您最终开始将库添加到依赖行而不是普通对象文件,我不希望您遇到麻烦。
猜你喜欢
  • 2014-01-28
  • 2014-12-10
  • 1970-01-01
  • 2016-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-19
  • 2011-02-03
相关资源
最近更新 更多