【发布时间】:2021-06-06 16:28:14
【问题描述】:
我有一个包含大量头文件和源文件的大型项目。我想要的是以下但自动的
生成文件
INCLUDE = -Iinc
CFLAGS = -g
LIB = lib/foo_bar.a
all: obj/foo_print_hello.o\
obj/foo_print_goodbye.o\
obj/bar_print_goodbye.o\
obj/bar_print_hello.o\
obj/main.o\
lib/foo_bar.a\
bin/main\
obj/foo_print_hello.o: src/foo_print_hello.c inc/foo.h
$(CC) $(INCLUDE) -c $(CFLAGS) -o $@ $<
obj/foo_print_goodbye.o: src/foo_print_goodbye.c inc/foo.h
$(CC) $(INCLUDE) -c $(CFLAGS) -o $@ $<
obj/bar_print_goodbye.o: src/bar_print_goodbye.c inc/bar.h
$(CC) $(INCLUDE) -c $(CFLAGS) -o $@ $<
obj/bar_print_hello.o: src/bar_print_hello.c inc/bar.h
$(CC) $(INCLUDE) -c $(CFLAGS) -o $@ $<
obj/main.o: src/main.c inc/foo.h inc/bar.h
$(CC) $(INCLUDE) -c $(CFLAGS) -o $@ $<
lib/foo_bar.a: obj/bar_print_hello.o obj/bar_print_goodbye.o obj/foo_print_goodbye.o obj/foo_print_hello.o inc/bar.h inc/foo.h
ar -crv $@ $^
bin/main: obj/main.o
$(CC) -o $@ $< $(LIB)
文件架构如下
.
├── bin
│ └── main
├── inc
│ ├── bar.h
│ └── foo.h
├── lib
│ └── foo_bar.a
├── makefile
├── obj
│ ├── bar_print_goodbye.o
│ ├── bar_print_hello.o
│ ├── foo_print_goodbye.o
│ ├── foo_print_hello.o
│ └── main.o
└── src
├── bar_print_goodbye.c
├── bar_print_hello.c
├── foo_print_goodbye.c
├── foo_print_hello.c
└── main.c
我想要这种精确的编译结构,它将它们全部编译成目标文件,然后是库函数,然后是用 main 编译。我在 GNU 和互联网上看到了很多模板,但都没有什么效果。如何让我的 makefile 自动生成 obj(将它们放在 obj 目录中)然后编译到存档中?
编译什么
cc -Iinc -c -g -o obj/foo_print_hello.o src/foo_print_hello.c
cc -Iinc -c -g -o obj/foo_print_goodbye.o src/foo_print_goodbye.c
cc -Iinc -c -g -o obj/bar_print_goodbye.o src/bar_print_goodbye.c
cc -Iinc -c -g -o obj/bar_print_hello.o src/bar_print_hello.c
cc -Iinc -c -g -o obj/main.o src/main.c
ar -crv lib/foo_bar.a obj/bar_print_hello.o obj/bar_print_goodbye.o obj/foo_print_goodbye.o obj/foo_print_hello.o inc/bar.h inc/foo.h
r - obj/bar_print_hello.o
r - obj/bar_print_goodbye.o
r - obj/foo_print_goodbye.o
r - obj/foo_print_hello.o
r - inc/bar.h
r - inc/foo.h
cc -o bin/main obj/main.o lib/foo_bar.a
主输出
Hello
Goodbye
Hello
Goodbye
代码仓库:
git@github.com:tlplayer/dummy_makefile_question.git
跟进
所以我尝试了以下makefile
SRCS := $(wildcard src/*.c)
OBJS := $(patsubt src/%.c, obj/%.o, $(SRCS))
LIB := lib/foo_bar.a
all: bin/main
obj/%.o: src/%.c
$(CC) $(INCLUDE) -c $(CFLAGS) -o $@ $<
$(LIB): obj/%.o
ar -crv $@ $^
bin/main: obj/main.o $(LIB)
$(CC) -o $@ $< $(LIB)
问题是它不知道我想要它做什么。是否将标头添加到 makefile(依赖项中的 foo.h bar.h)
make: *** No rule to make target `obj/%.o', needed by `lib/foo_bar.a'. Stop.
跟进 2
当前生成文件
INCLUDE = -Iinc
CFLAGS = -g
LIB = lib/foo_bar.a
SRCS := $(wildcard src/*.c)
OBJS := $(patsubt src/%.c, obj/%.o, $(SRCS))
OBJS := $(filter-out obj/main.o, $(OBJS))
all: bin/main\
obj/%.o: src/%.c
$(CC) $(INCLUDE) -c $(CFLAGS) -o $@ $<
$(LIB): $(OBJS)
ar -crv $@ $^
bin/main: obj/main.o $(LIB)
$(CC) -o $@ $^
错误是什么
cc -Iinc -c -g -o obj/main.o src/main.c
ar -crv lib/foo_bar.a
cc -o bin/main obj/main.o lib/foo_bar.a
obj/main.o: In function `main':
test/src/main.c:6: undefined reference to `foo_print_hello'
test/src/main.c:7: undefined reference to `foo_print_goodbye'
test/src/main.c:8: undefined reference to `bar_print_hello'
test/src/main.c:9: undefined reference to `bar_print_goodbye'
collect2: error: ld returned 1 exit status
make: *** [bin/main] Error 1
由于某种原因,它先编译 main.o,然后编译归档文件。但是存档缺少所有目标文件。那么为什么不包含对象呢?
解决方案
感谢 MadScientist 和 Topology
INCLUDE = -Iinc
CFLAGS = -g
LIB = lib/foo_bar.a
SRCS := $(wildcard src/*.c)
OBJS := $(patsubst src/%.c, obj/%.o, $(SRCS))
OBJS := $(filter-out obj/main.o, $(OBJS))
all:bin/main\
clean:
rm -f obj/* bin/* lib/*
obj/%.o: src/%.c
$(CC) $(INCLUDE) -c $(CFLAGS) -o $@ $<
lib/foo_bar.a: $(OBJS)
ar -crv $@ $^
bin/main: obj/main.o $(LIB)
$(CC) -o $@ $^
【问题讨论】:
-
你能定义自动是什么意思吗?我的意思是,make 总是要求你输入
make,所以它不会 100% 自动发生。一旦你输入make,它应该“做所有的事情”,而不需要你的任何输入。您希望看到哪些不是“自动”的? -
@MadScientist 自动我的意思是像this 这样它会从 src 目录中找到所有 .c 文件,然后将它们编译成 obj 目录中的 .o 文件。然后将其编译到 lib 目录中的 .a lib 中。我有 30 个源文件和 3 个头文件,我想成为 .o 文件,然后是 .a 文件。
-
上述错误的原因是模式规则必须在目标中有模式(带有
%的单词)。如果目标中没有模式,这不是模式规则,它只是一个常规的显式规则,你说它取决于文字文件名obj/%.o。 -
在模式规则中考虑模式是错误的,比如 shell 通配符 (
*)。它们不是那样的,模式规则不是这样工作的。模式规则是一个模板,用于如何构建目标的类,而无需指定目标的精确名称。模式规则不是关于如何从一堆其他文件构建特定文件的语句。这是一个明确的规则。 -
问题是您在 makefile 中拼写了
patsubst错误。你拼写了patsubt。