从零开始:一步步教你如何写Makefile

在这里插入图片描述

一. Makefile作用

makefile 带来的好处就是自动化编译,一但写好,只需要 make 命令,整个工程全完自动化编译,极大的提高了开发效率,make 是一个命令工具,是一个解释makefile 中指令的命令工具,一般来说,大多数 ide 都有这个命令 比如 vc++ 的 nmake, linux 下的 gnu 的 make

二. Makefile组成和优势

makefile组成三要素:目标,依赖, 命令

  targets(目标):prequisities(依赖)
         command(命令,command前面要有一个tab键)
  • 依赖(相当于原材料) -> 命令(加工)-> 目标(产物)

makefile优势:

  • 大量代码的关系维护

    大项目中源代码较多,手工维护 编译时间长而且编译命令复杂,把代码维护命令及编译命令写在 makefile 文件中,然后再用make 工具解析此文件自动执行相应命令 可实现合理编译

  • 减少重复编译时间

    在改动其中一个文件时,能判断哪些文件被修改过,可以只对该文件进行重新编译,然后重新链接所有的目标文件,节省编译时间

三. Makefile推导

目录结构:
在这里插入图片描述

1. 第一阶段Makefile文件

在这里插入图片描述
编译结果:
在这里插入图片描述

2. 第二阶段Makefile文件

使用变量
在这里插入图片描述

3. 第三阶段Makefile文件

自动推导
在这里插入图片描述

4. 第四阶段Makefile文件:

自动变量($^ $< $@)

具体意义如下:

 	> $@  : 目标文件 
 	$^   : 所有依赖文件 
 	$<   : 第一个依赖文件

如下:

在这里插入图片描述

5. 第五阶段Makefile文件

Makefile函数
wildcard函数查找文件下所有文件名
patsubst查找替换
在这里插入图片描述

四. Makefile工作原理

目标的生成: a. 检查规则中的依赖文件是否存在; b. 若依赖文件不存在,则寻找是否有规则用来生成该依赖文件。

在这里插入图片描述
比如上图中,生成calculator的规则是gcc main.o add.o sub.o mul.o div.o -o,Makefil会先检查main.o, add.o, sub.o, mul.o, div.o是否存在,如果不存在,就会再寻找是否有规则可以生成该依赖文件。

比如缺少了main.o这个依赖,Makefile就会在下面寻找是否有规则生成main.o。当它发现gcc main.c -o main.o这条规则可以生成main.o时,它就利用此规则生成main.o,然后再生成终极目标calculator。

整个过程是向下寻找依赖,再向上执行命令,生成终极目标。

目标的更新: a. 检查目标的所有依赖,任何一个依赖有更新时,就重新生成目标; b. 目标文件比依赖文件时间晚,则需要更新。

在这里插入图片描述
比如,修改了main.c,则main.o目标会被重新编译,当main.o更新时,终极目标calculator也会被重新编译。其它文件的更新也是类推。

附录:

gcc 命令的常用选项
在这里插入图片描述
经典Makefile

CC := g++  
CFLAGS := -g  
TARGET := test  
SRCS := $(wildcard *.cpp)  
OBJS := $(patsubst %cpp,%o,$(SRCS))  

all:$(TARGET)  
%.o:%.cpp  
    $(CC) $(CFLAGS) -c $< -o $@ 
$(TARGET):$(OBJS)  
    $(CC) $(CFLAGS) -o $@  
clean:  
    rm -rf $(TARGET) *.o  

万能Makefile

####################################################
# Generic makefile - 万能Makefile
# for compiling and linking C++ projects on Linux 
# Author: George Foot  Modified:Jackie Lee
####################################################
### Customising
#
# Adjust the following if necessary; EXECUTABLE is the target
# executable's filename, and LIBS is a list of libraries to link in
# (e.g. alleg, stdcx, iostr, etc). You can override these on make's
# command line of course, if you prefer to do it that way.
#
#
EXECUTABLE := main    # 可执行文件名
LIBDIR:=              # 静态库目录
LIBS :=               # 静 态   库 文 件 名
INCLUDES:=.           # 头文件目录
SRCDIR:=              # 除了当前目录外,其他的源代码文件目录
#
# # Now alter any implicit rules' variables if you like, e.g.:
 
CC:=g++
CFLAGS := -g -Wall -O3
CPPFLAGS := $(CFLAGS)
CPPFLAGS += $(addprefix -I,$(INCLUDES))
CPPFLAGS += -MMD
#
# # The next bit checks to see whether rm is in your djgpp bin
# # directory; if not it uses del instead, but this can cause (harmless)
# # `File not found' error messages. If you are not using DOS at all,
# # set the variable to something which will unquestioningly remove
# # files.
#

RM-F := rm -f 
 
# # You shouldn't need to change anything below this point.
#
SRCS := $(wildcard *.cpp) $(wildcard $(addsuffix /*.cpp, $(SRCDIR)))
OBJS := $(patsubst %.cpp,%.o,$(SRCS))
DEPS := $(patsubst %.o,%.d,$(OBJS))
MISSING_DEPS := $(filter-out $(wildcard $(DEPS)),$(DEPS))
MISSING_DEPS_SOURCES := $(wildcard $(patsubst %.d,%.cpp,$(MISSING_DEPS)))

.PHONY : all deps objs clean veryclean rebuild info

all: $(EXECUTABLE)

deps : $(DEPS)

objs : $(OBJS)

clean :
        @$(RM-F) *.o
        @$(RM-F) *.d
veryclean: clean
        @$(RM-F) $(EXECUTABLE)

rebuild: veryclean all
ifneq ($(MISSING_DEPS),)
$(MISSING_DEPS) :
        @$(RM-F) $(patsubst %.d,%.o,$@)
endif
-include $(DEPS)
$(EXECUTABLE) : $(OBJS)
        $(CC) -o $(EXECUTABLE) $(OBJS) $(addprefix -L,$(LIBDIR)) $(addprefix -l,$(LIBS))

info:
        @echo $(SRCS)
        @echo $(OBJS)
        @echo $(DEPS)
        @echo $(MISSING_DEPS)
        @echo $(MISSING_DEPS_SOURCES)

多级目录结构的Makefile

二级目录结构下的Makefile的写法参照 Linux编程工具-Makefile(二)


版权声明:本文为qq_34623621原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。