范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

Makefile学习

  Makefile   在开源项目中还是相当的常见的,熟悉他的基本语法,还是很有必要的,其次是Makefile相对于shell脚本的优点就是他的关联性,和前置条件等都很好的解决的构建链条的问题。有些学c/cpp的同学可能比较熟悉,我们这个核心不关注于这个,主要是使用在日常中make 一些cli参数-n 参数:   使用 -n 参数,让 make 命令输出将要执行的操作步骤,而不是真正执行这些操作;    makefile git:(master)   touch Makefile2          makefile git:(master)   make -n         rm -f Makefile1 Makefile2 Makefile3    makefile git:(master)   ls  Makefile  Makefile1 Makefile2-f 参数:  使用 -f 参数,后面可以接一个文件名,用于指定一个文件作为 makefile 文件。如果没有使用 -f 选项,则 make 命令会在当前目录下查找名为 makefile 的文件,如果该文件不存在,则查找名为 Makefile 的文件。 -C   参数 一般当我们调用其他目录的makefile,可以直接make -C    执行完退回当前make命令,类似于shellinclude   可以引用用其他的makefile,类似于其他编程语言的import  ,和环境变量MAKEFILES   等效
  Makefile文件 include a.make b.make  all: echoa echob     @echo hello
  a.make 文件 echoa:     @echo hello a
  b.make 文件 echob:     @echo hello b
  执行
  1) 可以发现include却是是把它完完全全的copy到了头部    makefile git:(master)   make hello a
  2)继续,完全符合    makefile git:(master)   make all hello a hello b hellomakefile一些环境变量MAKE
  其实就是你的make环境变量的,  which make   即可.PHONY: all  all:     @echo "make路径: $(MAKE)"
  输出    makefile git:(master)   make make路径: /Library/Developer/CommandLineTools/usr/bin/makeRM
  这个主要是当作  rm -f  参数.PHONY: all  clean:     $(RM) Makefile1 Makefile2 Makefile3
  输出:    makefile git:(master)   make rm -f Makefile1 Makefile2 Makefile3MAKEFILE_LIST
  MAKEFILE_LIST  的变量, 它是个列表变量, 在每次make读入一个make文件时, 都把它添加到最后一项,gnu make 有效。Makefile 文件 all:     @echo "当前makefile: $(MAKEFILE_LIST)"     @$(MAKE) -f Makefile2Makefile 文件2 all:     @echo "当前makefile: $(MAKEFILE_LIST)"
  输出    makefile git:(master)   make 当前makefile:  Makefile 当前makefile:  Makefile2
  所以依靠这个可以获取当前路径,但是目前没有模拟出 MAKEFILE_LIST   多个列表.PHONY:  first:     @echo $(MAKEFILE_LIST)  second:     @echo $(lastword $(MAKEFILE_LIST))  third:     @echo $(realpath $(lastword $(MAKEFILE_LIST)))  latest: first second third     @echo $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
  执行    go-source git:(master)   make latest  Makefile Makefile /Users/fanhaodong/go/code/go-source/Makefile /Users/fanhaodong/go/code/go-sourcemakefile 文件书写规则
   makefile 文件由一组 依赖关系 和规则 构成。每个依赖关系都由一个目标(即将要创建的文件)和一个该目标所依赖的源文件组成;规则描述了如何通过这些依赖文件创建目标。简单的来说,makefile 文件的写法如下:target: prerequisites     command1     command2     ...
  其中, target   是即将要创建的目标(通常是一个可执行文件),target   后面紧跟一个冒号,prerequisite   是生成该目标所需要的源文件(依赖),一个目标所依赖的文件可以有多个,依赖文件与目标之间以及各依赖文件之间用空格或制表符 Tab 隔开,这些元素组成了一个依赖关系 。随后的命令 command 就是规则 ,也就是 make 需要执行的命令,它可以是任意的 shell 命令。另外,makefile 文件中,注释以 # 号开头,一直延续到该行的结束 。
  比如下面这个,target就是 hello  ,prerequisite  是hello.c  的文件hello:  hello.c     $(CC) -o hello.s -S hello.c     $(CC) -o hello.o -c hello.s     $(CC) -o hello hello.o
  构建c项目all: test   test: test.o anotherTest.o      gcc -Wall test.o anotherTest.o -o test  test.o: test.c      gcc -c -Wall test.c   anotherTest.o: anotherTest.c      gcc -c -Wall anotherTest.c   clean:      rm -rf *.o test
  GNU的make工作时的执行步骤如下: 读入所有的Makefile。 读入被include的其它Makefile。 初始化文件中的变量。 推导隐晦规则,并分析所有规则。 为所有的目标文件创建依赖关系链。 根据依赖关系,决定哪些目标要重新生成。 执行生成命令。
  1-5步为第一个阶段,6-7为第二个阶段。第一个阶段中,如果定义的变量被使用了,那么,make会把其展开在使用的位置。但make并不会完全马上展开,make使用的是拖延战术,如果变量出现在依赖关系的规则中,那么仅当这条依赖被决定要使用了,变量才会在其内部展开。
  当然,这个工作方式你不一定要清楚,但是知道这个方式你也会对make更为熟悉。有了这个基础,后续部分也就容易看懂了。 申明变量=   类似宏一样,他会对变量进行引用,在执行时扩展,允许递归扩展:=   如果变量申明符合先来后到,和=  含义一样,但是如果 申明a引用了b但是b还没有申明,此时认为b为空a = $(b) + 1 b = 2  c := $(d) + 1 d = 2  all:     @echo $(a)     @echo $(c)
  输出    makefile git:(master)   make 2 + 1 + 1
  奇怪的现象: 可以发现我们申明a变量后,但是输出的时候却是 100 ,可以发现cli传递的优先级最高,不可以被覆盖    makefile git:(master)   make a=100         100 + 1?=   如果a变量前面已经申明过了,那么后面a ?=xxx   则因为前面已经申明了a,所以不进行赋值,也就是a?=xxxx  无效,如果前面没有申明则有效A = hello A ?= hello world  all:     @echo $(A)
  输出: hello  +=   这个类似于a+=1   , 意思就是在原来的基础上 += ,很方便,下面提供demobuild_args := -race ifeq ($(vendor),true)     build_args += -mod=vendor endif all:     @echo $(build_args)
  输出:    makefile git:(master)   make vendor=true -race -mod=vendor命令行参数echo:     @echo $(arg)
  执行:    makefile git:(master)   make arg=ruoyu ruoyu执行函数1、call+ define 宏定义
  类似于C语言的宏定义 # 编译生成到bin目录下 define build     sh ./build.sh $(1) ./bin/$(strip $(2)) endef # 脚手架脚本 go-build: pre     $(call build, cmd/go-build/main.go, go-build)2、自带函数
  格式  $(<命令><参数>)  all:     @echo $(lastword 1 2 3)
  输出    makefile git:(master)   make 33、调用shell函数all:     @echo $(shell dirname /data/test)
  执行    makefile git:(master)   make /dataMakefile文件的语法 :   [tab]  target: 目标,支持模式匹配 prerequisites:前置条件,可以有多个,支持模式匹配 commands: 前面必须有 tab   ,是shell命令/makefile函数命令1、注释
  注释一般使用 #   开头表示,但是如果注释在目标的命令包含# 一般all定义了全部 all:     #hello
  执行    makefile git:(master)   make #hello2、关闭回声
  这个其实很简单,就是在执行shell命令的时候,往往会打印日志,所以这里提供了很好的解决方式,使用 @   符号all:     echo "hello world"
  执行后会发现,每次执行的时候都会打印回声    makefile git:(master)   make echo "hello world" hello world
  所以可以将makefile文件改成以下 all:     @echo "hello world"
  输出    makefile git:(master)   make hello world3、通配符
  和bash一样,主要有 *   等通配符,主要是在 shell脚本中使用new:     for x in {1,2,3,4};do touch $x.test ;done clean:     $(RM) *.test
  执行    makefile git:(master)   make new  for x in {1,2,3,4};do touch $x.test ;done    makefile git:(master)   ls | grep test 1.test 2.test 3.test 4.test    makefile git:(master)   make clean  rm -f *.test    makefile git:(master)   ls | grep test4、模式匹配
  主要是对文件名的支持!主要是在 目标和依赖中使用, 使用匹配符%,可以将大量同类型的文件,只用一条规则就完成构建。 %.o: %.c
  等同于 f1.o: f1.c f2.o: f2.c
  不懂的可以看一下这篇文章,对比一下 模式匹配和通配符的区别 : https://blog.csdn.net/BobYuan888/article/details/88640923
  理解模式匹配必须了解下面这四个
  $@  :目标的名字
  $^  :构造所需文件列表所有所有文件的名字
  lt;  :构造所需文件列表的第一个文件的名字
  $?  :构造所需文件列表中更新过的文件
  大致原理: 我要找 f1.o  的构造规则,看看Makefile中那个规则符合。然后找到了%.o:%.c 来套一下来套一下 %.o 和我要找的 f1.o   匹配套上了,得到%= f1  。所以在后面的%.c就表示 f1.c  了。OK进行构造
  1、例子一(编译c文件) %.o: %.c %.h     @echo "目标的名字: $@, 依赖的第一个文件: lt; , 依赖的全部文件: $^, 所更新的文件: $?"     $(CC) -o $@ -c lt; all: utils.o     @echo "编译…"    clean:     $(RM) *.i *.s *.o main
  执行,可以看到完全符合我们的例子 目标的名字: utils.o, 依赖的第一个文件: utils.c , 依赖的全部文件: utils.c utils.h, 所更新的文件: utils.c utils.h cc -o utils.o -c utils.c 编译…for循环1、makefile: foreach循环
  语法: $(foreach,$(g_var),;)   , 这里需要变量引用需要使用$()  list := $(shell ls)  all:     @$(foreach item,$(list),         echo $(item);         echo $(realpath $(item));         echo "====================";     )
  输出:    makefile git:(master)   make Makefile /Users/fanhaodong/note/note/demo/makefile/Makefile ==================== Makefile1 /Users/fanhaodong/note/note/demo/makefile/Makefile1 ==================== Makefile2 /Users/fanhaodong/note/note/demo/makefile/Makefile2 ====================3、shell:for 循环list := $(shell ls)  all:     @for x in $(list); do         echo $x;     done
  记住一点就好, $   符号转移需要使用$
  执行    makefile git:(master)   make mfor  Makefile Makefile1 Makefile2 a.make b.makeif 函数1、makefile: if 函数
  命令格式: $(if,;,;)  all:     @$(if $(shell command -v $(arg)),echo command $(arg) is exist,echo command $(arg) is not exist)
  执行    makefile git:(master)   make arg=go command go is exist    makefile git:(master)   make arg=go1 command go1 is not exist2、shell: if 函数all:     @if [ `command -v $(arg)` ];then         echo "command [$(arg)] is exist";     else          echo "command [$(arg)] is not exist";     fi
  执行    makefile git:(master)   make arg=go command [go] is exist    makefile git:(master)   make arg=go1 command [go1] is not exist执行多个命令echo:     @echo hello world echo2:     @echo hello world 2
  执行:    makefile git:(master)   make echo echo2 hello world hello world 2宏定义define echo     echo "hello, $(1)!" endef  ARG :=  ifdef arg     ARG := $(arg) else     ARG := NULL endif      all: print     @$(call echo,"world")     @echo $(ARG)  print:     @echo "arg: $(arg)"
  执行    makefile git:(master)   make arg=world arg: world hello, world! world系统环境变量
  申明推荐: export<变量名称>   , 获取使用${<变量名称>}  GOPROXY := https://goproxy.cn,direct export GOPROXY  all:     @echo ${GOPROXY}编译C项目
  c项目往往很复杂,设计到 预编译,编译,汇编,链接 的过程
  1、文件 (头文件、main文件)
  1、utils.h #ifndef _ADD_H_ #define _ADD_H_  int add (int a,int b);  #endif
  2、utils.c int add(int x ,int y){     return x+y; }
  3、main.c
  注意:头文件的寻找方式 先搜索当前目录 然后搜索-I指定的目录,例如 -I ./head  再搜索gcc的环境变量CPLUS INCLUDE PATH(C程序使用的是C INCLUDE PATH) 最后搜索gcc的内定目录 #include  #include "utils.h"  int main(int argc, char const *argv[]) {     printf("1+2 = %d ",add(1,2));     return 0; }
  假如 .h 文件放在 head 目录    cpp git:(master)   ls head  utils.h # 可以发现编译异常,异常时 .h文件未找到    cpp git:(master)   gcc -c main.c -o main.o main.c:2:10: fatal error: "utils.h" file not found #include "utils.h"          ^~~~~~~~~ 1 error generated. # 修改 -I 参数可以发现通过    cpp git:(master)   gcc -I ./head  -c main.c -o main.o    cpp git:(master)   ls | grep main.o main.o2、预编译-E
  -E  :预编译,这一步主要是将头文件,宏定义展开到文件,是文本形式   cpp git:(master)   gcc -E main.c -o main.i    cpp git:(master)   tail -f 10 main.i  tail: 10: No such file or directory  ==> main.i <==  ### 可以看到这里是把 utils.h 的头文件信息 copy 过来了 int add (int a,int b); # 3 "main.c" 2  int main(int argc, char const *argv[]) {     printf("1+2 = %d ",add(1,2));     return 0; }3、编译-S
  编译为汇编代码,是文本形式     cpp git:(master)   gcc -S main.i -o main.s
  4、汇编-c
  就是编译成二进制的汇编文件,是可重定位目标程序,属于二进制文件     cpp git:(master)   gcc -c main.s -o main.o    cpp git:(master)   hexdump -C main.o 00000000  cf fa ed fe 07 00 00 01  03 00 00 00 01 00 00 00  |................| 00000010  04 00 00 00 08 02 00 00  00 20 00 00 00 00 00 00  |......... ......| 00000020  19 00 00 00 88 01 00 00  00 00 00 00 00 00 00 00  |................| 00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 00000040  b0 00 00 00 00 00 00 00  28 02 00 00 00 00 00 00  |........(.......| 00000050  b0 00 00 00 00 00 00 00  07 00 00 00 07 00 00 00  |................| 00000060  04 00 00 00 00 00 00 00  5f 5f 74 65 78 74 00 00  |........__text..| 00000070  00 00 00 00 00 00 00 00  5f 5f 54 45 58 54 00 00  |........__TEXT..| 00000080  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................| 00000090  42 00 00 00 00 00 00 00  28 02 00 00 04 00 00 00  |B.......(.......| 000000a0  d8 02 00 00 03 00 00 00  00 04 00 80 00 00 00 00  |................|    cpp git:(master)   objdump -d main.o  main.o: file format Mach-O 64-bit x86-64   Disassembly of section __TEXT,__text:  0000000000000000 _main:        0: 55                            pushq   %rbp        1: 48 89 e5                      movq    %rsp, %rbp        4: 48 83 ec 20                   subq    $32, %rsp        8: c7 45 fc 00 00 00 00          movl    $0, -4(%rbp)        f: 89 7d f8                      movl    %edi, -8(%rbp)       12: 48 89 75 f0                   movq    %rsi, -16(%rbp)       16: bf 01 00 00 00                movl    $1, %edi       1b: be 02 00 00 00                movl    $2, %esi       20: e8 00 00 00 00                callq   0 <_main+0x25>       25: 48 8d 3d 16 00 00 00          leaq    22(%rip), %rdi       2c: 89 c6                         movl    %eax, %esi       2e: b0 00                         movb    $0, %al       30: e8 00 00 00 00                callq   0 <_main+0x35>       35: 31 c9                         xorl    %ecx, %ecx       37: 89 45 ec                      movl    %eax, -20(%rbp)       3a: 89 c8                         movl    %ecx, %eax       3c: 48 83 c4 20                   addq    $32, %rsp       40: 5d                            popq    %rbp       41: c3                            retq5、链接
  对于c/cpp语言来说,最难的就是链接了!这里也设计到隐晦规则了,首先 .o   是符合main.o  ,utils.o  的,所以会执行 两次cc  ,最终链接成功# 伪目标,这里定义的目标不会去文件系统里寻找 .PHONY: all clean # CC 属于makefile的全局变量,已经定义好了,但是我们使用gcc需要指定 CC := gcc  # $@ 目前的目标项目名称 也就是 %.o # lt; 目前的依赖项目 %.o: %.c     $(CC) -c lt; -o $@ all: install run clean # 当依赖符合模式匹配时候,会执行上面的 %.o: %.c install: utils.o main.o     gcc -o main utils.o main.o run:     ./main clean:     $(RM) *.i *.s *.o main
  执行    cpp git:(master)   make gcc -c utils.c -o utils.o gcc -c main.c -o main.o gcc -o main utils.o main.o ./main 1+2 = 3 rm -f *.i *.s *.o main帮助
  如果你想写help,可以使用下面那个表达式 .PHONY: help  echo: ## 打印echo     @echo "hello"  all: ## 打印echo1  help: ## 帮助     @awk "BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {sub("\n",sprintf(" %22c"," "), $2);printf " 33[36m%-20s33[0m  %s ", $1, $2}" $(MAKEFILE_LIST)
  其实很简单,了解 awk 语法的话,知道 awk "条件 动作"文件名   所谓条件就是正则表达式,分隔符是:.*?##  ,然后匹配的条件是以 字母开头的[root@19096dee708b data]# cat demo.txt 11 22 111 22 33
  匹配一下· [root@19096dee708b data]# awk  "{printf "$1=%s $2=%s ",$1,$2}" demo.txt $1=11 $2=22 $1=111 $2= $1=22 $2=33
  我们要拿到我们的结果!所以需要匹配有空格的,匹配空格就是 s  [root@19096dee708b data]# awk  "/s/ {printf "$1=%s $2=%s ",$1,$2}" demo.txt $1=11 $2=22 $1=22 $2=33

一年诞生1700万虚拟人类,人们为什么想和AIbeings做朋友?来源中国经济周刊经济网中国经济周刊记者孙冰北京报道作词作曲加演唱,写诗作画搞设计,播音主持当Up主虚拟人类(即人工智能个体,AIbeings)正在以超乎想象的速度实现着各种不可能。旧小米手机能干什么?感谢你的阅读。不仅是小米手机,任何安卓机或苹果机都有把废变宝的效果,简单例举如下几项。时钟遥控器行车记录仪wifi放大器装饰品二手平台卖出一时钟下载时钟app,可以实现时间常亮闹钟你用过最有质感的手机是什么?感谢邀请你用过最有质感的手机是什么?题主问题的核心是你用过最有质感的手机是什么?实际我用过的手机很多,但是我觉得vivo的手机给我的印象是最好的,当然这不仅仅是从外观设计的创新方面驶向绿色与智慧快车道来源人民网人民日报图片来源影像中国制图赵偲汝汽车大大拓展了人们的活动半径,也不断改变着人们的生产生活方式。随着移动互联大数据人工智能等科技的发展,共享经济电子商务等新兴运营模式的兴电商及直播带货凸显的影响曾几何时一家几口在闲暇之余一起逛商场门店,妻子们与货主砍价斗志斗勇,丈夫们拧着大包小包无聊的等待,孩子们在大人呵斥声到处乱跑嘻戏。这些镜头已慢慢减少,变成了记忆。没有什么购物是一台来聊聊分布式数据一致性Base理论对于CAP理论来说,放弃强一致性,追求分区容错性和可用性,这是很多分布式系统设计的时候,最常选择的一种设计方式。在实际项目工程中,基于CAP理论逐步演化,后来就提出了B阿法狗等AI出现以后,围棋认知被完全颠覆,AI下出最让人感到不可思议的是哪步棋?说实话,阿狗的对局大致都看过,很多记不太清了。说到最不可思议的棋,其实和每个人的围棋水平有很大的关系。这个问题其实只能由现在围棋水平最高的人回答才会有权威性。爱好者看到的阿狗哪些令数字赋能高职数学三教改革新时代以互联网为标志的信息革命拓展了教学的时间空间质量和效率维度,也为技术赋能三教改革提供了重要的战略机遇。应用高等数学作为高职院校的一门基础课,目前还存在生源类型较多与要求多样数一千元以内国内品牌性价比高的手机有哪些?价格在一千以内的手机,国内品牌华为荣耀oppo和vivo都有对应的机型,我从这些品牌中各挑出一款性价比突出的机型,跟大家分析一下。一红米Note8,性能之选这款手机是小米旗下子品牌光刻机制造瓶颈在哪里?很多人都说光刻机的制造难度超越了原子弹,这绝不是夸张的。荷兰ASML生产的EUV光刻机光刻机是干什么用的?制造芯片的设备光刻机的原理是什么呢?简单的来说就是冲洗照片,不同的是洗照片如何调整相机设置,解决照片背景曝光过度而人像曝光不足的问题?在拍摄人像照片时,经常看到拍摄的照片背景过亮甚至亮的没有细节,而拍摄的人物又爆光不足,黑黑的一片,惨不忍睹,结果,美女看了下次再不会找你拍照了。出现这种情况,是由于现代都的相机受技
索尼前首席执行官担忧日本制造输给中国为什么日本制造业无法战胜中国?索尼前CEO出井伸之说这是日本醉心于过去的日本制造神话,未能很好融合IT技术使然日本民营厂商还存在对政府官僚依赖的大问题。本文内容摘录自他的新书经营人从3599元跌至2499元,6400万四摄55W,12GB运存旗舰售价大跳水机身储存容量可以低,但运行内存不能小,这就是如今智能手机选择不同规格版本最佳的答案,一般来说128GB机身储存容量不过度储存图片和视频基本已经够用了,不会影响日常使用,但运行内存就进可攻,退可守的创新Stage360音箱,体验入门级杜比全景声疫情不断反复,宅在家里的时间也越来越长,为了让在家里的时间也充满欢乐,决定将家庭影音系统的音质加强一下。但传统的家庭影院对物理空间和布线都有很高的要求,对大多数人来说都没有精力或者华为员工被判刑,竟越权访问机密数据,发给这家公司!收受5双篮球鞋,7000元购物卡4月12日,一则华为员工利用公司系统Bug越权访问机密数据被判刑的消息登上微博热搜!图片源自微博这则消息大致情况为,华为员工易某调离岗位后未清理ERP登陆信息,利用bug越权访问,苹果概念股思林杰上市22天跌18天,股民怒了没有哪个公司像这样文张佳儒估计中签缴费的人,心都在滴血!这哪里是吃肉,这是挨飞刀!有股民这样评价科创板新股思林杰,连续跌一个月,到现在还没有明显企稳的迹象,这是很难受的走势。4月14日午盘,思林杰报年度全能5G手机荣耀X10荣耀X10在外观上也保证了相当的水平,正面搭载了6。63英寸升降式全面屏,屏占比达到了92,保证了正面的全面屏视觉效果。荣耀X10背面引进了类似图像分割的设计语言,光线打上去之后能吉利新能源几何C解决您的续航焦虑为消除纯电动车用户痛点,几何C搭载全球首创能量管理解决方案SEM智能能量管理系统蓄能节能提升NEDC基准续航,回能提升真续航控能提升真准续航通过领先的大数据自学习,不断积累升华,通江龙船艇氢装上船聚焦新能源船助力双碳目标随着生态文明建设的加快和碳达峰碳中和目标的提出,清洁燃料在船舶领域的应用正在迎来新的曙光。作为下一代船用清洁能源,氢燃料近年来在航运业减排中的作用备受关注,布局氢能船舶的企业明显增中国要警惕特斯拉这样的企业如标题所说,我们需要警惕中国境内的特斯拉们,就当是阴谋论吧,但确实有些事情不得不说。1。马斯克拿拜登开涮,各位别太当真,在美国的媒体上经常有这样的情形发生,也许这就是美国的自由吧,终于降了,本周五油价或下调结束六连涨,新能源却被迫涨价今年油价连续六连涨,国内油价也达到历史高位。目前国内平均油价95号突破9元,98号更是突破了个位数,硬是给加油站的价目表做了一次设备升级。本周五油价或迎年内首降好消息是,本周五晚上多彩保护胶原理多彩涂料保护胶是一种人工合成白色粉状锂镁硅酸盐胶体材料,无毒无味无刺激性不溶于水油和乙醇。浸水溶胀,在自来水中以较低含固量分散就可以形成高透明高粘度高触变性的纳米凝胶而同样的含固量