Makefile始终重新编译文件

var*_*esa 12 c c++ makefile gnu-make

我正在学习如何设置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
Run Code Online (Sandbox Code Playgroud)

当我第一次运行它时(只有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
Run Code Online (Sandbox Code Playgroud)

但是,如果我make再次运行:

gcc -c main.m -o build/main.o
gcc ./build/main.o ./build/test.o -o test
Run Code Online (Sandbox Code Playgroud)

我做错了什么?还要注意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'.
Run Code Online (Sandbox Code Playgroud)

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'.
Run Code Online (Sandbox Code Playgroud)

Car*_*rum 12

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

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

您可以通过解决问题build顺序,唯一的前提条件通过添加|到规则:

$(OBJECTS): $(OBJ)/%.o: %.m | build
Run Code Online (Sandbox Code Playgroud)

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

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

  1. 添加clean目标.就像是:

    clean:
        rm -rf $(EXECUTABLE) $(OBJ)
    
    Run Code Online (Sandbox Code Playgroud)
  2. 您不需要./设置时间OBJ.仅仅OBJ = build是不够的.

  3. 您不需要如上所述的/on build.但这并不重要,因为无论如何你不应该把它提到它.Repalce build$(OBJ)无论你看到它.

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

    $(OBJ):
        -mkdir $(OBJ)
    
    Run Code Online (Sandbox Code Playgroud)

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

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

    DEPFILES = $(addprefix $(OBJ)/,$(SOURCES:.m=.d))
    
    Run Code Online (Sandbox Code Playgroud)

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

    gcc -MMD -c $< -o $@
    
    Run Code Online (Sandbox Code Playgroud)

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

    -include $(DEPFILES)
    
    Run Code Online (Sandbox Code Playgroud)