Make-File:将多个 SRC 文件夹编译为单个 OBJ 文件夹
Posted
技术标签:
【中文标题】Make-File:将多个 SRC 文件夹编译为单个 OBJ 文件夹【英文标题】:Make-File: compile multiple SRC-Folders to single OBJ-Folder 【发布时间】:2021-04-03 19:07:09 【问题描述】:我的项目层次结构如下所示:
+Makefile
+---src
| main.c
| ...
| +---block
| | air.c
| | ...
| |
| +---entity
| | esc.c
| | esc.h
| | ...
| |
| \---world
| \---gen
| noise.c
| ...
| xyz.c
| ...
\---obj
main.o
air.o
esc.o
noise.o
xyz.o
...
我想使用 make 将层次结构中的所有 .c 文件编译到一个 obj 文件夹中。 到目前为止,我得到了:
UNAME_S = $(shell uname -s)
CC = clang
CFLAGS = -std=c11 -O3 -g -Wall -Wextra -Wpedantic -Wstrict-aliasing
CFLAGS += -Wno-pointer-arith -Wno-newline-eof -Wno-unused-parameter -Wno-gnu-statement-expression
CFLAGS += -Wno-gnu-compound-literal-initializer -Wno-gnu-zero-variadic-macro-arguments
CFLAGS += -Ilib/cglm/include -Ilib/glad/include -Ilib/glfw/include -Ilib/stb -Ilib/noise -fbracket-depth=1024
LDFLAGS = lib/glad/src/glad.o lib/cglm/libcglm.a lib/glfw/src/libglfw3.a lib/noise/libnoise.a -lm
# GLFW required frameworks on OSX
ifeq ($(UNAME_S), Darwin)
LDFLAGS += -framework OpenGL -framework IOKit -framework CoreVideo -framework Cocoa
endif
ifeq ($(UNAME_S), Linux)
LDFLAGS += -ldl -lpthread
endif
OBJ_DIR = obj
SRC = $(wildcard src/**/*.c) $(wildcard src/*.c) $(wildcard src/**/**/*.c) $(wildcard src/**/**/**/*.c)
OBJ = $(addprefix $(OBJ_DIR)/,$(addsuffix .o,$(notdir $(basename $(SRC)))))
SRC_DIRS = $(sort $(dir $(SRC)))
BIN = bin
.PHONY: all clean
all: dirs libs game
libs:
cd lib/cglm && cmake . -DCGLM_STATIC=ON && make
cd lib/glad && $(CC) -o src/glad.o -Iinclude -c src/glad.c
cd lib/glfw && cmake . && make
cd lib/noise && make
dirs:
mkdir -p ./$(BIN) ./$(OBJ_DIR)
run: all
$(BIN)/game
game: $(OBJ)
$(CC) -o $(BIN)/game $^ $(LDFLAGS)
$(OBJ_DIR)/%.o: src/%.c
$(CC) -o $@ -c $< $(CFLAGS)
$(OBJ_DIR)/%.o: src/block/%.c
$(CC) -o $@ -c $< $(CFLAGS)
$(OBJ_DIR)/%.o: src/entity/%.c
$(CC) -o $@ -c $< $(CFLAGS)
$(OBJ_DIR)/%.o: src/gfx/%.c
$(CC) -o $@ -c $< $(CFLAGS)
$(OBJ_DIR)/%.o: src/ui/%.c
$(CC) -o $@ -c $< $(CFLAGS)
$(OBJ_DIR)/%.o: src/util/%.c
$(CC) -o $@ -c $< $(CFLAGS)
$(OBJ_DIR)/%.o: src/world/%.c
$(CC) -o $@ -c $< $(CFLAGS)
$(OBJ_DIR)/%.o: src/world/gen/%.c
$(CC) -o $@ -c $< $(CFLAGS)
clean:
rm -rf $(BIN) $(OBJ_DIR)
有什么方法可以更有效地完成这项工作吗?尤其是 $(OBJ_DIR)/%.o 的情况?
变量 $(SRC_DIRS) 存储所有 src 文件夹 变量 $(SRC) 存储所有 .c 文件及其路径 变量 $(OBJ) 存储所有 .o 文件路径和名称【问题讨论】:
**
对于 make 的 wildcard
函数并不特殊。 src/**/*.c
与 src/*/*.c
相同。
一般来说,将所有目标文件放在一个目录中并不是一个好主意:如果将名为 foo.c
的源文件放在两个不同的源目录中,则会发生错误。
我不确定你所说的“同样的事情”发生是什么意思。那是什么东西?显然,如果您将目标文件放在每个源目录的不同目标目录中,则不会发生冲突。
我用 ** 来提醒自己,我指的是文件夹,而不是文件
同一个目录下不可能有两个同名的源文件吧?因此,如果每个源文件都转换为具有相同目录结构的目标文件,则不能有两个冲突的目标文件。也就是说,如果你有src/foo/bar.c
并且你写出obj/foo/bar.o
,那么它不能与src/blah/bar.c
冲突,因为那将变成obj/blah/bar.o
而不是obj/foo/bar.o
。
【参考方案1】:
最好的方法是using VPATH。
例如:
SRC := $(wildcard src/*/*.c) $(wildcard src/*.c) $(wildcard src/*/*/*.c) $(wildcard src/*/*/*/*.c)
OBJ := $(addprefix $(OBJ_DIR)/,$(addsuffix .o,$(notdir $(basename $(SRC)))))
SRC_DIRS := $(sort $(dir $(SRC)))
VPATH := $(SRC_DIRS)
...
$(OBJ_DIR)/%.o: %.c
$(CC) -o $@ -c $< $(CFLAGS)
你只需要一个模式规则。
【讨论】:
以上是关于Make-File:将多个 SRC 文件夹编译为单个 OBJ 文件夹的主要内容,如果未能解决你的问题,请参考以下文章
是否可以将 C# 项目编译为单文件 UMD JavaScript 库?