简体   繁体   中英

Using GNU Make with subdirectories

I was wondering what different approaches of using Make in a project with subdirectories exist, and what are their advantages/drawbacks, but could never see a good summary or cookbook.

I have seen in my researches mainly the "recursive" and "single makefile" approaches, but are there others ?

I also assume that there is not only one "recursive" or "single makefile" approaches but several, so could somebody sum it up ?

For my particular case, I would like a directory architecture looking like this:

.
├── build
│   ├── *.d
│   ├── *.o
|   ├── subdir1
|   │   ├── *.d
|   │   └── *.o
|   └── subdir2
|       ├── *.d
|       ├── *.o
|       └── subdir3
|           ├── *.d
|           └── *.o
├── include
│   ├── *.h
│   └── *.h
├── Makefile
└── src
    ├── *.c
    ├── *.h
    ├── subdir1
    │   ├── *.c
    │   └── *.h
    └── subdir2
        ├── *.c
        ├── *.h
        └── subdir3
            ├── *.c
            └── *.h

Which solution should I choose ? Possibly one which would allow source files with the same name ?

Your project setup is really basic, so should be your Makefile:

SRC_DIR := src
BLD_DIR := build

SRC := $(shell find $(SRC_DIR) -name "*.c")
OBJ := $(SRC:$(SRC_DIR)/%.c=$(BLD_DIR)/%.o)
DEP := $(OBJ:.o=.d)

CPPFLAGS := -MMD -MP # enable auto-dependency generation
CFLAGS   := -Wall -W -pedantic

.PHONY: all clean

all: $(OBJ)

clean:
    $(RM) -r $(BLD_DIR)

.SECONDEXPANSION:
$(BLD_DIR)/%.o: $(SRC_DIR)/%.c | $$(@D)/ # First check that the destination directory exists
    $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<

%/:
    mkdir -p $* # -p flag necessary for recursive directory creation

ifeq "$(MAKECMDGOALS)" ""
-include $(DEP)
endif

The idea here is to list source files recursively using the find command, to supply make with the appropriate pattern rule to compile in the right place and pass the right preprocessor file to your compiler to enable auto-dependency generation.


Tested with GNU Make 4.1 under Windows 8.1 with the GIT Bash shell and the following directory structure:

.
├── Makefile
└── src
    ├── test.c
    ├── test1.c
    └── subdir1
        └── test.c

After reading Recursive Make Considered Harmful , I figured a quite simple and modular way to achieve this, by having files in all subdirectories that would include each other and be included in the main makefile:

CXX         := gcc

SRCDIR          := src
OBJDIR          := build

# These lines are needed to set immediate evaluation for
# these variables, instead of deferred evaluation which is unsuitable.
SRCS            :=
SUBDIRS         :=
CFLAGS          :=
LDFLAGS         :=

include $(SRCDIR)/module.mk

OBJS            := $(addprefix $(OBJDIR)/, $(SRCS:.c=.o))

SRCS            := $(addprefix $(SRCDIR)/, $(SRCS))

DEPS            := $(OBJS:.o=.d)

TMPS            := $(OBJS) $(OBJS:.o=.d)

CFLAGS          += -MD
debug: CFLAGS   += -g -g3 -ggdb
CFLAGS          += $(addprefix -I./$(SRCDIR)/, $(SUBDIRS))

LDFLAGS         += -lsomelib
debug: LDFLAGS      += -g -g3 -ggdb

NAME            := yolo

all: $(NAME)

debug:  re

-include $(DEPS)

$(OBJDIR)/%.o: $(SRCDIR)/%.c
    $(COMPILE.c) $(OUTPUT_OPTION) $<

$(NAME): $(OBJS)
    @$(CXX) $(OBJS) -o $(NAME) $(LDFLAGS)

$(OBJS): | $(OBJDIR)

$(OBJDIR):
    @mkdir -p $(OBJDIR)
    @for dir in $(SUBDIRS);         \
    do                  \
        mkdir -p $(OBJDIR)/$$dir;   \
    done

clean:
    rm -rf $(TMPS)

fclean: clean
    rm -rf $(NAME)
    rm -rf $(OBJDIR)

re: fclean all

.PHONY: all clean fclean re

And in every subdirectory, a module.mk file (I could have named it anything, but this seemde cool).

For src:

SRCS        :=  main.c file1.c file2.c

SUBDIRS     +=  subdir1 subdir2

include $(SRCDIR)/subdir1/module.mk
include $(SRCDIR)/subdir2/module.mk

For a level 1 subdirectory:

THIS_DIR_L0 := subdir1

MOD_SRC     :=  file3.c file4.c

SRCS        += $(addprefix $(THIS_DIR_L0)/, $(MOD_SRC))

SUBDIRS     += $(THIS_DIR_L0)/subdir3

include $(SRCDIR)/$(THIS_DIR_L0)/subdir3/module.mk

And for a level 2 subdir (one deeper):

THIS_DIR_L1 := subdir3

MOD_SRC     :=  file5.c file6.c

SRCS        += $(addprefix $(THIS_DIR_L0)/$(THIS_DIR_L1)/, $(MOD_SRC))

And so on...

This is quite simple to set up, I find it very modular and it does not use recursive makefiles. It would not be complicated to make librairies and stuff inside your directory structure either.

Anybody having a better idea please tell me.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM