问题 Makefile始终重新编译文件


我正在学习如何设置makefile,并遇到了问题。为了证明这一点,我创建了一个由源文件组成的简单“项目” main.m 和 test.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'.

10608
2018-05-24 20:42


起源

我想你只是不想要的 / 附属于 build 在几个地方。我试试吧。您可以使用 make -d 看怎么样 make 如果有帮助,正在决定建造什么。 - Carl Norum
谢谢。但是,那 make -d 路线需要一段时间,因为它输出927行信息:) - varesa
你可以通过摆脱尽可能多的隐含规则来平息下来。我刚刚尝试了你的makefile,虽然有一个简单的测试项目,它似乎按预期工作。也就是说,在第二轮比赛中,我得到了 make: Nothing to be done for 'all'.。 - Carl Norum
@CarlNorum它似乎与build /文件夹有关,请参阅我对Q的编辑 - varesa
对。我看到。回答如下。 - Carl Norum


答案:


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

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

您可以通过制作来解决问题 build 一个 仅限订单的先决条件 通过添加一个 | 遵守该规则:

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

我删除了 / 因为它没有做任何事情。

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

  1. 添加一个 clean 目标。就像是:

    clean:
        rm -rf $(EXECUTABLE) $(OBJ)
    
  2. 你不需要 ./ 当你设置 OBJ。只是 OBJ = build 足够。

  3. 你不需要 / 上 build 正如刚才提到的。但这并不重要,因为无论如何你不应该把它提到它。 Repalce build 同 $(OBJ) 无论你在哪里看到它。

  4. mkdir 如果目录已存在,则会失败。您可能应该在该命令前加上一个 -

    $(OBJ):
        -mkdir $(OBJ)
    

    请注意,我已经完成了替换 $(OBJ) 我在上面的#3中提到过。

  5. 自动生成依赖项非常有用。你所展示的项目不够大,不足以真正需要它,但它很容易添加,所以为什么不呢。你需要做几件事。首先,获取适当的依赖文件名:

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

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

    gcc -MMD -c $< -o $@
    

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

    -include $(DEPFILES)
    

10
2018-05-24 20:53



基本上就是这样 make 在中创建目标文件 build/ 导致它更新并强制重新编译? - varesa
好像那样。这不会发生在我的机器上,但我猜这种行为可能与文件系统有关。 - Carl Norum
或者它也可能与mount参数有关,主要是告诉它什么时候应该更新时间戳。 - varesa
另外:如果有文件,make会怎么做 build 和目录 build/。或者有文件,但目录不存在? - varesa
你不能在那里,文件系统不允许它。如果有文件而不是目录,你最终会遇到麻烦。但是,可能不值得将解决方法放入makefile中。 - Carl Norum