我正在尝试为我的项目编写一个Makefile,所有*.c
和*.h
文件都在一个名为src
的文件夹中,Makefile看起来像这样 -
CC := gcc
CFLAGS := -g -Wall -ansi -pedantic -std=gnu99
LDFLAGS := -lm
INCLUDES := $(wildcard src/*.h)
IFLAGS := $(addprefix -I/,$(INCLUDES))
SRC := $(wildcard src/*.c)
OBJS := $(patsubst %.c, %.o, $(SRC))
APP := app
all: $(OBJS)
$(APP): $(OBJS)
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
$(OBJS): $(SRC) $(INCLUDES)
$(CC) $(CFLAGS) $(IFLAGS) -c $< -o $@
clean:
rm -rf $(OBJS)
rm -rf *.out
rm -f $(APP)
此时我没有构建可执行文件,只是尝试将它们编译为目标文件,所以当我运行时,我得到了这个输出 -
gcc -g -Wall -ansi -pedantic -std=gnu99 -I/src/structure.h -I/src/rng.h -c src/allocate.c -o src/allocate.o
gcc -g -Wall -ansi -pedantic -std=gnu99 -I/src/structure.h -I/src/rng.h -c src/allocate.c -o src/auxiliary.o
gcc -g -Wall -ansi -pedantic -std=gnu99 -I/src/structure.h -I/src/rng.h -c src/allocate.c -o src/decode.o
gcc -g -Wall -ansi -pedantic -std=gnu99 -I/src/structure.h -I/src/rng.h -c src/allocate.c -o src/display.o
您可以看到,在每个gcc
调用中,源文件名都不会更改,它们总是src/allocate.c
为什么?但是,对象名称已正确扩展,如src/allocate.o
,src/auxiliary.o
和src/decode.o
等。
答案 0 :(得分:3)
看来你在这里混淆了一些东西。
它们基本上是你需要在这里使用的两种规则,它们都有相同的语法:
targets : prerequisites
recipe
当你这样写:
$(APP): $(OBJS)
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
您说要创建$(APP)
,要做到这一点,您需要$(OBJS)
才能存在或创建。
现在你写这个:
$(OBJS): $(SRC) $(INCLUDES)
$(CC) $(CFLAGS) $(IFLAGS) -c $< -o $@
您告诉您要创建.o
个文件列表,以及您需要的所有$(SRC)
和$(INCLUDES)
个别文件。
由于您在配方中使用$<
,这是先决条件列表中的第一个条目的快捷方式,因此您始终会使用相同的源文件进行编译
要做你想做的事,你必须抽象一些东西并告诉make&#34;这就是我希望你建立依赖于相应的任何 .o
文件的方式.c
&#34 ;.这是模式规则的工作:
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<
最终,您的Makefile应如下所示:
APP := app
SRC := $(wildcard src/*.c)
OBJ := $(SRC:.c=.o)
CFLAGS := -W -Wall -g -std=c99 -pedantic
LDLIBS := -lm
all: $(OBJS)
$(APP): $(OBJ)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
clean:
$(RM) $(APP) $(OBJ)
请注意你错过的另外几件事:
-I
预处理器标志(应放在CPPFLAGS
变量中)接受目录,而不是文件。
-ansi
编译器标志是-std=c89
的同义词。您之后立即使用-std=gnu99
,以便最终选择一个
您根本不需要列出头文件。不要打扰。
不要小心使用-r
命令的rm
标记,您最终会删除文件夹。它不是用于删除多个文件,而是用于递归删除,读取你的男人。
您在链接阶段使用了$<
而不是$^
,因此您的可执行文件会遗漏许多目标文件。
解决意见:
GNU make有许多预定义的规则,函数和变量,你应该在使用它们之前使用它们。它具有编译和链接C和C ++程序的基本规则,这就是为什么你的Makefile不需要重新定义已经存在的%.o: %c
规则。
您可以在自己喜欢的shell中输入以下内容来查看所有这些内容:
$ make -p > predefined.mk
$(RM)
,$(CC)
是这些预定义变量之一,您可以自己查看它们实际包含的内容。
现在,由于许多用户都关注头文件依赖关系,所以让我们解决这个问题。您不必手动执行此操作,GCC和Clang等现代编译器会在您设置完成后为您执行此操作。
每个.c
文件的依赖关系将在必须包含在Makefile中的.d
文件中生成。
要告诉编译器在编译时生成这些文件,您需要传递一个预处理器标志:
CPPFLAGS := -MMD
现在依赖项是自动生成的,我们需要包含它们:
DEP := $(OBJ:.o=.d)
-include $(DEP)
你也想清理它们:
clean:
$(RM) $(APP) $(OBJ) $(DEP)
现在你的Makefile看起来像这样:
APP := app
SRC := $(wildcard src/*.c)
OBJ := $(SRC:.c=.o)
DEP := $(OBJ:.o=.d)
CPPFLAGS := -MMD
CFLAGS := -W -Wall -g -std=c99 -pedantic
LDLIBS := -lm
all: $(OBJS)
$(APP): $(OBJ)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
clean:
$(RM) $(APP) $(OBJ) $(DEP)
-include $(DEP)
最后一点:语法$(SRC:.c=.o)
是$(SRC:%.c=%.o)
的快捷方式,也是$(patsubst %.c,%.o,$(SRC))
的快捷方式。