Makefile 总是重新编译一个文件

Posted

技术标签:

【中文标题】Makefile 总是重新编译一个文件【英文标题】:Makefile always recompiling a file 【发布时间】:2013-05-24 20:42:06 【问题描述】:

我正在学习如何设置 makefile,但遇到了问题。为了证明这一点,我创建了一个由源文件 main.mtest.m 组成的简单“项目”。

我正在尝试设置 make 来编译这些文件(仅在发生更改的情况下),并将目标文件存储在其他地方(此处为 build/

我的 Makefile:

OBJ = ./build

SOURCES=main.m test.m
OBJECTS=$(addprefix $(OBJ)/,$(SOURCES:.m=.o))
EXECUTABLE=test

all: $(EXECUTABLE)

$(EXECUTABLE): $(OBJECTS)
        gcc $(OBJECTS) -o $(EXECUTABLE)

$(OBJECTS): $(OBJ)/%.o: %.m build/
        gcc -c $< -o $@

build/:
        mkdir build

当我第一次运行它时(只有 Makefile 和当前目录中的源代码),它会按照我的预期运行:

gcc -c main.m -o build/main.o
gcc -c test.m -o build/test.o
gcc ./build/main.o ./build/test.o -o test

但是,如果我再次运行make

gcc -c main.m -o build/main.o
gcc ./build/main.o ./build/test.o -o test

我做错了什么?还请注意 Makefile 中的任何其他错误,因为我正在尝试学习创建“好”的 Makefile。

编辑:

我从make -d 发现的:

Finished prerequisites of target file `build/main.o'.
Prerequisite `main.m' is older than target `build/main.o'.
Prerequisite `build/' is older than target `build/main.o'.
No need to remake target `build/main.o'.

Finished prerequisites of target file `build/test.o'.
Prerequisite `test.m' is older than target `build/test.o'.
Prerequisite `build/' is newer than target `build/test.o'.
Must remake target `build/test.o'.

【问题讨论】:

我认为您只是不希望在几个地方将/ 附加到build。让我在这里试试。如果有帮助,您可以使用 make -d 查看 make 如何决定构建什么。 谢谢。然而,make -d 路由将需要一段时间,因为它会输出 927 行信息 :) 您可以通过摆脱尽可能多的隐含规则来平息它。我只是在这里用一个简单的测试项目尝试了你的 makefile,它似乎按预期工作。也就是说,在第二次运行时,我只得到make: Nothing to be done for 'all'. @CarlNorum 这似乎与 build/ 文件夹有关,请参阅我对 Q 的编辑 是的。我看到。答案如下。 【参考方案1】:

您的make -d 输出显示make 认为您的构建目录已更新,因此需要重新构建该文件。

我猜这是因为您的构建系统部分或文件系统中的其他部分的某些操作导致该目录上的某些时间戳被更新。

您可以通过将| 添加到该规则,使build 成为仅限订单的先决条件来解决此问题:

$(OBJECTS): $(OBJ)/%.o: %.m | build

我也删除了/,因为它什么也没做。

既然你问了,其他一些编辑说明:

    添加一个clean 目标。比如:

    clean:
        rm -rf $(EXECUTABLE) $(OBJ)
    

    当您设置OBJ 时,您不需要./OBJ = build 就够了。

    您不需要上面提到的build 上的/。但这并不重要,因为无论如何您都不应该提及它。将build 替换为$(OBJ),无论您在哪里看到它。

    如果目录已经存在,mkdir 将失败。您可能应该在该命令前加上 -:

    $(OBJ):
        -mkdir $(OBJ)
    

    请注意,我已经用上面#3 中提到的$(OBJ) 进行了替换。

    依赖项的自动生成非常有帮助。如图所示,您的项目不够大,无法真正需要它,但添加起来很容易,所以为什么不呢。你需要做几件事。首先,获取合适的依赖文件名:

    DEPFILES = $(addprefix $(OBJ)/,$(SOURCES:.m=.d))
    

    然后让编译器通过添加-MMD 标志来生成它们:

    gcc -MMD -c $< -o $@
    

    最后,如果它们可用,请将它们包含在你的 makefile 中,方法是在你的 makefile 末尾添加一行:

    -include $(DEPFILES)
    

【讨论】:

所以基本上是makebuild/中创建目标文件导致它更新并强制重新编译? 好像是这样。这不会在我的机器上发生,但我猜这种行为可能与文件系统有关。 或者它也可能与挂载参数有关,主要是告诉它何时应该更新时间戳的参数。 另外:如果有一个文件build 和目录build/ 会做什么。还是文件有但目录不存在? 你不能同时拥有两者,文件系统不允许。如果有一个文件但没有目录,你最终会遇到麻烦。不过,可能不值得为此在 makefile 中添加解决方法。

以上是关于Makefile 总是重新编译一个文件的主要内容,如果未能解决你的问题,请参考以下文章

Makefile不会在头文件更改时重新编译

避免使用 makefile 进行不必要的重新编译

用于在头文件更改时构建简单 c 项目重新编译的示例 makefile

Makefile工具使用

make与makefile

Makefile 只重新编译更改的对象?