1- 什么是Makefile
因为最近做的获取温度上报服务器的小项目,所以需要makefile来实现。也算是做个笔记吧
工程中的哪些源文件需要编译以及如何编译、需要创建那些库文件以及如何创建这些库文件、如何最后产生我们想要的可执行文件。尽管看起来可能是很复杂的事情,但是为工程编写Makefile 的好处是能够使用一行命令来完成“自动化编译”,一旦提供一个正确的 Makefile。编译整个工程你所要做的唯一的一件事就是在shell 提示符下输入make命令。整个工程完全自动编译,极大提高了效率。
一个工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。Linux 环境下的程序员如果不会使用GNU make来构建和管理自己的工程,应该不能算是一个合格的专业程序员。
在 Linux(unix )环境下使用GNU 的make工具能够比较容易的构建一个属于你自己的工程,整个工程的编译只需要一个命令就可以完成编译、链接以至于最后的执行。不过这需要我们投入一些时间去完成一个或者多个称之为Makefile 文件的编写。所要完成的Makefile 文件描述了整个工程的编译、连接等规则。
2- Makefile通用结构
下面是Makefile的通用结构:
这个还是比较抽象的,我们后面可以详细看着代码来理解
#以'#'开头的行表示注释
#定义变量VAR,强制赋值为test
VAR=test
#在VAR之前定义的值后面再追加app这个值,这时该变量值扩展为testapp
VAR+=app
#如果之前VAR没有被定义,则定义并使用testapp;否则使用之前的值。
VAR?=testapp
#第一条目标为总的目标,
#依赖可以是文件(目录)或为其他目标
#动作可以是Linux命令,动作的那一行必须以TAB键开头
target: depend1 depend2 depend3 ...
[TAB] action1
[TAB] action2
target1:
[TAB] action1
[TAB] action2`
3- Makefile编写
默认的情况下,make命令会在当前目录下按顺序找寻文件名为“GNUmakefile”、“makefile”、“Makefile”的文件,找到后就解释并执行该文件,如果找不到就提示错误并退出。一般Makeifle文件名我们会用Makefile或makefile,而不会使用GNUmakefile。接下来我们以之前的静态库和动态库为例讲解makefile的编写和使用。相信都想要了解makefile了,那动态库静态库肯定有所了解了,不了解的话需要了解才能更好理解makefile。
我们先了解src文件夹和lib文件夹,因为等会儿makefile是在src里面写的,动静态库会放在lib里面。
src目录,即源文件目录,一般.c源文件都会放在这里,你想想啊,一个公司写好了.c代码,肯定不能把.c文件直接给别人啊,所以就生成他们相应的动态库或者静态库给别人,别人呢只能拿来用,并不知道源代码怎么写的,岂不妙哉~
lib文件夹就是存放动静态库的,所以等会儿makefile生成的动静态库都放到这里面去。lib和src文件夹都是在一个目录下的。
下面是lib路径下用来同时生产静态库和动态库的makefile文件:
#这些都是需要生成的动静态库的名字,提前定义变量,方便后面直接用
LIBNAME1 = socket_client_connect
LIBNAME2 = get_temperature
LIBNAME3 = custom_syslog
#这是lib的路径,../lib就是本文件的上个目录下的lib文件夹,注意`pwd`上面的单引号是英问状态下的 ~ 号的那个键
INSTPATH =`pwd`/../lib
CC = gcc
#ar是静态库打包需要用的
AR = ar
# 这里all是整个makefile文件的第一个目标,也就是总的目标,当我们输入make命令时就是要完成这个目标;该目标有两个依赖dynamic_lib和 static_lib 和 两个动作 make clear和 make install
# 其中两个依赖 dynamic_lib 和 static_lib 也是makefile文件的目标,所以整个makefile要先执行完dynamic_lib和static_lib这两个
目标后才能执行后面的动作;
# 在动作make clear和make install前面有个 @ 符,这个符号会让执行make名时不打印这两天命令本身,而只是输出命令执行的结
果;另外make命令在执行过程中,也会多次载入makefile文件;执行完dynamic_lib就继续往下走
#总的来说就是一make就会从all开始执行,
all: dynamic_lib static_lib
@make clear
@make install
#dynamic_lib 目标用来编译生成动态库,它是all目标的一个依赖;
dynamic_lib:
${CC} -shared -fPIC *.c -o lib${LIBNAME1}.so
${CC} -shared -fPIC *.c -o lib${LIBNAME2}.so
${CC} -shared -fPIC *.c -o lib${LIBNAME3}.so
# static_lib 目标用来编译生成静态库,它是all目标的一个依赖;
static_lib:
${CC} -c *.c
${AR} -rcs lib${LIBNAME1}.a ${LIBNAME1}.o
${AR} -rcs lib${LIBNAME2}.a ${LIBNAME2}.o
${AR} -rcs lib${LIBNAME3}.a ${LIBNAME3}.o
# install是一个单独的目标,他用来将编译生成的库文件和头文件拷贝到相应的安装路径下。在总目标all下有个动作@make install会执行该目标;
install会执行该目标;
install:
cp -rf lib${LIBNAME1}.* ${INSTPATH}
cp -rf lib${LIBNAME2}.* ${INSTPATH}
cp -rf lib${LIBNAME3}.* ${INSTPATH}
cp -rf *.h ${INSTPATH}
# uninstall是一个单独的目标,他用来在安装路径下删除之前安装的库文件和头文件
# 该目标没有被总的目标all依赖或执行,所以默认该目标不会被执行,如果想执行该目标,则可以在Linux命令行下输入make uninstall来执行
uninstall:
rm -f ${INSTPATH}/lib${LIBNAME1}.*
rm -f ${INSTPATH}/lib${LIBNAME2}.*
rm -f ${INSTPATH}/lib${LIBNAME3}.*
rm -f ${INSTPATH}/ *.h
# clear是一个单独的目标,他用来将编译生成的object临时文件删除,静态库会生成.o中间文件。在总目标all下有个动作@make clear会执行该目标;
clear:
rm -f *.o
# clean是一个单独的目标,它依赖clear目标,所以先通过clear目标删除所有的object临时文件,之后再删除编译产生的库文件;
# 该目标没有被总的目标all依赖或执行,所以默认该目标不会被执行,如果想执行该目标,则可以在Linux命令行下输入make clean
来执行
clean: clear
rm -f lib${LIBNAME1}.*
rm -f lib${LIBNAME2}.*
rm -f lib${LIBNAME3}.*
4- makefile执行
保存退出之后我们来执行一下make命令:
可以看到,就等于是makefile打包了所有的命令,然后我们总的命令一下去,就分别执行了。我们去lib路径下看一下生成的动静态库文件:.a为静态库文件,.so为动态库文件,头文件也都复制多来了。
执行make clean命令:执行make clean命令之后我们可以看到在src文件夹下的动静态库都被删除了。
执行make uninstall:可以看到lib下的文件都被删除了,意思就是不安装了,全部删除
lib下的库文件和头文件就可以给用户啦,然后用户自己去玩就行了。
5- 结尾
makefile主要还是有一个模板比较好,后面做项目的时候就可以j简单修改拿来用了。
有错误的地方还请指出哈~