Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make makefile find target in subdirectory makefile

Tags:

makefile

How to make top level Makefile to call all targets in subdirectory Makefile ?

My folder structure is like this

/Makefile
/src/Makefile

I code all targets in /src/Makefile, but now I want to write another /Makefile to ease my work. How to write this top level Makefile ?

like image 520
guilin 桂林 Avatar asked Jul 26 '13 04:07

guilin 桂林


3 Answers

You could write in your TOP makefile use

all:
    @$(MAKE) -C src

and if you do NOT use makefile in sub dir, for example, you use somename.mk, you could use

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

I show you my example, my DIR looks like:

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

and my TOP makefile looks like:

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

it will call sub DIR *.mk during the compile. The sub DIR makefile, I just write a simple example for you reference:

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)

for the makefile, which generate the target file is little bit different, because I use the sub makefile to generate LIB file, and I use a root.mk to generate target:

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))"
like image 156
How Chen Avatar answered Nov 12 '22 08:11

How Chen


Beware, note there are, at least, two ways of doing this.

GNU Changedir Option

One way is using a specific feature of GNU Make, the -C option allow to change your compile directory and reach another one:

all:
    make -C dir

The make manual says:

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

You can also combine this option by calling a specific target inside the targeted directory. For example, the following target will get into the src/ directory and call make with the clean target:

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

POSIX Way

The problem with the GNU way of doing is that it only works with GNU Make, and not the standard Make. If you may use another Make (for whatever reason), you better consider doing it in a more POSIX way.

In POSIX Make, you have to rely more on the cd command, like this:

all:
        cd src/ && make

Note that, I used && and not ;. It is quite important to avoid infinite recursive calls to make. Indeed, cmd1 ; cmd2 will execute sequentially cmd1 and cmd2 whatever is the result of each command, where cmd1 && cmd2 will execute sequentially cmd1, and cmd2 will be executed only if cmd1 returned an EXIT_SUCCESS. In our case, imagine that the first cd failed because the directory has been removed. Then, the initial makefile will be executed again and again in an infinite recursive loop.

Anyway, this POSIX manner, is the more robust way of descending in subdirectories and execute other Makefile. I would recommend you to use it better than relying on an option linked to GNU Make.

like image 23
perror Avatar answered Nov 12 '22 07:11

perror


And if you want to do multiple dirs easily:

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 ..;)
like image 42
Goblinhack Avatar answered Nov 12 '22 06:11

Goblinhack