Makefile示例

目录

主要修改点:

  1. 定义 BUILD_DIR:指定存放 .o 文件的目录(这里设为 build)。

  2. 重构 OBJS 变量:使用模式替换,将源文件列表(如 src/a.c)映射到构建目录(如 build/src/a.o)。

  3. 自动创建目录:在编译规则中增加 mkdir -p,确保在编译 .o 之前,对应的子目录结构已经存在。

  4. 修正 Shared Library 标志:既然目标是 .so (动态库),我为你加上了 -fPIC (编译期) 和 -shared (链接期),这是 Linux 下编译动态库的标准做法(原 Makefile 缺少这些会导致不可用)。

优化后的 Makefile

Makefile

# 目标文件
TARGET = libucp.so
# 构建目录(存放 .o 文件)
BUILD_DIR = build

# 获取所有 .c 源文件
SRC := $(shell find . -type f -name "*.c")
# 将 .c 文件列表转换为 build 目录下的 .o 文件列表
# 例如: ./src/main.c -> build/./src/main.o
OBJS := $(SRC:%.c=$(BUILD_DIR)/%.o)

CC = gcc

# 编译选项
# 注意:编译动态库通常需要 -fPIC
CFLAGS = -O0 -g -fPIC
CFLAGS += -I/usr/include/glib-2.0/ -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
# 保留原本的头文件查找逻辑
CFLAGS += $(shell find . -type f -name "*.h" -exec dirname {} \; | sort -u | xargs printf "-I%s ")

# 链接选项
LDFLAGS = -Lucp_stack/libs/lib
# 生成 .so 必须加上 -shared
LDFLAGS += -shared

LIBS = -lpthread -lglib-2.0

# 伪目标,防止文件名冲突
.PHONY: all clean

all: $(TARGET)

# 链接规则
$(TARGET): $(OBJS)
	@echo "Linking $@"
	$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) $(LIBS)

# 编译规则
# $(BUILD_DIR)/%.o 匹配 build 目录下的目标
# %.c 匹配当前目录下对应的源文件
$(BUILD_DIR)/%.o: %.c
	@echo "Compiling $<"
	@mkdir -p $(dir $@)
	$(CC) $(CFLAGS) -c $< -o $@

# 清理规则
clean:
	@echo "Cleaning build directory and target..."
	$(RM) -r $(BUILD_DIR) $(TARGET)

代码详解

1. 路径映射的核心逻辑

OBJS := $(SRC:%.c=$(BUILD_DIR)/%.o)

这行代码使用了 Make 的模式替换。假设 SRCsrc/foo.cBUILD_DIRbuild,那么 OBJS 就会自动变成 build/src/foo.o

2. 编译规则与目录创建

$(BUILD_DIR)/%.o: %.c
	@mkdir -p $(dir $@)
	$(CC) $(CFLAGS) -c $< -o $@
  • Target ($(BUILD_DIR)/%.o): 告诉 Make 如何生成位于 build/ 下的 .o 文件。

  • Dependency (%.c): 它依赖于源码树中相同路径的 .c 文件。

  • @mkdir -p $(dir $@): 这是一个关键技巧。$@ 是目标文件(例如 build/src/net/tcp.o),$(dir $@) 取出目录部分(build/src/net/)。mkdir -p 会在编译前递归创建这个目录结构,防止编译器报错“目录不存在”。

3. 动态库标志 (Important)

原 Makefile 中编译 .so 文件却没有加 -fPIC-shared

  • -fPIC: Position Independent Code,编译 .o 时必须加,否则无法合并进动态库。

  • -shared: 链接时必须加,告诉 gcc 生成共享库而不是可执行文件。