今天, 做了个比较复杂的项目, 先来看看项目结构:
├── build // 编译目录
│ ├── exes
│ │ └── huge.exe
│ ├── libs
│ │ ├── libbar.a
│ │ └── libfoo.a
│ ├── Makefile
│ └── make.rule
└── source // 源码目录
├── bar // 小项目 1
│ ├── inc
│ │ └── bar.h
│ └── src
│ ├── bar.c
│ ├── deps
│ │ └── bar.dep
│ ├── makefile
│ └── objs
│ └── bar.o
├── foo // 小项目 2
│ ├── inc
│ │ └── foo.h
│ └── src
│ ├── deps
│ │ └── foo.dep
│ ├── foo.c
│ ├── makefile
│ └── objs
│ └── foo.o
└── huge // 小项目 3
└── src
├── deps
│ └── main.dep
├── main.c
├── makefile
└── objs
└── main.o
1. 首先, 可以直接创建好目录
[root@ test]# mkdir -p build source/foo/src source/foo/inc source/huge/src
2. 然后把资源文件都放到相应的文件夹
├── build
│ ├── Makefile
│ └── make.rule
└── source
├── bar
│ ├── inc
│ │ └── bar.h
│ └── src
│ ├── bar.c
│ ├── makefile
├── foo
│ ├── inc
│ │ └── foo.h
│ └── src
│ ├── foo.c
│ ├── makefile
└── huge
└── src
├── main.c
└── makefile
3. 从 build 目录开始看
- make.rule: 这是 make 的主要规则, 即把各个 makefile 的共同点合并, 到时候直接 include 就可以了.
- Makefile: 编译整个工程的 Makefile, 它只是便利每个小项目, 然后执行该项目自己的 makefile.
# 文件: make.rule
.PHONY: all test clean
CC = gcc
AR = ar
ARFLAGS = crs
MKDIR = mkdir
RM = rm
RMFLAGS = -rf
ROOT_DIR ?= /home/XXX
DIR_OBJS = objs
DIR_EXES = $(ROOT)/build/exes
DIR_DEPS = deps
DIR_LIBS = $(ROOT)/build/libs
ifeq ("$(wildcard $(DIR_DEPS))", "")
DIR_DEPS_PRE := $(DIR_DEPS)
endif
ifeq ("$(wildcard $(DIR_OBJS))", "")
DIR_OBJS_PRE := $(DIR_OBJS)
endif
DIRS = $(DIR_OBJS) $(DIR_EXES) $(DIR_DEPS) $(DIR_LIBS)
RMS = $(DIR_OBJS) $(DIR_DEPS)
# EXE =
ifneq ($(EXE), "")
EXE := $(addprefix $(DIR_EXES)/, $(EXE))
RMS += $(EXE)
endif
# LIB = libfoo.a
ifneq ($(LIB), "")
LIB := $(addprefix $(DIR_LIBS)/, $(LIB))
RMS += $(LIB)
endif
SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRCS))
OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
DEPS = $(SRCS:.c=.dep)
DEPS := $(addprefix $(DIR_DEPS)/, $(DEPS))
ifneq ($(EXE), "")
all: $(EXE)
endif
ifneq ($(LIB), "")
all: $(LIB)
endif
ifneq ($(MAKECMDGOALS), clean)
include $(DEPS)
endif
# 添加 include 目录
ifneq ($(INC_DIRS), "")
INC_DIRS := $(strip $(INC_DIRS))
INC_DIRS := $(addprefix -I, $(INC_DIRS))
endif
ifneq ($(LINK_LIBS), "")
LINK_LIBS := $(strip $(LINK_LIBS))
LINK_LIBS := $(addprefix -l, $(LINK_LIBS))
endif
$(DIRS):
$(MKDIR) $@
$(EXE): $(DIR_EXES) $(OBJS)
$(CC) -L$(DIR_LIBS) -o $@ $(filter %.o, $^) $(LINK_LIBS)
$(LIB): $(DIR_LIBS) $(OBJS)
$(AR) $(ARFLAGS) $@ $(filter %.o, $^)
$(DIR_OBJS)/%.o: $(DIR_OBJS_PRE) %.c
$(CC) $(INC_DIRS) -o $@ -c $(filter %.c, $^)
$(DIR_DEPS)/%.dep: $(DIR_DEPS_PRE) %.c
@echo "Making $@ ..."
@set -e; \
$(CC) $(INC_DIRS) -E -MM $(filter %.c, $^) | sed 's,\(.*\)\.o[ :]* ,$(DIR_OBJS)/\1.o $@: ,g' > $@
clean:
$(RM) $(RMFLAGS) $(RMS)
# 文件: Makefile
.PHONY: all clean
DIRS = $(ROOT_DIR)/source/foo/src \
$(ROOT_DIR)/source/bar/src \
$(ROOT_DIR)/source/huge/src
RM = rm
RMFLAGS = -rf
RMS = $(ROOT_DIR)/build/exes \
$(ROOT_DIR)/build/libs
all:
@set -e; \
for dir in $(DIRS); \
do \
cd $$dir && $(MAKE); \
done
@echo ""
@echo ":-) Completed !"
@echo ""
clean:
@set -e; \
for dir in $(DIRS); \
do \
cd $$dir && $(MAKE) clean; \
done
$(RM) $(RMFLAGS) $(RMS)
@echo ""
@echo ":-) Completed !"
@echo ""
4. 然后就是 source 里面个目录的 Makefile
这部分很简单, 只是 include make.rule, 然后配置自己独有/不同的变量:
# 文件: bar/src/makefile
EXE =
LIB = libbar.a
INC_DIRS = $(ROOT_DIR)/source/bar/inc
LINK_LIBS =
include $(ROOT_DIR)/build/make.rule
# 文件: foo/src/makefile
EXE =
LIB = libfoo.a
# 头文件路径
INC_DIRS = $(ROOT_DIR)/source/foo/inc
LINK_LIBS =
# ROOT 为 buid 的绝对路径.
include $(ROOT_DIR)/build/make.rule
# 文件: huge/src/makefile
EXE = huge.exe
LIB =
INC_DIRS = $(ROOT_DIR)/source/foo/inc \
$(ROOT_DIR)/source/bar/inc
LINK_LIBS = foo bar
include $(ROOT_DIR)/build/make.rule
5. 最后, 在 build 目录 make, 将执行 build/Makefile 里面的规则, 编译 source 里面所有的源文件
过程大概如下:
make[1]: Entering directory '/home/XXX/source/foo/src'
mkdir deps
Making deps/foo.dep ...
mkdir /home/XXX/build/libs
mkdir objs
gcc -I/home/XXX/source/foo/inc -o objs/foo.o -c foo.c
ar crs /home/XXX/build/libs/libfoo.a objs/foo.o
make[1]: Leaving directory '/home/XXX/source/foo/src'
make[1]: Entering directory '/home/XXX/source/bar/src'
/home/XXX/build/make.rule:52: deps/bar.dep: 没有那个文件或目录
mkdir deps
Making deps/bar.dep ...
mkdir objs
gcc -I/home/XXX/source/bar/inc -o objs/bar.o -c bar.c
ar crs /home/XXX/build/libs/libbar.a objs/bar.o
make[1]: Leaving directory '/home/XXX/source/bar/src'
make[1]: Entering directory '/home/XXX/source/huge/src'
/home/XXX/build/make.rule:52: deps/main.dep: 没有那个文件或目录
mkdir deps
Making deps/main.dep ...
mkdir /home/XXX/build/exes
mkdir objs
gcc -I/home/XXX/source/foo/inc -I/home/XXX/source/bar/inc -o objs/main.o -c main.c
gcc -L/home/XXX/build/libs -o /home/XXX/build/exes/huge.exe objs/main.o -lfoo -lbar
make[1]: Leaving directory '/home/XXX/source/huge/src'
:-) Completed !
[1] 至简李云. 驾驭Makefile(准完整版) 2009.08.25
网友评论