首页 > 解决方案 > 使用 Make 的多个嵌套目录

问题描述

我有这个 Makefile。

# Variables
CC = gcc
CFLAGS = -Wall -g -c
ODUMP = objdump
ODFLAGS = -d

# Directories
OBJDIR := obj
TGTDIR := target
SRCDIR := src
DMPDIR := dump

# Sources list
SRCS := main.c kernel.c
# Sources location
VPATH := src:../headers

# Objects list
objects = $(notdir $(patsubst %.c,%.o,$(addprefix $(SRCDIR)/,$(SRCS))))
# Objects list with prefix
prefix_objs = $(addprefix $(OBJDIR)/, $(objects))

# Target name
target = main

$(target) : $(prefix_objs)
    $(CC) -o $(TGTDIR)/$@ $(prefix_objs)

$(OBJDIR)/%.o: %.c | folders
    $(CC) $(CFLAGS) -o $@ $<
    $(ODUMP) $(ODFLAGS) $@ > $(DMPDIR)/$@

folders:
    mkdir -p $(OBJDIR)
    mkdir -p $(TGTDIR)
    mkdir -p $(DMPDIR)/$(OBJDIR)

.PHONY: clean
clean:
    rm -rf $(OBJDIR) $(TGTDIR) $(DMPDIR) *.o

我希望能够支持嵌套在 src 目录下的至少一层深的“模块或功能”。我也希望能够不必手动构建# Sources list SCRS := main.c kernel.c 我的文件夹结构如下

| dump
| obj
| src ----
    | kernel.c
    | kernel.h
    | main.c
| target
| .gitignore
| Makefile
| README.md

但是,我希望能够支持。

| dump
| obj
| src ----
    | kernel ----
        | kernel.h
        | thing.c
        | kernel.c
        | any.c
    | feature1 ----
        | ...whatever files
    | main.c
| target
| .gitignore
| Makefile
| README.md

如果你看我的folders规则。我必须显式创建,$(DMPDIR)/$(OBJDIR)因为$(OBJDIR)/%.o目标会添加前缀,即使对于转储文件也是如此。如果我开始为我的“功能”添加文件夹,我也需要支持 mkdir,因为它会是obj/kernel/kernal.o. 我还需要列出 SRCS 中的每个文件......现在推荐的使用方式VPATH也已经崩溃,因为它不再只是src. 似乎增加了一个新的要求已经增加了扩展这个 Makefile 的难度。是否有任何 GNU Make 技巧来帮助支持嵌套目录?

标签: makefilegnu-make

解决方案


查找子目录和子子目录中的所有源文件:

SRCS := $(wildcard $(SRCDIR)/*.c $(SRCDIR)/*/*.c)

为什么要做“objects”/“prefix_objects”这件事?只需制作目标文件:

OBJS := $(patsubst $(SRCDIR)/%.c,$(OBJDIR)/%.o,$(SRCS))

编写一个规则,objsrc. 创建目标目录:

$(OBJDIR)/%.o : $(SRCDIR)/%.c
        @mkdir -p $(@D) $(DMPDIR)/$(@D)
        $(CC) $(CFLAGS) -o $@ $<
        $(ODUMP) $(ODFLAGS) $@ > $(DMPDIR)/$@

修复你的链接线:

$(TGTDIR)/$(target) : $(OBJS)
        $(CC) -o $@ $^

如果你真的不想mkdir在规则中执行,你可以使用这个:找到所有包含对象的目录,然后创建它们:

OBJDIRS := $(sort $(dir $(OBJS)))

folders :
        mkdir -p $(TGTDIR) $(OBJDIRS) $(addprefix $(DMPDIR)/,$(OBJDIRS))

推荐阅读