如何让makefile在子目录下找到目标文件?

问题描述 投票:5回答:3

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

我的文件夹结构是这样的

/Makefile
/src/Makefile

我将所有的目标都编码为 /src/Makefile但现在我想再写一篇 /Makefile 以方便我的工作。如何编写这个顶级的Makefile?

makefile
3个回答
7
投票

你可以在你的顶级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

它将在编译过程中调用子DIR *.mk。子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文件,而我用了一个 "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))"

3
投票

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

GNU Changedir选项

其中一个方法是使用GNU Make的一个特殊功能,即 -C 选项允许改变你的编译目录并到达另一个目录。

all:
    make -C dir

这个 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/ 目录和呼叫 make 随着 clean 目标。

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 将依次执行 cmd1cmd2 只有在以下情况下才会被执行 cmd1 返回一个 EXIT_SUCCESS 在我们的案例中,想象一下,第一个 cd 失败,因为该目录已经被删除。然后,初始的makefile将在一个无限递归的循环中被反复执行。

总之,这种POSIX方式,是更强大的在子目录中下降并执行其他Makefile的方式。我建议你最好使用它,而不是依赖GNU Make中的一个选项。


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 ..;)
© www.soinside.com 2019 - 2024. All rights reserved.