简体   繁体   English

对子目录使用GNU Make

[英]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. 我想知道在带有子目录的项目中使用Make的不同方法是什么,它们的优点/缺点是什么,但是永远看不到好的摘要或菜谱。

I have seen in my researches mainly the "recursive" and "single makefile" approaches, but are there others ? 我在研究中主要看到“递归”和“单个makefile”方法,但是还有其他方法吗?

I also assume that there is not only one "recursive" or "single makefile" approaches but several, so could somebody sum it up ? 我还假设不仅有一种“递归”或“单个makefile”方法,而且有几种,那么有人可以总结一下吗?

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: 您的项目设置实际上是基本的,因此应该是您的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. 这里的想法是使用find命令递归列出源文件,为make提供适当的模式规则,以便在正确的位置进行编译,并将正确的预处理程序文件传递给编译器以启用自动依赖项生成。


Tested with GNU Make 4.1 under Windows 8.1 with the GIT Bash shell and the following directory structure: 在Windows 8.1下使用GIT Bash shell和以下目录结构在GNU Make 4.1上进行了测试:

.
├── 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: 阅读了“ 递归使被认为有害”之后 ,我想出了一种非常简单且模块化的方法,通过在所有子目录中包含相互包含并包含在主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). 在每个子目录中,都有一个module.mk文件(我可以给它起任何名字,但这看起来很酷)。

For src: 对于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: 对于1级子目录:

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): 对于2级子目录(更深一层):

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. 设置非常简单,我发现它非常模块化,并且不使用递归的makefile。 It would not be complicated to make librairies and stuff inside your directory structure either. 在目录结构中进行库和东西也不会很复杂。

Anybody having a better idea please tell me. 有更好的主意的人请告诉我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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