三.linux开发之uboot移植(三)——.基础之shell和Makefile回顾

一.补基础之shell

1.shell程序运行的运行有多种方法,这里介绍三种方法:

第一种:./xx.sh,和运行二进制可执行程序方法一样。这样运行shell要求shell程序必须具有可执行权限。chmod a+x xx.sh来添加可执行权限。

第二种:source xx.sh,source是linux的一个命令,这个命令就是用来执行脚本程序的。这样运行不需要脚本具有可执行权限。常用这个

第三种:bash xx.sh,bash是一个脚本程序解释器,本质上是一个可执行程序。这样执行相当于我们执行了bash程序,然后把xx.sh作为argv[1]传给他运行。

2.shell程序的第一行一般都是: #!/bin/sh

这行话以#!开始,后面加上一个pathname(路径),这行话的意思就是指定shell程序执行时被哪个解释器解释执行。所以我们这里写上/bin/sh意思就是这个shell将来被当前机器中/bin目录下的sh可执行程序执行。

3、shell中的变量定义和引用

(1)变量定义时可以初始化,使用=进行初始化赋值。在shell中赋值的=两边是不能有空格的。

(2)变量引用。shell中引用一个变量必须使用 符号就是变量解引用符号。

注意:$符号后面跟一个字符串,这个字符串就会被当作变量去解析。如果这个字符串本身没有定义,执行时并不会报错,而是把这个变量解析为空。也就是说在shell中没有被定义的变量其实就相当于是一个定义并赋值为空的变量。

注意:变量引用的时候可以 var {var}。这两种的区别是在某些情况下只能用 var var

4、shell中调用linux命令

(1)直接执行

(2)反引号括起来执行。有时候我们在shell中调用linux命令是为了得到这个命令的返回值(结果值),这时候就适合用一对反引号(键盘上ESC按键下面的那个按键,和~在一个按键上)来调用执行命令。
这里写图片描述
5.shell中的选择分支结构

(1)判断文件是否存在。 (-f),判断目录是否存在 (-d) 注意[]里面前后都有空格,不能省略。
这里写图片描述
(2)判断字符串是否相等("str1" = "str2"),注意用一个等号而不是两个
这里写图片描述
判断数字是否相等(-eq)、大于(-gt)、小于(-lt)、大于等于(-ge)、小于等于(-le)

(3)判断字符串是否为空(-z)注意-z判断时如果变量本身没定义也是不成立(也就是说-z认为没定义不等于为空)
这里写图片描述
(4)if判断式中使用"-o"表示逻辑或
这里写图片描述
(5)逻辑与&&和逻辑或||与简写的if表达式相结合
这里写图片描述
6.shell中的循环结构

(1)for循环、while循环

注意:while后面的[]两边都有空格,[]后面有分号分号(如果do放在一行的话),i++的写法中有两层括号
这里写图片描述
(2)echo的创建和追加输入文件

(1)在shell中可以直接使用echo指令新建一个文件,并且将一些内容传入这个文件中。创建文件并输入内容的关键就是>。

(2)还可以使用echo指令配合追加符号>> 向一个已经存在的文件末尾追加输入内容。
这里写图片描述
(3)case语句

(1)shell中的case语句和C语言中的switch case语句作用一样,格式有差异

(2)shell中的case语句天生没有break,也不需要break,和C语言中的switch case不同。shell中的case默认就是匹配上哪个执行哪个,不会说执行完了还去执行后面的其他case(就好像shell中的case语言默认都带了break)。
这里写图片描述
(4)调用shell程序的传参

shell程序本身也可以在调用时传参给他。在shell程序内部使用传参也是使用的一些特定符号来表示的,包括:#表示调用该shell时传参的个数。(#计数时只考虑真正的参数个数)

0 1、$2·····则依次表示传参的各个参数。

例如:shell:source a.sh aa bb cc # = 3,0是执行这个shell程序的解析程序的名字, 1 2是第2个有效参数的值·····
这里写图片描述
这里写图片描述
(5)shift指令改变内置变量的值

shell中的#1等内置变量的值不是不可变的,而是可以被改变,被shift指令改变。

shift指令有点像左移运算符,把我们给shell程序的传参左移了一个移出去了,原来的 2 1,原来的$#少了1个。
这里写图片描述
这里写图片描述

二.Makefile基础

1.目标、依赖、命令

(1)目标就是我们要去make xxx的那个xxx,就是我们最终要生成的东西。

(2)依赖是用来生成目录的原材料

(3)命令就是加工方法,所以make xxx的过程其实就是使用命令将依赖加工成目标的过程
这里写图片描述
2.Makefile的基本工作原理

其一,当我们执行 make xx 的时候,Makefile会自动执行xx这个目标下面的命令语句。

其二,当我们make xx的时候,是否执行命令是取决于依赖的。依赖如果成立就会执行命令,否则不执行。

其三,我们直接执行make 和make 第一个目标 效果是一样的。(第一个目标其实就是默认目标)

3.通配符%和Makefile自动推导(规则)

(1)%是Makefile中的通配符,代表一个或几个字母。也就是说%.o就代表所有以.o为结尾的文件。

(2)所谓自动推导其实就是Makefile的规则。当Makefile需要某一个目标时,他会把这个目标去套规则说明,一旦套上了某个规则说明,则Makefile会试图寻找这个规则中的依赖,如果能找到则会执行这个规则用依赖生成目标。
这里写图片描述
4.伪目标(.PHONY)

(1)伪目标意思是这个目标本身不代表一个文件,执行这个目标不是为了得到某个文件或东西,而是单纯为了执行这个目标下面的命令。

