文章目录
前言
我们刚开始在Linux
系统下进行编程时,采用的编译方法为:将程序所引用的文件打包成静态库/共享库
,再使用生成的静态库/共享库与源程序一起编译成可执行文件
。
然而,我们发现在一个中大型的C/C++
工程中,往往包含了成百上千个源文件
。如果我们使用上述方法编译,编译命令就会变得十分冗长,在输入命令的过程中容易出错。即便是正确输入了编译命令,在进行编译过程中,也会耗费较长的编译时间。显然,手动编译并不适用于大部分的Linux编程场景。
为解决以上问题,我们将在本篇中学习如何编写Makefile文件完成自动化编译。
一、make工具简介
在学习编写Makefile文件之前,我们需要先了解Linux系统中一个非常重要的编译命令make
。
1.什么是make?
make
是用于自动编译,链接程序的实用工具。它最主要最基本的功能就是通过makefile
文件来描述源程序之间的相应关系,并自动维护编译工作。
使用make
工具的好处在于,在编译完成之后,若修改了某个源代码,make
只对修改后的部分进行编译,其他目标文件不会更改,并且会安装文件依赖性来更新执行文件。大大提高了编译效率。
2.如何安装make?
(1)进入root权限,终端命令:sudo su
。
(2)进入更新列表,终端命令:apt-get update
。
(3)Linux安装make,终端命令:apt-get install ubuntu-make
。
(4)验证是否安装成功,终端命令:make -v
,显示所安装make的版本号即安装成功。
二、编写Makefile文件
1.文件组成
- makefile三要素:
targets(目标),prequisities(依赖),command(命令)
。 - 每个依赖关系由一个
目标
文件和一组该目标所需的源文件(依赖
文件)构成。 命令
则描述了如何通过这些依赖关系文件创建目标。
makefile文件格式如下:
目标文件:依赖文件
[tab键] gcc -o 目标文件 依赖文件
2.工作原理
- 目标生成:检查规则中的依赖是否存在,若依赖文件不存在,则寻找是否有规则生成依赖文件。
- 目标更新:检查目标文件的所有依赖文件,任何一个依赖文件有更新时,就重新生成目标文件。
3.Makefile文件优点
(1)减少重复编译时间
在改动其中一个文件时,能判断哪些文件被修改过,只对该文件进行重新编译,然后重新链接所有目标文件, 大大提高了编译效率,节省了编译时间。
(2)利于大量代码关系维护
中大型工程中源代码较多,手工维护编译时间长,且编译命令复杂,把代码维护命令和编译命令写在makefile文件中,然后再用make工具解析此文件自动执行相应命令,实现高效编译。
4.单级目录下的Makefile文件编写
(1)第一版本,通俗易懂但不通用
(2)第二版本,变量obj类似C/C++中的宏定义,进行等量替换
(3)第三版本,将依赖文件改成相应的头文件,make命令在编译过程中会自动推导
(4)第四版本,$@
目标文件;$^
所有依赖文件;$<
第一个依赖文件
(5)第五版本,wildcard函数,查找文件下所有文件名;patsubst函数,查找替换
5.多级目录下的Makefile文件编写
当工程文件比较大时,我们可以采用文件分类的方式,将工程文件分为头文件(include)
、源文件(src)
、目标文件(obj)
、可执行文件(bin)
,并在这几个文件的同级目录下编写makefile文件
,如下图所示。
此时,对应的makefile文件通用写法,如下所示。
DIR_INC = ./include
DIR_SRC = ./src
DIR_OBJ = ./obj
DIR_BIN = ./bin
SRC = $(wildcard ${DIR_SRC}/*.c)
OBJ = $(patsubst %.c,${DIR_OBJ}/%.o,$(notdir ${SRC}))
TARGET = main
BIN_TARGET = ${DIR_BIN}/${TARGET}
CC = gcc
CFLAGS = -g -Wall -I${DIR_INC}
${BIN_TARGET}:${OBJ}
$(CC) $(OBJ) -o $@
${DIR_OBJ}/%.o:${DIR_SRC}/%.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
find ${DIR_OBJ} -name *.o -exec rm -rf {} \;
总结
以上就是关于如何编写Makefile文件的所有内容,希望大家阅读后都能有所收获!原创不易,转载请标明出处,若文章出现有误之处,欢迎读者留言指正批评!