我想知道在具有子目录的项目中使用Make的不同方法是什么,它们的优点/缺点是什么,但却看不到好的摘要或菜谱。
我在研究中看到的主要是“递归”和“单一文件”方法,但还有其他方法吗?
我还假设不仅有一种“递归”或“单一makefile”方法,而且有几种方法,所以有人总结一下吗?
对于我的特定情况,我希望目录架构看起来像这样:
.
├── 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
我应该选择哪种解决方案?可能是一个允许同名源文件?
答案 0 :(得分:1)
您的项目设置非常基本,所以应该是您的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
这里的想法是使用find
命令递归列出源文件,为make提供适当的模式规则以在正确的位置进行编译,并将正确的预处理器文件传递给编译器以启用自动依赖生成
使用GIT Bash shell和以下目录结构在Windows 8.1下使用GNU Make 4.1进行测试:
.
├── Makefile
└── src
├── test.c
├── test1.c
└── subdir1
└── test.c
答案 1 :(得分:1)
在阅读Recursive Make Considered Harmful之后,我想到了一种非常简单和模块化的方法来实现这一点,方法是让所有子目录中的文件相互包含并包含在主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
在每个子目录中,都有一个module.mk文件(我可以将它命名为任何东西,但这看起来很酷)。
对于src:
SRCS := main.c file1.c file2.c
SUBDIRS += subdir1 subdir2
include $(SRCDIR)/subdir1/module.mk
include $(SRCDIR)/subdir2/module.mk
对于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
对于2级子目录(更深一个):
THIS_DIR_L1 := subdir3
MOD_SRC := file5.c file6.c
SRCS += $(addprefix $(THIS_DIR_L0)/$(THIS_DIR_L1)/, $(MOD_SRC))
等等......
设置非常简单,我发现它非常模块化,并且不使用递归makefile。在目录结构中创建librairies和东西并不复杂。
任何有更好主意的人请告诉我。