(2)伪目标一般都没有依赖,因为执行伪目标就是为了执行目标下面的命令。既然一定要执行命令了那就不必加依赖,因为不加依赖意思就是无条件执行。

(3)伪目标可以直接写,不影响使用;但是有时候为了明确声明这个目标是伪目标会在伪目标的前面用.PHONY来明确声明它是伪目标。
这里写图片描述
5.Makfile中引用其他Makefile(include指令)

(1)有时候Makefile总体比较复杂,因此分成好几个Makefile来写。然后在主Makefile中引用其他的,用include指令来引用。引用的效果也是原地展开,和C语言中的头文件包含非常相似。

三.Mafile补充学习

1.命令前面的@用来静默执行

这里写图片描述
这里写图片描述
(1)在makefile的命令行中前面的@表示静默执行。

(2)Makefile中默认情况下在执行一行命令前会先把这行命令给打印出来,然后再执行这行命令。

(3)如果你不想看到命令本身,只想看到命令执行就静默执行即可。

2.Makefile中几种变量赋值运算符

(1) = 最简单的赋值

(2) *:= * 一般也是赋值

以上这两个大部分情况下效果是一样的,但是有时候不一样。

用=赋值的变量,在被解析时他的值取决于最后一次赋值时的值,所以你看变量引用的值时不能只往前面看,还要往后面看。

用:=来赋值的,则是就地直接解析 ,只用往前看即可。
这里写图片描述
这里写图片描述
(3)?=如果变量前面并没有赋值过则执行这条赋值,如果前面已经赋值过了则本行被忽略 。(实验可以看出:所谓的没有赋值过其实就是这个变量没有被定义过)

(4)+=用来给一个已经赋值的变量接续赋值,意思就是把这次的值加到原来的值的后面 ,有点类似于strcat。(在shell makefile等文件中,可以认为所有变量都是字符串,+=就相当于给字符串stcat接续内容)(注意一个细节,+=续接的内容和原来的内容之间会自动加一个空格隔开)
这里写图片描述
这里写图片描述
注意:Makefile中并不要求赋值运算符两边一定要有空格或者无空格,这一点比shell的格式要求要松一些。

3.Makefile的环境变量

(1)makefile中用export导出的就是环境变量。一般情况下要求环境变量名用大写,普通变量名用小写。

(2)环境变量和普通变量不同,可以这样理解:环境变量类似于整个工程中所有Makefile之间可以共享的全局变量,而普通变量只是当前本Makefile中使用的局部变量。所以要注意:定义了一个环境变量会影响到工程中别的Makefile文件,因此要小心。

(3)Makefile中可能有一些环境变量可能是makefile本身自己定义的内部的环境变量或者是当前的执行环境提供的环境变量(譬如我们在make执行时给makefile传参。make CC=arm-linux-gcc,其实就是给当前Makefile传了一个环境变量CC,值是arm-linux-gcc。我们在make时给makefile传的环境变量值优先级最高的,可以覆盖makefile中的赋值 )。这就好像C语言中编译器预定义的宏__LINE__ __FUNCTION__等一样。
这里写图片描述
这里写图片描述

4.Makefile中使用的各种通配符

详细参考资料

(1)* 若干个任意字符

(2)? 1个任意字符

(3)[] 将[]中的字符依次去和外面的结合匹配

还有个%,也是通配符,表示任意多个字符,和*很相似,但是%一般只用于规则描述中,又叫做规则通配符。
这里写图片描述
这里写图片描述

5.Makefile的自动变量

(1)为什么使用自动变量。在有些情况下文件集合中文件非常多,描述的时候很麻烦,

所以我们Makefile就用一些特殊的符号来替代符合某种条件的文件集,这就形成了自动变量。

(2)自动变量的含义:预定义的特殊意义的符号。就类似于C语言编译器中预制的那些宏__FILE__一样。

(3)常见自动变量:
这里写图片描述
$@

* 表示规则中的目标文件集。在模式规则中,如果有多个目标,那么,"$@"就是匹配于目标中模式定义的集合。*

$%

* 仅当目标是函数库文件中,表示规则中的目标成员名。例如,如果一个目标是"foo.a(bar.o)",那么," @"就是"foo.a"。如果目标不是函数库文件(Unix下是[.a],Windows下是[.lib]),那么,其值为空。*

$<

* 依赖目标中的第一个目标名字。如果依赖目标是以模式(即"%")定义的,那么"$<"将是符合模式的一系列的文件集。注意,其是一个一个取出来的。*

$?

* 所有比目标新的依赖目标的集合。以空格分隔。*

$^

* 所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。*

$+

* 这个变量很像"$^",也是所有依赖目标的集合。只是它不去除重复的依赖目标。*

$*

* 这个变量表示目标模式中"%"及其之前的部分。如果目标是"dir/a.foo.b",并且目标的模式是"a.%.b",那么,"\*&quot;的值就是&quot;dir/a.foo&quot;。这个变量对于构造有关联的文件名是比较有较。如果目标中没有模式的定义,那么&quot;*"也就不能被推导出,但是,如果目标文件的后缀是make所识别的,那么"\*&quot;就是除了后缀的那一部分。例如:如果目标是&quot;foo.c&quot;,因为&quot;.c&quot;是make所能识别的后缀名,所以,&quot;*"的值就是"foo"。这个特性是GNU make的,很有可能不兼容于其它版本的make,所以,你应该尽量避免使用"\*&quot;,除非是在隐含规则或是静态模式中。如果目标中的后缀是make所不能识别的,那么&quot;*"就是空值*

猜你喜欢

转载自blog.csdn.net/wangweijundeqq/article/details/79128280