当我们的工程越来越大的以后,每次都使用命令编译显得非常的麻烦.所以我们需要一个自动化编译的工具来帮助我们编译.在我们使用源码安装软件的时候都会有make,make install等操作,这个就是使用Makefile来进行自动化编译的工作的.
Makefile也是一个脚本文件和shell脚本非常的相似,但是也有很多的地方不一样.
程序编译通常会有一下几个步骤,先是预编译,然后将C语言代码编译成汇编,然后在将汇编编译成二进制文件.o文件,然后将所有的.o文件连接起来就得到了可执行文件.
在编写Makefile时,我们先将所有的c语言代码编译成二进制文件,然后将所有二进制文件链接起来.
和shell类似的,里面有变量,有命令,有循环,判断等语句,所有的命令都需要另起一行,而且开始必须是tab键(所有开头是tab键的行都会被认为是命令,哪怕不能执行),变量等必须顶行不能有空格等.
简单的Makefile格式(不涉及循环,选择等语句):
TARGET... : PREREQUISITES...
COMMAND
a:main.o
gcc -o main.o
main.o:main.c
gcc -c main.c
这样就是一个最简单的Makefile
当然我们如果是文件多的话这样写就非常的麻烦,我们就可以使用 变量名 += .....来进行编辑,使用时直接$(变量名)来使用.(和shell一样)
我们也常常会使用make clean的命令等,这个叫做伪目标,直接
clean:
rm *.o
install:
cp .. /bin
Makefile文件也可以应用其他的Makefile文件
include 文件名
在我们写了.o文件名以后,当.o和.c文件是同名时,我们也可以不用.c文件,make会自动查找同名的文件,例如%.o:%.c.
以下是一些自动化变量:
$@
表示规则的目标文件名。如果目标是一个文档文件(Linux中,一般称.a文件为文档文件,也称为静态库文件) ,那么它代表这个文档的文件名。在多目标模式规则中,它代表的是哪个触发规则被执行的目标文件名。
$%
当规则的目标文件是一个静态库文件时,代表静态库的一个成员名。例如,规则的目标是 “foo.a(bar.o)” , 那么, “$%” 的值就为 “bar.o” , “$@” 的值为“foo.a” 。
如果目标不是静态库文件,其值为空。
$<
规则的第一个依赖文件名。 如果是一个目标文件使用隐含规则来重建, 则它代表由隐含规则加入的第一个依赖文件。
$?
所有比目标文件更新的依赖文件列表,空格分割。如果目标是静态库文件名,代表的是库成员(.o文件) 。
$^
规则的所有依赖文件列表,使用空格分隔。如果目标是静态库文件,它所代表的只能是所有库成员(.o文件)名。一个文件可重复的出现在目标的依赖中,变量“$^”只记录它的一次引用情况。就是说变量“$^”会去掉重复的依赖文件。
$+
类似“$^” ,但是它保留了依赖文件中重复出现的文件。主要用在程序链接时库的交叉引用场合。
$*
在模式规则和静态模式规则中,代表“茎” 。 “茎”是目标模式中“%”所代表的部分 (当文件名中存在目录时, “茎” 也包含目录 (斜杠之前) ) 。例如:文件“dir/a.foo.b” ,当目标的模式为“a.%.b”时,“$*”的值为“dir/a.foo” 。 “茎”对于构造相关文件名非常有用
以下是一般的简单的Makefile写法:
COBJS += main.o
#CFLAGS += -O2 -Wall -DDEBUG
CFLAGS += -I./
LDFLAGS += -lmxml -lpthread
CROSS_COMPILE ?=
CC = $(CROSS_COMPILE)gcc
TARGET = tag
all:$(TARGET)
$(TARGET):$(COBJS)
$(CC) -o $@ $^ $(LDFLAGS)
%.o:%.c
$(CC) $(CFLAGS) -c -o $@ $^ $(LDFLAGS)
.PHONY:clean
clean:
rm -f $(COBJS)