总流程:
可执行文件生成过程: .c --> .o --> .exe
当有多个.c时,需要进行打包处理,则: .c(多个) --> .o (多个)--> .a --> .exe
详细步骤:
1. 读入所有的Makefile。
2. 读入被include的其它Makefile。
3. 初始化文件中的变量。
4. 推导隐晦规则,并分析所有规则。
5. 为所有的目标文件创建依赖关系链。
6. 根据依赖关系,决定哪些目标要重新生成。
7. 执行生成命令。
目标文件依赖
格式: 目标文件 :所依赖文件1 所依赖文件2 ...
如:target... : prerequisites ...
command
...
target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。说白一点就是说,prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。这就是Makefile的规则。也就是Makefile中最核心的内容。
变量定义: $
格式: 变量: $(被定义的内容),且变量可以累加,
如:
CFLAGS += -I../PUB/include
CFLAGS += -I../PUB/include/libxml
make 自动推导
GNU的make很强大,它可以自动推导文件以及文件依赖关系后面的命令,只要make看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中,如果make找到一个whatever.o,那么whatever.c,就会是whatever.o的依赖文件。并且 cc -c whatever.c 也会被推导出来
utils.o : utils.c defs.h
cc -c utils.c
可以省略去 cc -c utils.c ,而 简写成 utils.o : defs.h
makefile 文件名
默认情况下,makefile文件命名为makefile或者Makefile, 也可以使用其他名字,比如:“Make.Linux”,“Make.Solaris”,“Make.AIX”等,如果要指定特定的Makefile,你可以使用make的“-f”和“--file”参数,如:make -f Make.Linux或make --file Make.AIX。
makefile间互相引用
在Makefile使用include关键字可以把别的Makefile包含进来,这很像C语言的#include,被包含的文件会原模原样的放在当前文件的包含位置。include的语法是:
include<filename>
filename可以是当前操作系统Shell的文件模式(可以保含路径和通配符),在include前面可以有一些空字符,但是绝不能是[Tab]键开始。include和可以用一个或多个空格隔开。
通配符
" ~ " 波浪号(“~”)字符在文件名中也有比较特殊的用途。如果是“~/test”,这就表示当前用户的$HOME目录下的test目录
" * " 通配符代替了你一系列的文件,如“*.c”表示所以后缀为c的文件。一个需要我们注意的是,如果我们的文件名中有通配符,如:“*”,那么可以用转义字符“\”,如“\*”来表示真实的“*”字符,而不是任意长度的字符串。
$(patsubst %.c,%.o,$(wildcard *.c ./sub/*.c) )
patsubst表示替换,wildcard表示通配符,整个含义即是将当前目录所有.c文件和sub目录所有.c文件替换为.o文件
三种常用变量: $@,$^,$<
$@--目标文件,$^--所有的依赖文件,$<--第一个依赖文件。
如果我们使用上面三个变量,那么我们可以简化我们的Makefile文件为:
# 这是简化后的Makefile
main:main.o mytool1.o mytool2.o
gcc -o $@ $^
main.o:main.c mytool1.h mytool2.h
gcc -c $<
mytool1.o:mytool1.c mytool1.h
gcc -c $<
mytool2.o:mytool2.c mytool2.h
gcc -c $<
经过简化后我们的Makefile是简单了一点,不过人们有时候还想简单一点。这里我们学习一个Makefile的缺省规则
.c.o:
gcc -c $<
这个规则表示所有的 .o文件都是依赖与相应的.c文件的。例如mytool.o依赖于mytool.c这样Makefile还可以变为:
.c.o:
gcc -c $<
伪目标
clean:
rm *.o temp
我们生成了许多文件编译文件,我们也应该提供一个清除它们的“目标”以备完整地重编译而用。 (以“make clean”来使用该目标)
因为,我们并不生成“clean”这个文件。“伪目标”并不是一个文件,只是一个标签,由于“伪目标”不是文件,所以make无法生成它的依赖关系和决定它是否要执行。我们只有通过显示地指明这个“目标”才能让其生效。当然,“伪目标”的取名不能和文件名重名,不然其就失去了“伪目标”的意义了。
当然,为了避免和文件重名的这种情况,我们可以使用一个特殊的标记“.PHONY”来显示地指明一个目标是“伪目标”,向make说明,不管是否有这个文件,这个目标就是“伪目标”。
.PHONY : clean
只要有这个声明,不管是否有“clean”文件,要运行“clean”这个目标,只有“make clean”这样。于是整个过程可以这样写:
.PHONY: clean
clean:
rm *.o temp
其他伪目标:
“all” 这个伪目标是所有目标的目标,其功能一般是编译所有的目标。
“install” 这个伪目标功能是安装已编译好的程序,其实就是把目标执行文件拷贝到指定的目标中去。
"print” 这个伪目标的功能是例出改变过的源文件。
“tar” 这个伪目标功能是把源程序打包备份。也就是一个tar文件。
“dist” 这个伪目标功能是创建一个压缩文件,一般是把tar文件压成Z文件。或是gz文件。
文件搜索
在一些大的工程中,有大量的源文件,我们通常的做法是把这许多的源文件分类,并存放在不同的目录中。所以,当make需要去找寻文件的依赖关系时,你可以在文件前加上路径,但最好的方法是把一个路径告诉make,让make在自动去找。
VPATH = src:../headers
vpath < pattern> < directories> 为符合模式< pattern>的文件指定搜索目录<directories>。
Makefile 使用总结 === http://www.cnblogs.com/wang_yb/p/3990952.html
Makefile常用万能模板(包括静态链接库、动态链接库、可执行文件)=== https://www.cnblogs.com/cyyljw/p/8137015.html
######################################
#
######################################
#source file
#源文件,自动找所有.c和.cpp文件,并将目标定义为同名.o文件
OBJS := $(patsubst %.c,%.o,$(wildcard *.c))
#target you can change test to what you want
#目标文件名,输入任意你想要的执行文件名
TARGET := test
#compile and lib parameter
#编译参数
CC := gcc
LIBS := -lpthread -lxml
LDFLAGS := -L../pub/debug
DEFINES := -D_PRODUCT_VERSION=\"2018.05.06"\
INCLUDE := -I../pub/inc -I./inc
CFLAGS := -g -Wall -fno-strict-aliasing -O3 $(DEFINES) $(INCLUDE)
CXXFLAGS:= $(CFLAGS)
#i think you should do anything here
#下面的基本上不需要做任何改动了
all : $(TARGET)
clean :
rm -fr *.o
$(TARGET) : $(OBJS)
$(CC) $(CXXFLAGS) -o $@ $(OBJS) $(LDFLAGS) $(LIBS)
#交叉编译
ifdef powerpc
CC: = /opt/powerpc-linux-gnu-gcc
endif