对我的 Makefile 如何重新制作目标文件感到困惑

Confused how my Makefile is remaking object files

我的 make 文件在尝试重新制作目标文件时找不到我的 include 目录。例如,当我调用 make tests 时,我得到输出:

g++    -c -o sdl_class.o sdl_class.cpp
sdl_class.cpp:9:23: fatal error: sdl_class.h: No such file or directory
#include <sdl_class.h>
                   ^
compilation terminated.
make: *** [sdl_class.o] Error 1

我的 Makefile 是这样的:

#Originally from: http://www.cs.colby.edu/maxwell/courses/tutorials/maketutor/
#But will be heavily modified
IDIR =../include
CC=g++
CFLAGS=-w -I$(IDIR)

#ODIR=obj
LDIR =../lib

LIBS=-lSDL2

_DEPS = sdl_class.h SDL_image.h 
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))

OBJ = sdl_class.o tests.o 
#OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))


%.o: %.cpp $(DEPS)
    $(CC) -c -o $@ $< $(CFLAGS) $(LIBS)

tests: sdl_class.o tests.o
    $(CC) -o $@ $^ $(CFLAGS) $(LIBS)

all: $(OBJ)
    $(CC) -o $@ $^ $(CFLAGS) $(LIBS)

.PHONY: clean

clean:
    rm -f *.o *~ core $(IDIR)/*~ 

我的理解是,当我调用 make tests 时,它应该尝试重新制作 sdl_class.o 文件。然后这应该调用 %.o 规则,它应该尝试通过调用类似的东西来制作目标文件:

g++ -c -o sdl_class.o sdl_class.cpp -w -I../include -lSDL2

然而,事实并非如此,因为它看起来像是在调用 $(CC) -c -o $@ $< $(CFLAGS) $(LIBS),正如您从上面看到的那样。

我对 make 如何构建其规则有根本性的误解吗?很可能,这是我的第一个 Makefile。也许我对编译的一般工作方式感到困惑,因为我对此也有些陌生。

CC/CCFLAGS 用于 C 编译。对于 C++,您应该使用 CXX 和 CXXFLAGS。它们用在内置规则和 LINK.cc 宏中,使 Makefile 更简单,因此更不容易出错。

CXXFLAGS = -Wall ...
prog :  foo.o bar.o
      $(LINK.cc) -o $@ $^

Default linker setting in Makefile for linking C++ object files

我会说问题是一个或多个文件 ../include/sdl_class.h../include/SDL_image.h 不存在。因此,make 决定你的模式规则不匹配(因为不是所有的先决条件都可以找到或制作)并且它默认使用内置规则从 .cpp 文件创建目标文件。

内置规则对 C++ 编译器使用 make 变量 CXX,对 C++ 标志使用 CXXFLAGSCCCFLAGS 变量用于C编译器。这就是为什么您对 CFLAGS 的设置被忽略的原因。

如果你 运行 make -d sdl_class.o 你会看到 make 正在寻找哪个文件以及为什么它决定不使用你的模式规则。

如果你像这样重写你的规则,它会更好地工作:

%.o: %.cpp
        $(CC) -c -o $@ $< $(CFLAGS)

sdl_class.o tests.o: $(DEPS)

因为 make 现在会抱怨找不到或创建相关文件。

当然还有其他问题。您不应该将 $(LIBS) 传递给您的编译命令;仅属于您的 link 行。而且,对于 C++ 编译器,您可能应该坚持使用标准变量 CXX,对于 -I-D 等预处理器标志使用 CPPFLAGS,对于 C++ 编译器使用 CXXFLAGS旗帜。此外,linker 库标志如 -L../lib 进入 LDFLAGS 和 linker 库标志如 -lSDL2 进入 LDLIBS.