之前学习导师给的代码并且在linux环境下编译的时候,第一次见到makefile文件,对于makefile文件,我只知道这是一个可以编译.c文件的工具,今天我就到网上找了一些有关makefile的资料进行了学习和知识整理。
下面参照的代码是节选了一个makefile文件的几个代码。
/*
makefile是一个能自动判断一个大型程序的哪些源代码需要重新编译的工具
并且能够根据判断结果自动调用编译器编译源代码,按照一点的顺序将编译结果整合成可执行程序
编译:gcc -c file.c
链接:gcc <file.o><file2.o>-o<output> 会解决掉.o文件中的交叉引用解决掉
<c> <汇编> <目标> <可执行>
.c => .s => .o => a.out
.h
If median.c is edited
- gcc -c median.c
- gcc median.o main.o sort.o -o top
***********************************************************************/
#
# 用libtool工具编译目标系统
# 以 STEST.c ==>生成STEST.so
/**
使用 GNU Libtool 可以容易的在不同的系统中建立动态链接库。
它通过一个称为 Libtool 库的抽象,隐藏了不同系统之间的差异,给开发人员提供了一致的的接口。
对于大部分情况,开发人员甚至不用去查看相应的系统手册,只需要掌握 GNU Libtool 的用法就可以了。
并且,使用 Libtool 的 Makefile 也只需要编写一次就可以在多个系统上使用。
Libtool 库可以是一个静态链接库,可以是一个动态链接库,也可以同时包含两者。
**/
//Libtool库资料网站 https://www.cnblogs.com/xmphoenix/p/4065950.html
/****************************************************************************
引用其他的makefile文件
语法: include <filename> (filename 可以包含通配符和路径)
*/
include ${HOME}/src/etc/makefile.${PLATFORM}
/****************************************************************************
Makefile中的变量*/
DATE =`date +"%Y%m%d%H%M"`
BUILDDATETIME =$(DATE)
RELEASE_VERSION =1.0.0
LIBDIR =${HOME}/lib -L${HOME}/sqlite/lib
SHLIBDIR =${HOME}/shlib
BINDIR =${HOME}/bin
LIBINCL =${HOME}/libincl
INCLUDE =${HOME}/incl -I${HOME}/sqlite/include
CC =cc ${OS_CCFLAG}
/*
Makefile 中的变量
变量定义 ( = or := )
OBJS = programA.o programB.o
OBJS-ADD = $(OBJS) programC.o
# 或者
OBJS := programA.o programB.o
OBJS-ADD := $(OBJS) programC.o
*****************************************************************************/
/******************************************************************************
makfile规则中的通配符
* :: 表示任意一个或多个字符
? :: 表示任意一个字符
[...] :: ex. [abcd] 表示a,b,c,d中任意一个字符, [^abcd]表示除a,b,c,d以外的字符, [0-9]表示 0~9中任意一个数字
~ :: 表示用户的home目录
******************************************************************************/
/******************************************************************************
源文件的路径*/
VPATH=.libs
/*
指定了 VPATH 之后, 如果当前目录中没有找到相应文件或依赖的文件, Makefile 回到 VPATH 指定的路径中再去查找.
VPATH 使用方法:
vpath <directories> :: 当前目录中找不到文件时, 就从<directories>中搜索
vpath <pattern> <directories> :: 符合<pattern>格式的文件, 就从<directories>中搜索
vpath <pattern> :: 清除符合<pattern>格式的文件搜索路径
vpath :: 清除所有已经设置好的文件路径
******************************************************************************/
/*
从上往下第一个目标就是最终目标 ,top图,从下往上 (依赖树)
先查询目标文件是否存在,若存在则结束
若不存在,查找依赖文件是否存在;
依赖文件存在则直接使用,若不存在则继续向下找 以依赖文件为目标文件的依赖图
查找是否重新编译的规则,看修改目标文件和依赖文件的编辑时间
若依赖文件修改时间比目标文件的编辑时间晚,则重新编译
*/
/**
all:
此目标动作是编译整个软件包。all是整个软件的终极目标
**/
all:STEST.so
/**
第一行取消掉makefile的可识别后缀表
第二行重新制定可识别后缀
**/
.SUFFIXES:
.SUFFIXES: .c .lo
.c.lo:
libtool --mode=compile --tag=CC ${CC} -g -O $(DEBUG) $(CCFLAG) -I$(LIBINCL) -I$(INCLUDE) -c $<
/**
install:
此目标动作为完成程序的编译并且将最终的可执行程序、库文件等拷贝到安装的目录
如果只是验证这些程序是否可被正确安装,它的动作应该是一个测试安装动作
**/
install:
install-shlib.sh STEST.la ${SHLIBDIR}
/**
uninstall:
删除所有的已安装文件——由install创建的所有的文件拷贝。
规则定义的命令 不能修改编译目录下面的文件,仅仅是删除安装目录下的文件。
**/
uninstall:
libtool --mode=uninstall /bin/rm ${SHLIBDIR}/STEST.so ${SHLIBDIR}/STEST-*.so
/****************************************************************************
目标文件:需要源文件
target:dependencies
<tab>rule
like as:
main.o:main.c median.h //dependencies 依赖
<tab>gcc -c main //rule 规则
tab必须要有,而且必须是tab,否则makefile不认为这是一条规则命令,同一条规则命令不换行
*/
STEST.so: STEST.lo
libtool --mode=link --tag=CC ${CC} ${LDFLAG} ${LDFLAG} -g -O -o $(@:.so=.la) $? -rpath ${SHLIBDIR} -release 1.0.0 -L${LIBDIR}/****************************************************************************/
/**
chean:
清除当前目录下变异生成的所有文件,这些文件在make过程中产生。
注意:clean命令不能删除软件包的配置文件,同时也不能删除build时创建的那些文件。
**/
clean:
@rm -f lib*.a *~ *core *.lo *.o *.la
@rm -rf .libs
/**
隐含规则:makefile自己定义的规则
Compiling C Program
'n.o' is made automatically from 'n.c' with a command of the from
'$(CC) -c $(CPPFLAGS) $(CFLAGS)'
Compiling C++ Program
'n.o' is made automatically from 'n.cc','n.cpp'or'n.C' with a command of the from
'$(CXX) -c $(CPPFLAGS) $(CFLAGS)'
We encourage you ti use the suffix '.cc' for C++ source file instead of '.C'
用户也可以自己定义隐含规则,用户自己定义的规则称为模式规则
格式
模式规则和普通规则相似;
模式规则的目标有且只有一个"%","%"可以匹配任意的非空字符串
'%.o:%.c' //表示把任意一个.c文件编译成.o文件
%.o:%.c
$(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@
自动变量
$@ 表示规则中的目标名字
$< 表示规则中的源文件(依赖)的名字
$? The name of all the prerequisties that are newer than the traget,
with spacees between them.
$^ The name of all the prerequisites, with spaces between them.
任意匹配模式规则
%:%.c
touch $@
"任意匹配"模式规则可以匹配任意一个target的规则
when a pattern rule's target is just '%' , it matches any file name whatever.
问题:
会寻找不存在的依赖,例如 file.c.c file.o.o
解决方案:
只有当其他的所有规则都无法使用才使用任意匹配模式规则
%::%.c
touch $@
采用双冒号的任意匹配规则叫做terminal规则
这种规则 对依赖进行限制,只有依赖确实存在,才会使用这种规则
取消隐含规则
1、如果自己定义的模式规则的目标依赖和make内部的规则相同将会替换
2、%.o:%.s
{no command}
省略掉command即可取消掉隐含规则
一个源文件可能会依赖很多个头文件,这些头文件再依赖其他的头文件...
现代编译器可以提供源文件依赖的所有头文件
cc -M main.c
main.o:main.c defs.h
对于每一个源文件'name.c'编译器会产生一个'name.d'的文件,这个文件中'name.o'所依赖的所以文件
这个文件的本质是一个规则
**/
//学习参考源于makefile中文操作手册
//参考视频:https://www.bilibili.com/video/av21042581