1.1 makefile介绍
make是一个工程管理器,它可以根据文件时间自发检测更新的文件从而减少编译量,makefile文件和make工具一起使用,用于控制工程项目的编译和链接,也可以用来编写手册页和程序的安装。make工具用于解释执行makefile文件中的内容。makefile文件中通常包含源文件和目标文件的依赖关系以及从源文件生成目标文件的规则。make工具可以根据makefile判断哪些文件需要被重新编译,目标文件的构建顺序等。
1.2 makefile文件名
make会自动识别GUNmakefile,makefile,Makefile,最好使用Makefile,有的系统不会检测别的文件名。
当然可以使用 make -f xxx 指定文件,建立的时候尽量使用makefilexxx
1.3 makefile规则
目标:依赖
命令
目标:可以使文件名,也可以是标签,但必须存在。如果是标签作为第一个,会被一直执行。
依赖:可以使文件名,字符等。可以没有
命令:从行首加入Tab键,可以没有
test.o:test.s
gcc -c test.s -o test.o
注意:规则与规则之间没有必然的顺序关系
第一条的目标会成为终极目标
使用make之前需要把系统时间纠正准确,因为makefile是根据时间来进行编译的
假设:先对fun1.c进行修改,然后删除原来的fun1.c和fun1.out,在重新复制出来,此时虽然是原先的文件.
但是fun1.o和app的时间都改变了,系统检测到时间相比上次发生改变,则不给予执行。
2.1显式规则
显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的编写人员明显指出,要生成的文件,文件的依赖文件,生成的命令。
sr1=test.c
G=gcc
#include tes.mk
#AAA=$(patsubst *.c,*.o $(notdir $(wildcard /root/test1/714/*.c)))
# echo "$(AAA)"
test.out:test.o
gcc test.o -o $@
test.o:test.s
gcc -c test.s -o test.o
# echo "$(test)"
%.s:%.i
${G} -S $^ -o $@
test.i:${sr1}
${G} -E $^ -o $@
2.2隐晦规则
有一点需要注意的是,"%"的展开发生在变量和函数的展开之后,变量和函数的展开发生在make载入Makefile时,而模式规则中的"%"则发生在运行时。
2.3变量定义
(1)变量在定义的时候需要给定初始值,一般在使用变量的时候加上“$(变量名称)”或者“${变量名称}”,推荐(),如果存在函数有色态提醒
SS=test.c
app:$(SS)
gcc $(SS) -o app
(2)运算符:
=:延时展开赋值
A=$(B)
B=hello
echo "$(A)"
结果:
echo "hello"
hello
:=:立即赋值
A:=$(B)
B=hello
echo "$(A)"
结果:
echo ""
\r\n
+=:追加赋值
A=$(B)
B=HELLO
B+=1111
app:
echo "$(A)"
结果:
echo "HELLO 1111"
HELLO 1111
?=:判断变量是否赋值,如果之前已经赋值,则不赋值,否则,赋值
fliet=1
fliet?=2 //判断是否赋值过
A=$(fliet)
app:
echo "$(A)"
结果:
echo "1"
1
屏蔽fliet=1
echo "2"
2
$$:$
$^: 规则中所有依赖
$<:代表规则中的第一个依赖名,如果是隐晦规则,则代表由隐晦规则加入的第一个依赖文件名,配合%等规则使用
$@:当前规则的目标名称
@:不显示在标准输出/
2.4文件指示
make命令开始时,会把找寻找include所指出的其它Makefile,并把其内容安置在当前的位置。就好像C/C++的#include指令一样。
如果有文件没有找到的话,make会生成一条警告信息,但不会马上出现致命错误。它会继续载入其它的文件,一旦完成makefile的读取,make会再重试这些没有找到,或是不能读取的文件,如果还是不行,make才会出现一条致命信息。如果你想让 make不理那些无法读取的文件,而继续执行,你可以在include前加一个减号“-”。如:-include
vim test.mk
写入A=HELLO
vim makefile
include test.mk
echo "A"
结果:
HELLO
2.5伪目标
指定标签运行:(make -f xxfile clean)
clean:
rm *.out test
.PHONY:clean
2.6执行步骤
加载makefile文件——>展开inlcude下的makefile文件——>变量初始化——>推导隐晦规则,分析所有规则
——>为目标文件创建依赖关系链——>根据依赖关系决定哪些需要真正生成——>执行
makefile中如果变量使用了,在创建依赖关系链的时候并不会马上展开,如果变量所存在的依赖中最后被使用了,才会真正展开
3.1匹配指定目录下文件
3.2去除文件路径
3.3模式替换函数
3.4反过滤函数
编译的时候整个库会加载到目标代码中。
优点:编译后不需要外部函数库的支持,运行速度快
缺点:如果静态库改变后,代码需要重新编译,编译的文件相对于动态库大
编译的时候不会加载到目标代码中,只是保留了相关接口,程序执行过程用到才会被加载。
优点:编译工程量比较少,库与代码相对独立,库升级不影响程序的使用
缺点:加载速度慢。
动态库就在当前目录下,为什么操作系统会提示找不到该文件呢?
原因:操作系统默认从标准位置寻找相应的库:/lib、/usr/lib、usr/local/lib。但如果没有找到依赖的库文件,则从LD_LIBRARY_PATH环境变量里寻找。
也就是说,动态库文件要么放在标准位置,要么放在LD_LIBRARY_PATH指定的位置,才能被操作系统找到。
解决方法:
1)通过环境变量,export LD_LIBRARY_PATH=动态库路径
export LD_LIBRARY_PATH=./lib 临时生效,终端重启环境变量失效 //决定动态库的搜素路径。
2)永久生效:“export LD_LIBRARY_PATH=动态库路径”写入到终端配置文件 ~/.bashrc 建议使用绝对路径。
3)拷贝自定义动态库到标准位置中
(1)使用makefile编译指定路径下的所有.c文件生成.o,同时生成可执行文件
图上圆形表示命令,方形表示文件,斜体表示需要自己编写或者修改的文件。
在存放源代码的目录下执行autoscan命令生成configure.scan文件;
将configure.scan文件改名为configure.in或者configure.ac(早起使用.in后缀),并对其默认配置进行修改;
执行aclocal、autoconf两个命令,分别生成aclocal.m4、configure文件;
执行autoheader命令,扫描configure.ac文件,生成config.h.in文件;
创建一个名为Makefile.am的文件,并输入相应的内容。
执行automake,它根据Makefile.am文件,生成Makefile.in。
执行./configure脚本文件,它根据Makefile.in文件,生成最终的Makefile文件