美文网首页
Makefile 浅析 (3)

Makefile 浅析 (3)

作者: heyzqq | 来源:发表于2017-12-14 20:05 被阅读0次

    今天, 做了个比较复杂的项目, 先来看看项目结构:

    ├── 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 目录开始看

    1. make.rule: 这是 make 的主要规则, 即把各个 makefile 的共同点合并, 到时候直接 include 就可以了.
    2. 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

    相关文章

      网友评论

          本文标题:Makefile 浅析 (3)

          本文链接:https://www.haomeiwen.com/subject/almzixtx.html