当编译过程比较复杂的时候, 我们就可以使用 shell 脚本来简化这个过程, 同时版本升级, 重复构建的基础上 shell 脚本也能够重复利用, 下面直接开始看看 shell 脚本是如何使用的, 先从最简单的开始
hello shell
|
|
#!/bin/bash
第一行一般都是用来声明是用什么解释器来执行, 这里是 Bash , 然后 echo 是用来打印的, 一个简单的 hello shell 脚本就完成了, 然后通过 cmd 执行 ./1.sh 就可以了
变量
变量的设置规则
- 命名跟 Java 规范一样, 不能以数字开头等
- shell 中默认都是字符串类,如果需要用到其他类型,需要额外处理
- 变量用等号连接,不能有空格
变量的值如果有空格,需要用单引号或者双引号包括
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#!/bin/bash # 变量 str1="str11" str2=str1 # 赋值 str3=32 # 数字会被默认当作字符串处理 echo "str1 = ${str1}" echo "str2 = $str2" echo "str3 = $str3" # 输出环境变量 CMAKE_PATH echo "CMAKE_PATH = ${CMAKE_PATH}" # 指定一个命令的执行结果返回给变量 (pwd 是当前的工作目录) soPath=`pwd` echo "sopath = ${soPath}"
代码都比较简单, 语法也基本是固定格式, 运行后, 结果如下
获取参数
$n
来获取参数,$0 代表程序本身,$1-$9
代表第一个参数到第九个参数,十以上的参数要用大括号${10}
$*
代表的是命令中的所有参数,但是会把参数看成一个整体"$0,$1,$2,$3,$4...$n"
$@
代表命令中的所有参数,但是会把参数区分对待"$0","$1","$2"..."$n"
$#
代表参数中的个数1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
#!/bin/bash echo "$0=$0" echo "\$1=$1" echo "\$2="$2 echo "\$*="$* echo "\$@="$@ echo "\$#="$# #每次逻动(删除)第一个参数 shift echo "\$1=$1" echo "\$@="$@ echo "========================================" for i in $* do echo $i done echo "========================================" for i in $@ do echo $i done echo "========================================" for i in "$@" do echo $i done echo "========================================" for i in "$*" do echo $i done
还有一些,读取控制台上的输入赋值给变量
|
|
read 表示读取用户输入,然后将其存储出 name 中
|
|
这里和上面的区别就是, -sp 会将密码隐藏起来,并赋值给 pwd,执行结果如下
|
|
这里代表的意思是:
read
命令来读取用户输入-t 5
:设置一个超时时间为 5 秒。如果用户在 5 秒内没有输入内容,read 命令将会自动结束,并且 input 变量会为空-n 1
:指定读取一个字符的输入(即用户输入一个字符后 read 命令会立即结束,而不需要等待用户按下 Enter 键)-p "please input [y|n]: "
:在读取用户输入前,显示提示信息"please input [y|n]: "
预定义变量
指的是 bash 中已经定义好的,我们可以直接拿过来用
$?
:返回的是上一个执行命令的返回值,执行成功返回 0 ,执行失败返回非0$$
:获取当前角本的进程号$!
:获取最后一个后台执行的进程号
条件判断和数字使用
|
|
执行的结果如下
条件判断
1 2 3 4 |
1. [ str ] 测试字符串是否不为空 2. test -n str 测试字符串是否不为空或者是 [ -n str ] 3. test -z str 测试字符串是否为空或者是 [ -z str ] 4. [ str1 = str2 ] 是否相等 |
数字:
1 2 3 4 5 6 |
1. [ num1 -eq num2 ] 测试是否相等 2. [ num1 -ne num2 ] 不等 3. [ num1 -ge num2 ] >= 4. [ num1 -gt num2 ] > 5. [ num1 -le num2 ] <= 6. [ num1 -lt num2 ] < |
文件:
1 2 3 4 5 6 7 |
1. test -d file 目录 2. test -f file 普通文件 3. test -e file 存在 4. test -L file 链接 5. test -r file 可读 6. test -w file 可写 7. test -x file 可执行 |
接下来让我们编写一个根据用户输入编译类型来编译出对应的构建产物,这在实际的场景中也挺场景的
|
|
函数
在上面的例子中,提示的错误信息都是一样的, 这里可以用一个函数封装起来
|
|
这里将相同的逻辑部分, 都封装了在 error 中,其余的基本不变, 需要注意的是 error 内部 $1 接受到的参数区别,不是脚本传过来的参数,而是方法传递过来的参数, 运行后如下
循环和switch
|
|
执行后结果如下
输出日志到文件中
临时重定向
临时重定向是指一次性地将命令的输出重定向到某个文件或设备。常用的重定向符号有:
>
:将标准输出(stdout
,文件描述符1)重定向到一个文件,会覆盖文件的内容>>
:将标准输出重定向到一个文件,会追加到文件末尾2>
:将标准错误(stderr
,文件描述符2)重定向到一个文件,会覆盖文件内容2>>
:将标准错误重定向到一个文件,会追加到文件末尾1 2 3 4 5 6
# 临时重定向,> 代表写入到文件中,会被覆盖 echo "log error" > log.txt echo "log error 2" > log.txt # >> 代表的是追加 echo "log error 3" >> log.txt
执行结果后, 会生成 log.txt, 文件信息是这样的
永久重定向
永久重定向是使用 exec
命令改变当前 Shell 环境中文件描述符的默认目的地,直到 Shell 会话结束或被再次更改。永久重定向对所有后续命令生效,而不仅仅是单个命令
|
|
exec >log.txt
:- 将标准输出重定向到
log.txt
,这意味着之后所有的标准输出都会写入到log.txt
,并覆盖其中已有的内容。
- 将标准输出重定向到
exec >>log.txt
:- 将标准输出重定向追加到
log.txt
,这意味着之后所有的标准错误都会追加写入到log.txt
。
- 将标准输出重定向追加到
所以, 执行后,log.txt 文件是这样的
交叉编译
在上一篇文章中,我们编译了 libmath.so 库, 是在 Linux 中编译的,只能在 Linux 中使用,为了在 Android 平台上能够使用
那么就需要使用交叉编译了,这里我们刚刚已经学习了 shell 脚本编写,接下来使用 shell 脚本,来完成此次的交叉编译
要完成交叉编译,需要安装 NDK,并且配置环境变量,有这么以下几个步骤
下载 NDK
1 2 3 4 5
# 在 Linux 中的下载 NDK,在控制台中输入 wget -c https://dl.google.com/android/repository/android-ndk-r27-linux.zip?hl=zh-cn # 然后进行解压 unzip 文件名 # 解压后,放置到 lib/ndk 目录下
配置NDK环境变量
1 2 3 4 5 6 7 8 9 10 11 12
vim ~/.bashrc # 在文件末尾追加以下代码: export NDK_PATH=/lib/ndk/android-ndk-r27 export PATH=$PATH:$NDK_PATH # 然后更新一下环境变量 source ~/.bashrc # 再试试 ndk-build出现如下说明就安装好了 Android NDK: Could not find application project directory ! Android NDK: Please define the NDK_PROJECT_PATH variable to point to it. /usr/lib/ndk/android-ndk-r27/build/core/build-local.mk:151: *** Android NDK: Aborting . Stop.
然后使用上一篇文章中的源代码,CMakeLists.txt 有所改变,注意这里必须要添加最低版本声明,不然编译不过去,完整代码如下
|
|
然后编写脚本文件,其中最重要的是 NDK 相关的一些配置
|
|
完整内容如下
|
|
以往我们的编译,我们的编译文件都是和 CMakeLists 文件放在同一级文件夹的,会有些混乱,所以这里我们将构建文件都放在了 build 文件中,然后执行 ./build.sh 就可以编译出 Android 平台上能够使用的 so 库了
Android 中 导入第三方 so 库
这样我们就编译好了得到了 so 库,然后试试在 Android studio 上看看能不能正常使用,创建一个全新的 C++ Android 项目,导入 so 库,它的文件路径是这样的
大致做的步骤是引入头文件,导入 so 库,然后在 C 代码中,调用 so 库的 add 方法,运行后结果如下
可以发现,sum 计算正确,也正常输出了,可以证明我们的 so 库已经成功的在 Android 平台上运行了