C++ Makefile总是重新编译一个文件

C++ Makefile总是重新编译一个文件,c++,c,makefile,gnu-make,C++,C,Makefile,Gnu Make,我正在学习如何设置makefile,但遇到了一个问题。为了证明这一点,我创建了一个简单的“项目”,由源文件main.m和test.m组成 我正在尝试将make设置为编译这些文件(仅当某些内容发生更改时),并将对象文件存储在其他位置(此处为build/) 我的生成文件: OBJ = ./build SOURCES=main.m test.m OBJECTS=$(addprefix $(OBJ)/,$(SOURCES:.m=.o)) EXECUTABLE=test all: $(EXECUTAB

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

我正在尝试将make设置为编译这些文件(仅当某些内容发生更改时),并将对象文件存储在其他位置(此处为
build/

我的生成文件:

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
但是,如果我再次运行
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'.


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

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

您可以通过在该规则中添加一个
|
,使
生成
成为仅订单的先决条件来解决此问题:

$(OBJECTS): $(OBJ)/%.o: %.m | build
我也删除了
/
,因为它没有做任何事情

既然你问了,还有一些其他的评论:

  • 添加一个
    clean
    目标。比如:

    clean:
        rm -rf $(EXECUTABLE) $(OBJ)
    
  • 设置
    OBJ
    时不需要
    /
    。只要
    OBJ=build
    就足够了

  • 您不需要上面提到的
    构建
    上的
    /
    。但这并不重要,因为你无论如何都不应该提到它。使用
    $(OBJ)
    在您看到的任何地方重新安装
    build

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

    $(OBJ):
        -mkdir $(OBJ)
    
    请注意,我已经用上面第3部分提到的
    $(OBJ)
    进行了替换

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

    DEPFILES = $(addprefix $(OBJ)/,$(SOURCES:.m=.d))
    
    然后,通过添加
    -MMD
    标志,让编译器生成它们:

    gcc -MMD -c $< -o $@
    

  • 我想你只是不想把
    /
    附加到
    build
    的几个地方。让我在这里试试。您可以使用
    make-d
    查看
    make
    如何决定要构建什么,如果这样有帮助的话。谢谢。然而,
    make-d
    路由将需要一段时间,因为它输出927行信息:)您可以通过尽可能多地删除隐式规则来平息这种情况。我只是在这里用一个简单的测试项目尝试了你的makefile,它看起来像预期的那样工作。也就是说,在第二次运行时,我只得到了
    make:all无需执行任何操作。
    @CarlNorum似乎与构建/文件夹有关,请参阅我对QYup的编辑。我明白了。回答如下。所以基本上是
    make
    build/
    中创建对象文件,导致它更新并强制重新编译?似乎是这样。这在我的机器上没有发生,但我猜这种行为可能与文件系统有关。或者它也可能与装载参数有关,主要是告诉它何时应该更新时间戳的参数。另外:如果有文件
    build
    和目录
    build/
    ,该怎么办。或者有文件,但目录不在那里?不能两者都在那里,文件系统不允许这样做。如果有一个文件,但没有目录,你最终会遇到麻烦。不过,可能不值得在makefile中加入解决方案。
    DEPFILES = $(addprefix $(OBJ)/,$(SOURCES:.m=.d))
    
    gcc -MMD -c $< -o $@
    
    -include $(DEPFILES)