如何让makefile在子目录的makefile中查找目标

6
如何使顶层Makefile调用子目录Makefile中的所有目标?
我的文件夹结构如下:
/Makefile
/src/Makefile

我在/src/Makefile中编写了所有的目标,但现在我想写另一个/Makefile来简化我的工作。如何编写这个顶层的Makefile?


你想要在 makefile 中调用子 makefile 吗? - How Chen
1
你是指所有目标,还是 all 目标? - Beta
3个回答

8
您可以在您的TOP makefile中使用以下代码:
all:
    @$(MAKE) -C src

如果您在子目录中没有使用makefile,例如您使用了somename.mk,那么可以使用以下命令:

all:
    @$(MAKE) -C src -f somename.mk

我为您展示一个例子,我的DIR看起来像这样:

TOPDIR-- Makefile
|
|-- debug
|   |-- debug.c
|   |-- debug.h
|   |-- debug.mk
|   |-- instrument.c
|   `-- uart_print.c
|-- driver
|   |-- driver.c
|   |-- driver_ddi.c
|   |-- driver_ddi.h
|   |-- driver.h
|   `-- driver.mk
|-- include
|   `-- common.h
|-- Makefile
|-- mw
|   |-- manager.c
|   `-- mw.mk
|-- root
|   |-- main.c
|   `-- root.mk

我的 TOP makefile 看起来像这样:

MAKE_DIR = $(PWD)

ROOT_DIR    := $(MAKE_DIR)/root 
DRV_DIR     := $(MAKE_DIR)/driver
INCLUDE_DIR := $(MAKE_DIR)/include
DEBUG_DIR   := $(MAKE_DIR)/debug

INC_SRCH_PATH := 
INC_SRCH_PATH += -I$(ROOT_DIR)
INC_SRCH_PATH += -I$(DRV_DIR) 
INC_SRCH_PATH += -I$(INCLUDE_DIR)
INC_SRCH_PATH += -I$(DEBUG_DIR)

LIB_SRCH_PATH :=
LIB_SRCH_PATH += -L$(MAKE_DIR)/libs


COLOR_ON = color
COLOR_OFF = 
CC = $(COLOR_ON)gcc
#CC = $(COLOR_OFF)gcc
LD = ld

LINT = splint

LIBS := -ldriver -ldebug -lmw -lm -lpthread

CFLAGS :=
CFLAGS += $(INC_SRCH_PATH) $(LIB_SRCH_PATH) 
CFLAGS += -Wall -O -ggdb -Wstrict-prototypes -Wno-pointer-sign -finstrument-functions -fdump-rtl-expand
CFLAGS += -DDEBUG -D_REENTRANT

LDFLAGS :=

export MAKE_DIR CC LD CFLAGS LDFLAGS LIBS LINT INC_SRCH_PATH

all:
    @$(MAKE) -C debug -f debug.mk
    @$(MAKE) -C driver -f driver.mk
    @$(MAKE) -C mw -f mw.mk
    @$(MAKE) -C root -f root.mk

.PHONY: clean
clean:
    @$(MAKE) -C debug -f debug.mk clean
    @$(MAKE) -C driver -f driver.mk clean
    @$(MAKE) -C mw -f mw.mk clean
    @$(MAKE) -C root -f root.mk clean

.PHONY: lint
lint:
    $(MAKE) -C debug -f debug.mk lint

在编译期间,它会调用 sub DIR *.mk。关于 sub DIR 的 makefile,我为您提供了一个简单的示例:

LIB = $(MAKE_DIR)/libs/yourmodulename.a
SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRCS))

$(LIB): $(OBJS)
    @mkdir -p ../libs
    @$(AR) cr $@ $^
    @echo "    Archive    $(notdir $@)"

$(OBJS): $(SRCS)
    @$(CC) $(CFLAGS) -c $^
    @echo "    CC        $(OBJS)"

.PHONY: clean
clean:
    @$(RM) -f $(LIB) $(OBJS)
    @$(RM) -f *.expand
    @echo "    Remove Objects:   $(OBJS)"
    @echo "    Remove Libraries:  $(notdir $(LIB))"

.PHONY: lint 
lint:
    $(LINT) $(INC_SRCH_PATH) $(SRCS)

对于生成目标文件的Makefile,有一点不同,因为我使用子Makefile来生成LIB文件,并且我使用root.mk来生成目标文件:

PROG = ../prog/DEMO

SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRCS))

$(PROG): $(SRCS)
    @mkdir -p ../prog
    @$(CC) $^ $(CFLAGS) -Wl,-Map=$(PROG).map $(LIBS) -o $@
    @echo "    Generate Program $(notdir $(PROG)) from $^"

.PHONY: clean
clean:
    @$(RM) -f $(OBJS) $(PROG)
    @$(RM) -f *.expand
    @$(RM) -rf ../prog ../libs
    @echo "    Remove Objects:   $(OBJS)"
    @echo "    Remove Libraries:  $(notdir $(PROG))"

非常感谢,但是all是否匹配任何目标?还是all只是目标之一的示例? - guilin 桂林
@guilin 在我的 makefile 中,我认为 all 匹配了项目中的任何目标。 - How Chen

4

注意,至少有两种方法可以做到这一点。

GNU Changedir 选项

一种方法是使用 GNU Make 的特定功能,即 -C 选项,允许更改编译目录并进入另一个目录:

all:
    make -C dir
< p > 《make》手册上写道:

-C dir, --directory=dir
    Change to directory dir before reading the makefiles or doing anything
    else. If multiple -C options are specified, each is interpreted relative
    to the previous one: -C / -C etc is equivalent to -C  /etc. This is
    typically used with recursive invocations of make.
您可以通过调用目标文件夹中的特定目标来结合此选项。例如,以下目标将进入 src/ 目录,并使用 clean 目标调用 make 命令:
clean:
        @rm -f *.o
        make -C src/ clean

POSIX方式

使用GNU方式的问题是它只能与GNU Make一起使用,而不能与标准Make一起使用。如果您可能使用其他Make(无论出于什么原因),最好考虑以更符合POSIX标准的方式进行。

在POSIX Make中,您需要更多地依赖cd命令,如下:

all:
        cd src/ && make

请注意,我使用的是&&而不是;。这很重要,可以避免对make进行无限递归调用。实际上,cmd1 ; cmd2将按顺序执行cmd1cmd2,无论每个命令的结果如何,而cmd1 && cmd2将按顺序执行cmd1,只有当cmd1返回一个EXIT_SUCCESS时才会执行cmd2。在我们的情况下,假设第一个cd失败,因为目录已被删除。然后,初始makefile将在无限递归循环中再次执行。

无论如何,这种POSIX方式是在子目录中下降并执行其他Makefile的更可靠方式。我建议您使用它,而不是依赖于与GNU Make相关的选项。


谢谢!我已添加一个扩展部分来显示如何将其扩展到多个目录。 - Goblinhack

1

如果您想轻松地处理多个目录:

SUBDIRS=dir1 dir2

all::
        @echo make all
        $(foreach var,$(SUBDIRS),echo $(var): ; cd $(var)/ && make $@ && cd ..;)
clean:
        @echo make clean
        $(foreach var,$(SUBDIRS),echo $(var): ; cd $(var)/ && make $@ && cd ..;)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接