【转】makefile那些事儿
一、好处
自动化编译,一条make命令,整个工程可以完全自动编译,make命令是构建大型项目的首选方案。
makefile就像一个shell脚本一样,用来定义规则,一个名称包含一条或多条命令,在终端make 规则,即可执行某项规则定义的命令。
二、问题记录
1、mac系统明明没有安装make命令,为什么可以直接使用?
电脑系统没有安装GNU Make, 但是可以在mac终端使用make,但是为什么没有安装git,就不能直接使用git?
shell是命令解析器,又是一种程序设计语言,它类似于DOS下的command.com和后来的cmd.exe。它接收用户命令,然后调用相应的应用程序。shell是linux,unix系统的外壳,也可以理解为命令行,就是你输入命令的地方。
bash是大多数Linux系统以及Mac OS X默认的shell,温习一下linux系统。
git是版本控制工具,通过命令行和图形界面两种方式使用shell。
2、直接在终端输入make,会怎么样?
如果Make命令运行时没有指定目标,默认会执行Makefile文件的第一个目标。
3、如何让两行代码在一个进程执行?
要么将两行命令写在一行,中间用分号分隔,这样就可以共享变量;
要么在每行换行前,加反斜杠\,转义。
4、格式不对,不是tab。
makefile:4: *** missing separator. Stop.
把代码重新tab下。
5、检查语法是否有问题
t1 is up to date
make t1,显示上述问题,说明t1已经存在,最新。排除法,查看和解决。
三、参考学习
https://www.gnu.org/software/make/manual/make.html
https://www.w3cschool.cn/mexvtg/sriygozt.html
http://www.ruanyifeng.com/blog/2015/02/make.html
http://www.ruanyifeng.com/blog/2015/03/build-website-with-make.html
linux其他命令:https://www.cnblogs.com/worldleader131/p/linux-sth.html
四、格式
1、定义一个规则
目标:前置条件
TAB 命令
目标可以是文件名,也可以是某个操作名,称为伪目标。
如果当前目录中,正好有一个文件和某个目标名一样,那么这个命令不会执行。因为Make发现文件已经存在,就认为没有必要重新构建了,就不会执行指定的命令。
为了避免这种情况,可以明确声明clean是"伪目标",加上temp。
目标:前置条件
TAB 命令 temp
命令表示如何更新目标文件,由一行或多行shell命令组成,每行命令之前必须有一个tab键。
五、语法
1、定义变量
用等号给变量赋值,用$()引用变量。
entryPath="./bin/server" start: node $(entryPath)
#比如命令,两个$$
@echo $$branch
echo "这是一句话"
5、【@】在规则前:代表不在终端中输入该命令。
# 定义服务器启动文件路径
7、回声
make会打印每条命令,然后执行,这叫做回声。如果在命令前加@,可以关闭回声。
- 一个进程一条命令
7.1 执行make printRedBg,终端没有任何输出。
# 定义红色背景 RED_BG=`echo "\033[41m"` printRedBg: @ # echo "$(RED_BG) Background in red"
7.2 执行make printRedBg,终端输出# echo "`echo "\033[41m"` Background in red"
# 定义红色背景 RED_BG=`echo "\033[41m"` printRedBg: # echo "$(RED_BG) Background in red"
7.3 执行make printRedBg,终端输出红色背景的Background in red【正确】
# 定义红色背景 RED_BG=`echo "\033[41m"` printRedBg: @ echo "$(RED_BG) Background in red"
7.4 执行make printRedBg,终端第一行输出echo "`echo "\033[41m"` Background in red",第二行输出红色背景的Background in red
# 定义红色背景 RED_BG=`echo "\033[41m"` printRedBg: echo "$(RED_BG) Background in red"
- 一个进程多条命令
7.5 执行 make t1,终端不会打印下列命令,只会执行。【正确】
可以看到,在一条进程里面,export进程开头有一个@,就可以关闭回声,不必在内部命令比如echo前写@,如果写了,也会报错。因为每行用&&\做了连接,说明它们共享同一个进程。
t%:
@ export branch=`git branch | grep \* | grep -Eo ' .+'` && \
echo "当前分支: $$branch" && \
git checkout t$* && \
git pull --rebase && \
echo "merging: \033[0;31morigin/develop\033[0m" && \
git merge origin/develop && \
echo "merging: \033[0;31m$$branch\033[0m" && \
git merge $$branch && \
git push && \
git checkout $$branch;
@ echo "\n 自动发布中,查看进度:https://gitlab.pinganfang.com/f2e/webApp/pipelines";
7.6 执行 make t1,终端会打印下列所有命令,然后会执行。其实没必要让开发者看到命令行是什么。
t%: @ export branch=`git branch | grep \* | grep -Eo ' .+'` && \ echo "当前分支: $$branch" && \ git checkout t$* && \ git pull --rebase && \ echo "merging: \033[0;31morigin/develop\033[0m" && \ git merge origin/develop && \ echo "merging: \033[0;31m$$branch\033[0m" && \ git merge $$branch && \ git push && \ git checkout $$branch; @ echo "\n 自动发布中,查看进度:https://gitlab.pinganfang.com/f2e/webApp/pipelines";
8、函数
# 定义一个函数,取第1个参数$(1),实际值比如t1,t2 define mytest - git branch -D $(1); git fetch; @ export branch=`git branch | grep \* | grep -Eo ' .+'` && \ echo "当前分支: $$branch" && \ git checkout t$* && \ git pull --rebase && \ echo "merging: \033[0;31morigin/develop\033[0m" && \ git merge origin/develop && \ echo "merging: \033[0;31m$$branch\033[0m" && \ git merge $$branch && \ git push && \ git checkout $$branch; @ echo "\n 自动发布中,查看进度:https://gitlab.pinganfang.com/f2e/webApp/pipelines"; endef # 定义规则,调用函数 t%: $(call mytest, t$*) # 执行规则,在终端输入 make t1
t1的1和t%匹配成功,$*就等值于1,传给mytest参数值为t1。
9、目标只是一个%的时候,它会匹配任何一个文件名,称作match-anything规则。
六、使用
在根目录新建一个makefile文件,里面按照语法定义一些规则,然后make 规则。
七、从命令行给makefile传值
1、传数字
# 定义规则,打印来自命令行的传值 val%: @ echo $* # 执行规则,在终端输入make val1 会看到结果为1
val1的1和val%匹配成功,$*就等值于1。
# 定义规则,打印来自命令行的传值 val%: @ echo $@ # 执行规则,在终端输入make val1 会看到结果为val1
val1的1和val%匹配成功,$@就等值于val1。
2、传字符串
# 定义规则,打印来自命令行的传值 testArgs: @echo '当前分支:'$(CURRENT_BRANCH)' 构建分支:'$(TARGET_BRANCH) # 执行规则,在终端输入make testArgs CURRENT_BRANCH=master TARGET_BRANCH=master 会看到结果为【前分支:master 构建分支:master】