如何使makefile在子目录makefile中找到目标

如何使makefile在子目录makefile中找到目标,makefile,Makefile,如何使顶级Makefile调用子目录Makefile中的所有目标 我的文件夹结构是这样的 /Makefile /src/Makefile 我在/src/Makefile中对所有目标进行编码,但现在我想编写另一个/Makefile来简化我的工作。如何编写顶级Makefile?您可以使用顶级Makefile编写 all: @$(MAKE) -C src 如果在sub-dir中不使用makefile,例如,使用somename.mk,则可以使用 all: @$(MAKE) -C s

如何使顶级Makefile调用子目录Makefile中的所有目标

我的文件夹结构是这样的

/Makefile
/src/Makefile

我在
/src/Makefile
中对所有目标进行编码,但现在我想编写另一个
/Makefile
来简化我的工作。如何编写顶级Makefile?

您可以使用顶级Makefile编写

all:
    @$(MAKE) -C src
如果在sub-dir中不使用makefile,例如,使用somename.mk,则可以使用

all:
    @$(MAKE) -C src -f somename.mk
我向您展示我的示例,我的目录如下所示:

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
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
我的顶级makefile如下所示:

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
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))"

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

GNU Changedir选项

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

all:
    make -C dir
make
手册上说:

您还可以通过在目标目录中调用特定目标来组合此选项。例如,以下目标将进入
src/
目录,并使用
clean
目标调用
make

clean:
        @rm -f *.o
        make -C src/ clean
POSIX方式

GNU方式的问题在于,它只适用于GNU Make,而不适用于标准Make。如果你可以使用另一个制作(不管什么原因),你最好考虑以一种更积极的方式来做。p> 在POSIX Make中,您必须更多地依赖
cd
命令,如下所示:

all:
        cd src/ && make
注意,我使用了
&
而不是
。避免对
make
的无限递归调用非常重要。实际上,
cmd1;cmd2
将按顺序执行
cmd1
cmd2
每个命令的结果,其中
cmd1和&cmd2
将按顺序执行
cmd1
,并且
cmd2
仅在
cmd1
返回
退出成功时才会执行。在我们的例子中,假设第一张
cd
失败,因为目录已被删除。然后,初始makefile将在无限递归循环中一次又一次地执行


无论如何,这种POSIX方式是在子目录中降序并执行其他Makefile的更健壮的方式。我建议您更好地使用它,而不是依赖与GNU Make链接的选项。

如果您想轻松完成多个DIR:

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 ..;)

您想要顶部的
makefile
调用子
makefile
?您是指所有目标还是
all
目标?非常感谢,但是
all
是否匹配任何目标?还是说
all
只是其中一个目标的一个例子?@guilin桂林, 在我的
makefile
中,我认为
所有的
都符合我项目的任何目标谢谢!我在下面添加了一个扩展来展示如何将它扩展到多个目录。