[TOC]

Linux驱动开发

Linux指令非常多,全部记忆基本不可能,所以总结文章只选取重要的指令进行总结,其具体的指令上Linux指令查询网:https://www.linuxcool.com/,进一步查询使用

一、Linux驱动开发第一期:Ubuntu基础入门

1.Vmware虚拟机安装

参考教程:虚拟机VMware最详细下载与安装教程

2.Vmware内Ubuntu功能介绍

2.1 启动栏介绍

启动栏介绍如图所示

20210605234417

2.2 Ubuntu连接USB设备

图形界面下两种连接方式

  1. 拔插选择设备连接

    20210517210556

  2. Vmware右下角进行切换

    20210517210634

2.3 Ubuntu终端下Shell操作

Ubuntu终端指命令行操作界面,打开终端后我们通过输入shell指令来进行操作,下面我们讲解一下常用Shell指令操作(所有Linux版本基本通用)

2.3.1 Shell 基本操作

Shell 命令的格式 如下:

1
command -options [argument]

command: Shell 命令名称。

options:选项,同一种命令可能有不同的选项,不同的选项其实现的功能不同。

argument:Shell 命令是可以带参数的,也可以不带参数运行。

以ls为例,分别执行如下指令

1
2
3
ls 
ls -l
ls /usr

执行结果如下

20210605222626

“ls”命令用来打印出当前目录下的所有文件和文件夹

“ls -l”同样是 打印出当前目录下的所有文件和文件夹,但是此命令会列出所有文件和文件夹的详细信息,比 如文件大小、拥有者、创建日期等等。

“ls /usr”是用来打印出目录“/usr”下的所有 文件和文件夹。

Shell 命令是支持自动补全功能的,要输入命令的前面一部分字 母,然后按下 TAB 键自动补全,如果有多个指令,可以选择全部列出

20210605222926

以上为基本操作

2.3.2 Shell 常用指令

Shell 命令是所有的 Linux系统发行版所通用的,指令在所有版本linux下都通用

  • 目录信息查看命令 ls

文件浏览是最基本的操作了,Shell 下文件浏览命令为 ls,格式如下

1
ls [选项] [路径]

主要参数有:

-a 显示所有的文件以及子目录,包括以“.”开头的隐藏文件。

-l 显示文件的详细信息,比如文件的形态、权限、所有者、大小等信息。

-t 将文件按照创建时间排序列出。

-A 和-a 一样,但是不列出“.”(当前目录)和“..”(父目录)。

-R 递归列出所有文件,包括子目录中的文件。

注意:Shell 命令里面的参数是可以组合在一起用的,比如组合“-al”就是显示所有文件的详细信 息,包括以“.”开头的隐藏文件

20210605231021

  • 目录切换命令 cd

中切换到其它的目录,使用的命令是 cd,命令格式如下

1
cd [路径]

使用范例

1
2
3
4
cd / 		//进入到根目录“/”下,Linux 系统的根目录为“/”,
cd /usr //进入到目录“/usr”里面。
cd .. //进入到上一级目录。
cd ~ //切换到当前用户主目录
  • 当前路径显示命令pwd

pwd 命令用来显示当前工作目录的绝对路径,不需要任何的参数

20210605231329

  • 系统信息查看命令 uname

查看当前系统信息

1
uname [选项]

可选的选项参数如下:

-r 列出当前系统的具体内核版本号。

-s 列出系统内核名称

-o 列出系统信息

20210605231511

  • 清屏命令 clear

clear 命令用于清除终端上的所有内容,只留下一行提示符(实际上未清除,只是推到最上面了)

  • 切换用户执行身份命令 sudo

sudo 命令可以 使我们暂时将身份切换到 root 用户。当使用 sudo 命令的时候是需要输入密码的,这里要注意输 入密码的时候是没有任何提示的!

1
sudo [选项] [命令]

选项主要参数如下:

-h 显示帮助信息。

-l 列出当前用户可执行与不可执行的命令

-p 改变询问密码的提示符。

  • 添加用户命令 adduser

此命令需要 root 身份去运行。命令 格式如下:

1
adduser [参数] [用户名]

主要参数有:

-system 添加一个系统用户

-home DIR DIR 表示用户的主目录路径

-uid ID ID 表示用户的 uid

-ingroup GRP 表示用户所属的组名

  • 删除用户命令 deluser

删除用户使用命令“deluser”,命 令参数如下:

1
deluser [参数] [用户名]

主要参数有:

-system 当用户是一个系统用户的时候才能删除

-remove-home 删除用户的主目录

-remove-all-files 删除与用户有关的所有文件

-backup 备份用户信息

  • 切换用户命令 su

命令“su”可以 直接将当前用户切换为 root 用户,切换到 root 用户以后就可以尽情的进行任何操作了!因为你 已经获得了系统最高权限,在 root 用户下,所有的命令都可以无障碍执行,不需要在前面加上 “sudo”,“su”命令格式如下:

1
su [选项] [用户名]

常用选项参数如下:

-c –command 执行指定的命令,执行完毕以后恢复原用户身份。

-login 改变用户身份,同时改变工作目录和 PATH 环境变量。

-m 改变用户身份的时候不改变环境变量

-h 显示帮助信息

20210605232447

要切换回原来的用户,使用命令“sudo su 用户名”即可

20210605232541

  • 显示文件内容命令 cat
1
cat [选项] [文件]

主要参数如下:

-n 由 1 开始对所有输出的行进行编号。

-b 和-n 类似,但是不对空白行编号。

-s 当遇到连续两个行以上空白行的话就合并为一个行空白行。

20210605232819

  • 显示和配置网络属性命令 ifconfig

ifconfig 是一个跟网络属性配置和显示密切相关的命令,通过此命令我们可以查看当前网络 属性,也可以通过此命令配置网络属性,比如设置网络 IP 地址等等

1
ifconfig interface options | address

主要参数如下:

interface 网络接口名称,比如 eth0 等。

up 开启网络设备。

down 关闭网络设备。

add IP 地址,设置网络 IP 地址。

netmask add 子网掩码。

  • 系统帮助命令 man

Ubuntu 提供了一个命令来帮助用户完成这个功能,那 就是“man”命令,通过“man”命令可以查看其它命令的语法格式、主要功能、主要参数说明等, “man”命令格式如下:

1
man [命令名]

例如,查询ls

1
man ls

输入指令后会跳出来一个资料文档

20210605233305

  • 系统重启命令 reboot

直接输入命令“reboot”然后点击回车键即可

  • 系统关机命令 poweroff

输入 命令“poweroff”然后按下回车键即可关闭 Ubuntu 系统

2.4 Ubuntu软件安装

  • 通过APP Store安装

    使用apt工具安装软件,需要sudo,也就是root权限。

    20210518122248

  • 使用APT工具安装

    使用apt包管理工具,apt可以自动下载,配置,安装。

    指令:sudo apt-get install + 软件

    安装git如下

    20210518122559

  • deb软件包安装

    下载.deb软件包

    使用dpkg命令安装deb软件包,命令如下:

    1
    sudo dpkg -i xxxx.deb

    在windows下,我们安装的是.exe文件,在Ubuntu就有一个.deb

    安装网易云音乐,

  • 自己下载程序源码编译安装

    Make

    Make install

  • 其他 安装方法

    QT扩展名是.run

  • 安装的软件启动图标位置

    以下路径中 usr/share/applications

    20210518122923

3.Ubuntu文件系统结构

本小结学习目标:了解”/“根目录下各个文件包含内容的含义

3.1 根目录

Linux下“/”就是根目录!所有的目录都是由根目录衍生出来的

3.2 其他文件目录(后期移植需要了解)

20210518125354

目录 功能
/bin 存放二进制可执行文件,这些命令在单用户模式下也能够使用,可以被root和一般的账号使用。
/boot Ubuntu内核和启动文件,比如vmlinuz-xxx。gurb引导装载程序。
/dev 设备驱动文件
/etc 存放一些系统配置文件,比如用户账号和密码文件,各种服务的起始地址。
/home 系统默认的用户主文件夹,一般创建用户账户的时候,默认的用户主文件夹都会放到此目录下。
/lib 存放库文件
/media 此目录下放置可插拔设备,比如SD卡,或者U盘就是挂载到这个目录中。
/mnt 用户可使用的挂载点,如果要挂载一些额外的设备,那么就可以挂载到此处。
/opt 可选的文件和程序存放目录,给第三方软件放置的目录。
/root root用户目录,也就是系统管理员目录。
/sbin 和/bin类似,也是存放一些二进制可执行文件。sbin下面的一般是系统开机过程中所需要的命令。
/srv 服务相关目录。比如网络服务。
/sys 记录内核信息,虚拟文件系统。
/tmp 临时目录
/var 存放一些变化的文件,比如日志文件
/usr usr不是user的缩写,而是UNIX Software Resource的缩写,存放于系统用户有关的文件,会占用很大的存储空间!
/proc 虚拟文件系统,数据放置到内存中,存放系统运行信息

3.3 绝对路径与相对路径

绝对路径:从根目录“/”算起的路径。

相对路径:相对于目前路径的文件名写法,比如./home/zzk。不是以“/”开头的就行。

“.” 代表当前路径,也可以 用“./”表示

“..” 代表上一层目录,也可以用“../”表示

“*” 为通配符,表示全部

4.Ubuntu磁盘管理

本小节目标了解Ubuntu下磁盘的管理以及

4.1 Ubuntu磁盘设备文件

/dev/sd*文件,此类文件是磁盘设备文件(并不能直接访问磁盘,必须要将磁盘挂载到某一个目录下才可以访问)

指令:定位到磁盘设备目录,显示所有sd开头设备

1
cd \devls sd*

20210530214939

/dev/sdb 和 /dev/sdb1 是U盘的设备文件。

/dev/sdb表示U盘,/dev/sdb1表示U盘的第一个分区(当前U盘只有一个分区)

4.2 磁盘和目录的容量查询命令

​ df:列出文件系统的整体磁盘使用量。主要查看个整个文件系统的使用量,

​ du:评估文件系统的磁盘使用量,主要查看单个文件的大小。

20210530215119

两个指令都有各自的进一步衍生指令,指令太多,需要使用时查询即可

4.3 磁盘挂载与卸载,分区和格式化

  1. 磁盘的挂载和卸载

    磁盘无法直接进入,需要进行挂载操作后才能进入,使用完毕再卸载

    mount(挂载)和umount(卸载)命令

1
1. mount /dev/sdb1 + 挂载点 #挂载到指定挂载点2. umount /dev/sdb1	#卸载

挂载到新建的usb文件夹,并进入查看文件

20210530220933

卸载(卸载前先退出usb,不然无法退出)

20210530221056

  1. 磁盘分区

    fdisk命令

1
sudo fdisk /dev/sdb#输入对应指令#执行

创建一个分区

1
sudo fdisk /dev/sdbnp2048 #开始扇区2097152 #(1024*1024*1024+2048)扇区结束长度

20210530224310

1
sudo fdisk -l /dev/sdb #查询扇区信息

20210530224505

已经创建1G分区

  1. 磁盘格式化

​ 磁盘分区创建好以后就可以格式化磁盘,使用命令mkfs。如:格式化sdb1分区

1
mkfs -t vfat /dev/sd1

20210530224858

5.Ubuntu压缩与解压缩

5.1 Linux下常用的压缩格式

Linux下常用的压缩扩展名有:.tar、.tar.bz2、.tar.gz与windows下的常用压缩包.rar、.zip有较大区别

5.2 Window和Linux压缩工具

5.2.1 Windows下7ZIP软件的安装

因为Linux下很多文件是.bz2,.gz结尾的压缩文件,因此需要在windows下安装7ZIP软件(强大的压缩软件):链接

20210531100225

5.2.2 Linux下压缩工具

输入输入:工具名称–help 可查询 对应工具有关指令

  • gzip压缩工具

.gzip工具负责压缩和解压缩.gz格式的压缩包。

1
gzip xxx          #压缩gzip -d xxx.gz    #解压缩

单个文件压缩与解压缩

20210531101952

gzip对文件夹进行压缩

1
gzip -r xxx       #对文件夹进行压缩gzip -rd xxx.gz   #对文件夹进行解压缩

对test文件夹压缩与解压缩

20210531102459

gzip虽然可以对文件夹进行压缩,但是并不能提供打包的服务,只是对文件夹中的所有文件进行了单独的压缩,例如上图中test内文件单独被压缩为.gz文件

  • bzip2压缩工具

输入输入bzip2–help可查询bzip2有关指令

和gzip类似,只是bzip2工具负责压缩和解压缩.bz2格式的压缩包。

1
bzip2 -z xxx         #压缩bzip2 -d xxx.gz      #解压缩

20210531104937

bzip只能对单个文件进行压缩和解压操作

  • tar打包工具
tar常用工具参数: 参数功能
-f 使用归档文件或 ARCHIVE 设备
-c 创建新归档,创建压缩文件
-x 从图档中解出文件,解压缩
-j 使用bzip2压缩格式。
-z 使用gzip压缩格式
-v 显示打包过程、结果

tar工具提供打包服务,就是将多个文件打包(参数顺序有要求,注意顺序),比如

1
tar -vcf test.tar test    #将test打包成test.tartar -vxf test.tar       #解包

打包test文件:

20210601204602

解压test.tar文件:

20210601204815

  • tar压缩与解压缩(很常用)

    上面的tar命令只提供了打包和解包的功能,tar在提供打包和解包的同时使用gzip/bzip2进行压缩,实现类似windwos下winRAR软件的命令。

  1. 对.tar.bz2进行压缩和解压缩
1
tar -vxjf xxx.tar.bz2    #解压缩tar -vcjf xxx.tar.bz2 xxx  #压缩
  1. 对.tar.gz进行压缩和解压缩
1
tar -vxzf xxx.tar.gz    #解压缩tar -vczf xxx.tar.gz xxx  #压缩 

以gzip格式压缩test文件

20210601205020

解压缩同理(注意解压后位置,默认为当前文件夹,不要出现重名文件夹)

5.3 其他格式的压缩和解压缩

5.3.1 .rar格式

输入rar可查询rar有关指令

需要先安装rar:sudo apt-get install rar

1
rar x xxx.rar      #解压缩rar a xxx.rar xxx  #压缩

解压缩测试

20210601210906

5.3.2 .zip格式

输入zip可查询zip有关指令

zip格式压缩使用“zip“命令:

1
zip -rv xxx.zip xxx 

zip格式解压缩使用“unzip”命令:

1
unzip -v xxx.zip

压缩与解压缩

20210601211932

6.Ubuntu用户与用户组

Linux是多用户系统,一个系统不仅仅只针对一个用户,而是多个用户,所以掌握用户与用户组的管理与操作很有必要;

6.1 Linux用户

Linux是一个多用户操作系统,不同的用户拥有不同的权限,可以查看和操作不同的文件,Ubuntu有三种用户:

● 初次创建的用户,此可以完成比普通更多功能。 初次创建的用户,此可以完成比普通更多功能。
● root用户,系统管理员中的BOSS拥有至高无上权利。
● 普通用户,安装完操作系统以后被创建的。 普通用户,安装完操作系统以后被创建的。

Linux用户记录在/etc/passwd这个文件内,操作系统通过UID来识别是哪个用户,使用如下指令打开,用户显示方式:名称+UID+用户组GID

1
sudo vi /etc/passwd #VI打开,退出方式为按下esc后按下shift + q

20210601213107

Linux用户密码记录在/etc/shadow这个文件内,加密过

1
sudo vi /etc/shadow #VI打开,退出方式为按下esc后按下shift + q

20210601213330

每个用户都有一个ID,叫做UID。

6.2 Linux用户组

为了方便管理,将用户进行分组。这样就可以设置非本组人员不能访问某些文件。每个用户可以属于多个不同的组。

  • 用户与用户组区别:

用户:家里有你、弟弟、妹妹个人,每个人都有自己的房间,你们三个人都是用户,你们都不能随便的乱翻别人的房间。

用户组:你们三个都是一个家庭的,也就是属于同一个用户组,你们三个可以共用厨房,书房等空间。

  • 用户和用户组作用

用户和用户组的存在就是为了控制文件的访问权限的。

注意:每个用户组都有一个ID,叫做GID,用户组信息存储在/etc/group文件中

6.3 创建用户和用户组

  • 图形化界面创建

​ 要使用图形化界面创建用户和用户组的话就需要安装gnome-system-tools这个工具:

1
sudo apt-get install gnome-system-tools

若出现以下BUG:

1
E: 无法获得锁 /var/lib/apt/lists/lock - open (11: 资源暂时不可用)E: 无法对目录 /var/lib/apt/lists/ 加锁E: 无法获得锁 /var/lib/dpkg/lock - open (11: 资源暂时不可用)E: 无法锁定管理目录(/var/lib/dpkg/),是否有其他进程正占用它?

解决方法:

1
sudo rm /var/cache/apt/archives/lock  sudo rm /var/lib/dpkg/lock  

然后关掉终端重新打开,再次运行安装指令,安装成功后直接打开安装程序-用户和用户组就能创建和删除用户组了:

20210602094750

  • 命令创建用户和用户组

添加用户:adduser命令**(备注:下面的添加和删除都需要root权限)**

1
sudo adduser 用户名

addusr

用户查询:finger命令

1
finger 用户名

finger

修改用户密码:passwd命令,passwd 用户名

删除用户:deluser命令

1
sudo deluser 用户名

deluser

添加用户组:addgroup命令

1
sudo addgroup 用户组名

addgroup

显示组内用户名:groups命令,groups 用户组名

删除用户组:delgroup命令

1
sudo delgroup 用户组名

delgroup

7. 文件权限管理

7.1 Ubuntu/Linux文件权限

文件权限是指不同的用户或用户组对某个文件拥有的权限,文件的权限分为三种:

命令字 含义
r
w
x 可执行

文件权限的描述形式如下:

20210602110454

-rw-r–r–**就是文件权限,第一位表示文件类型(例如c开头为字符设备,d开头为块设备),剩下的每三位表示一组权限。分别对应拥有者权限拥有者所在组权限其他用户权限**。

可以使用二进制表示文件权限

权限 二进制数字 八进制数字
000 0
–x 001 1
-w- 010 2
-wx 011 3
r– 100 4
r-x 101 5
rw- 110 6
rwx 111 7

1.c的权限就是r=6,w=4,x=4

1.c文件信息:- rw- r– r–,表示:1.c所属用户拥有读写权限无可执行权限,组内其他用户拥有只读权限,其他用户仅有可读权限。

7.2 Ubuntu/Linux文件权限修改

  1. 修改文件权限命令

​ chmod命令

1
chmod [权限值] [文件名 /目录名] [参数]

常用参数

参数 功能
-c 效果类似“ 效果类似“ -v”参数,但仅回显更改的部分
-f 不显示错误信息
-r 递归处理,即指定目录下所有文件以及子文件一起处理
-v 显示指令执行过程

改变hollow的可执行权限

20210604093331

  1. 修改文件所属用户

​ chown命令

1
chown [选项]... [所有者][:[组]] 文件...

eg:

1
chown root /u		将 /u的所属用户更改为"root"。

20210604094937

8.Ubuntu连接文件(Linux通用)

8.1 连接文件概念

Linux有两种连接文件:符号连接(软连接)和硬链接

  • 符号链接(软连接):类似Windows下的快捷方式。

  • 硬链接:通过文件系统的inode连接来产生新文件名,而不是产生新文件。

inode:记录文件属性,一个文件一个inode,inode相当于文件ID,查找文件的时候要先找到inode,然后才能读出文件的内容。

8.2 ln命令

ln命令用于创建连接文件:

1
ln [选项] 源文件 目标文件

选项:

​ -s 创建符号链接(软连接)

​ -f 强制创建连接文件,如果目标存在,那么先删除掉目标文件,然后再建立连接文件。

8.3 硬连接

硬链接是多个文件都指向同一个inode,硬链接知识点:

​ ① 具有相同inode的多个文件互为硬链接文件,创建硬链接相当于文件实体多了入口。

​ ② 对于硬链接文件,只有删除了源文件以及对应的所有硬连接文件,文件实体才会被删除。

​ ③ 根据硬链接文件的特点,我们可以通过给文件创建硬连接的方式来防止文件误删除。

​ ④ 不论修改源文件还是连接文件,另一个文件的数据都会被改变。

​ ⑤ 硬连接不能跨文件系统

​ ⑥ 硬连接不能连接到目录。

因为以上这些限制,硬链接其实不常用。

显示硬链接详细信息就是显示具体文件的信息

20210605110241

8.4 符号连接(软连接)

符号连接类似Windows下的快捷方式,符号链接也叫做软连接,软连接要用的多。符号连接相当于创建了一个独立的文件,这个文件会让数据读取指向它连接的哪个文件的文件名。软连接的特点:

​ ① 可以连接到目录。

​ ② 可以跨文件系统

​ ③ 删除源文件以后,软连接文件也就“打不开了”。

​ ④ 符号连接文件通过->来指示具体的连接文件。

​ ⑤ 符号连接要使用绝对路径,否则连接出问题。

显示软连接详细信息就是显示软链接文件的详细信息,下图中显示的文件信息就是l(链接文件),所有用户都有操作权限!

20210605110145

9.Vim编辑器常用操作

9.1 vim编辑器

Linux系统命令行的操作方式与图形化的操作方式不一样,他内部自带了vi编辑器,但是vi编辑器太难用,所以安装vim编辑器,安装命令:

1
sudo apt-get install vim

9.2 vim编辑器三种工作模式

​ vim xxx 使用vim编辑器打开文件。

  1. 一般模式(指令模式):默认模式,用vim打开一个软件以后自动进入到此模式。

  2. 编辑模式:一般模式中无法编辑文件,要编辑文件就要进入编辑模式,按下“i、I、a、A、o、O、s、r”等就会进入到编辑模式。一般按下“a”进入编辑模式。按下ESC键可退出编辑模式。

  3. 命令行模式(底行模式):先进入到一般模式,然后输入’:’、’/‘、’?’这三个中的任意一个就可以进入到命令行模式。

  • 一般模式:

20210605112025

常用指令:

命令 作用
x 删除光标所在处字符 nx 删除光标所在处后n个字符
dd 删除光标所在行,ndd删除n行
dG 删除光标所在行到末尾的内容
D 删除从光标所在处到行尾
yy、Y 复制当前行
nyy、nY 复制当前行以下n行
dd 剪切当前行
ndd 剪切当前行以下n行
yy、Y 复制当前行
nyy、nY 复制当前行以下n行
dd 剪切当前行
ndd 剪切当前行以下n行
p、P 粘贴在当前光标所在行下 或行上
r 取代光标所在处字符
R(shift + r) 从光标所在处开始替换字符,按Esc结束
u undo,取消上一步操作
ctrl+r redo,返回到undo之前
  • 编辑模式:

20210605112048

常用指令:

命令 作用
a 在光标后附加文本
A(shift + a) 在本行行末附加文本 行尾
i 在光标前插入文本
I(shift+i) 在本行开始插入文本 行首
o 在光标下插入新行
O(shift+o) 在光标上插入新行
  • 底行模式:

20210605112106

常用指令:

命令 作用
:w 保存修改
:w new_filename 另存为指定文件
:w >> a.txt 内容追加到a.txt文件中 文件需存在
:wq 保存修改并退出
shift+zz(ZZ) 快捷键,保存修改并退出
:q! 不保存修改退出
:wq! 保存修改并退出(文件所有者可忽略文件的只读属性)

10.Linux下C编程入门

10.1 编写C程序

Linux下的编写C代码包括两部分:代码编写和编译,在 Windows 下可以使用 Visual Studio 直接完成这两部分,但在 Linux 下这两部分是分开的,我们先进行代码编写,编写完成以后再使用 GCC 编译器进行编译,其中代码编写工具很多,比如 VIM 编辑器、Emacs 编辑器、VScode 编辑器等等,此处我使用VIM编辑器来编写程序,把 Linux 下 的 C 编程完整的走一遍。

10.1、设置vim编辑器

用vim打开文件 /etc/vim/vimrc

1
sudo vim /etc/vim/vimrc

设置vim编辑器,一个TAB=4个字节,即在最后面输入如下指令

1
set ts=4

设置vim编译器,显示行号,最后面加入下面一行代码

1
set nu

10.2、编写C程序

新建一个1.c文件(不新建C文件也可以,vim会自动创建)

1
touch 1.c

20210605115614

vim打开C文件

1
vim 1.c

根据上一小节vim操作输入如下c程序

1
1 #include <stdio.h>  2   3 int main(void)  4 {  5     printf("Hello World\r\n");  6     return 0;  7 }

20210605115942

保存退出

10.2 编译C程序

使用gcc编译器编译C程序。

1
gcc -o hello 1.c

执行程序

20210605120211

补充GCC编译器介绍

1
gcc [选项] [文件名字] [源文件]

主要选项如下:

-c:只编译不链接为可执行文件,编译器将输入的.c 文件编译为.o 的目标文件。

-o:<输出文件名>用来指定编译结束以后的输出文件名,如果不使用这个选项的话 GCC 默 认编译出来的可执行文件名字为 a.out。

-g:添加调试信息,如果要使用调试工具(如 GDB)的话就必须加入此选项,此选项指示编 译的时候生成调试所需的符号信息。

-O:对程序进行优化编译,如果使用此选项的话整个源代码在编译、链接的的时候都会进 行优化,这样产生的可执行文件执行效率就高。

-O2:比-O 更幅度更大的优化,生成的可执行效率更高,但是整个编译过程会很慢。

注意gcc编译时,若C语言语法不对会报错显示!

11.make工具和Makefile文件

11.1 makehe1makefile介绍

源码文件比较多的时候就不适合通过直接输入gcc命令来编译,这时候就需要一个自动化的编译工具.

make:一般说GNU Make,是一个软件,用于将源代码文件编译为可执行的二进制文件,make工具主要用于完成自动化编译。make工具编译的时候需要Makefile文件提供编译文件

Makefile:make工具所使用的文件,Makefile指明了编译规则

11.2 编写C程序测试例程

使用VIM编写多个小型的含有多个.c文件的C程序。

编写主函数main.c文件

1
1 #include <stdio.h>2 #include "input.h"3 #include "calcu.h"45 int main(int argc, char *argv[])6 {7 int a, b, num;89 input_int(&a, &b);10 num = calcu(a, b);11 printf("%d + %d = %d\r\n", a, b, num);12 }

输入函数input.c

1
1 #include <stdio.h>2 #include "input.h"34 void input_int(int *a, int *b)5 {6 printf("input two num:");7 scanf("%d %d", a, b);8 printf("\r\n");9 }

input的头文件input.h

1
1 #ifndef _INPUT_H2 #define _INPUT_H34 void input_int(int *a, int *b);5 #endif

计算函数calcu.c

1
1 #include "calcu.h"2 3 int calcu(int a, int b)4 {5 return (a + b);6 }

calcu的头文件calcu.h

1
1 #ifndef _CALCU_H2 #define _CALCU_H34 int calcu(int a, int b);5 #endif

编写文件夹如下:

20210605161504

11.3 使用GCC直接编译

使用GCC直接编译的过程如下

第一次编译使用

1
gcc [所有文件] -o [目标文件]

20210605161827

之后哪个文件更新了单独编译那个文件后再链接

1
gcc [更新文件] -c gcc [所有文件.o] -o [目标文件]

使用如下,先生成所有文件的.o文件,更新直接更新对应.o文件就行,最后再通过gcc的-o来链接所有编译后文件。

20210605162235

gcc的编译方法复杂,尤其在文件数量很多时十分低效,所以引入Makefile来自动化编译,简化流程!

11.3 使用make工具和Makefile文件进行编译

以上面的文件为例子,进行makefile编译!

第一次使用VIM编辑的话,首先修改文件/etc/vim/vimrc,使 TAB 键不用空格形成

1
set noexpandtab

Vim新建一个Makefile文件(严格按照大小写来)

编写代码如下:(2、4、6、8、11、12处tab进位,必须!)

1
1 main: main.o input.o calcu.o  2     gcc -o main main.o input.o calcu.o  3 main.o: main.c  4     gcc -c main.c  5 input.o: input.c  6     gcc -c input.c  7 calcu.o: calcu.c  8     gcc -c calcu.c  9  10 clean: 11     rm *.o 12     rm main

保存后,我们在命令行输入make就会默认执行main的程序

20210605164053

使用make clean则会调用清除程序

20210605164134

此处makefile的功能如下

  1. 如果工程没有编译过,那么工程中的所有.c 文件都要被编译并且链接成可执行程序。

  2. 如果工程中只有个别 C 文件被修改了,那么只编译这些被修改的 C 文件即可。

  3. 如果工程的头文件被修改了,那么我们需要编译所有引用这个头文件的 C 文件,并且 链接成可执行文件。

11.4 Makefile语法入门

  • 规则格式

Makefile由一系列的规则组成的,规则格式如下

1
[目标]: [依赖]	命令1	命令2	命令3	...

比如上一小结的规则

1
main : main.o input.o calcu.o	gcc -o main main.o input.o calcu.o

这条规则的目标是 main,main.o、input.o 和 calcu.o 是生成 main 的依赖文件,如果要更新 目标 main,就必须先更新它的所有依赖文件,如果依赖文件中的任何一个有更新,那么目标也 必须更新,(更新就是执行一遍规则中的命令列表)

命令列表中的每条命令必须以 TAB键开始,不能使用空格;make 命令会为 Makefile 中的每个以 TAB开始的命令创建一个 Shell进程去执行

规则间的依赖关系如下:以上一节代码为例子

1
main: main.o input.o calcu.o	gcc -o main main.o input.o calcu.omain.o: main.c	gcc -c main.cinput.o: input.c	gcc -c input.ccalcu.o: calcu.c	gcc -c calcu.c	clean:	rm *.o	rm main

代码中有5条规则,最上面为默认规则,执行时会检查他的依赖文件是不是最新的,如果不是最新的就会向下搜索规则来生成最新的依赖文件,如果我们要直接执行对应规则,命令行输入如下指令就行,第五条规则因为没用依赖文件,默认认为依赖文件是最新的直接执行命令;

1
make [规则目标]

具体执行流程总结如下:

  1. make 命令会在当前目录下查找以 Makefile(makefile 其实也可以)命名的文件。
  2. 当找到 Makefile 文件以后就会按照 Makefile 中定义的规则去编译生成最终的目标文件。
  3. 当发现目标文件不存在,或者目标所依赖的文件比目标文件新(也就是最后修改时间比目标文件晚)的话就会执行后面的命令来更新目标。

注意:除了第一条规则顺序有意义,其他规则顺序随意!

  • Makefile变量

Makefile 加入了变量支持,不像 C 语言中的变量有 int、char 等各种类型,Makefile 中的变量都是字符串!类似 C 语言中的宏。使用变量将上面的代码修改,例如

1
#Makefile 变量的使用objects = main.o input.o calcu.omain: $(objects)	gcc -o main $(objects)

先简单的补充一下上面用到的语法

’#‘ 为makfile语法中注释

’objects‘ 为变量名称

’$(变量名称)‘ 为引用变量

‘=’ 为对变量进行赋值

  • Makefile赋值符
  1. 赋值符“=”

    变量赋值,其真实值取决于它所引用的变量的最后一次有效值

    1
    name = jkcurname = $(name)name = jeck666print:	@echo curname: $(curname)

    执行后结果,显示最后一次赋值

    20210605202001

  2. 赋值符“:=”

    ‘:=’ 与 ‘=’ 号的区别在于,前者不会使用后面定义的变量,只能使用前面已经定义好的,这就是“=”和“:=”两个的区别,我们将代码换成如下代码进行测试

    1
    name = jkcurname := $(name)name = jeck666print:	@echo curname: $(curname)

    可以看到值取的是赋值时的值,不是最后定义的变量值

    20210605202705

  3. 赋值符“?=”
    “?=”使用时如果变量前面没有被赋值,那么此变量就是“?=”后面的值, 如果前面已经赋过值了,那么就使用前面赋的值

  4. 变量追加“+=”
    有时候我们需要给前面已经定义好的变量添加一些字符串进 去,此时就要使用到符号“+=”,比如如下所示代码

    1
    objects = jeckobjects += 666

    一开始变量objects为jeck,追加后变为jeck666

  • Makefile 模式规则

模式规则中,至少在规则的目标定定义中要包涵“%”,否则就是一般规则,目标中的“%”表示对文件名的配,“%”表示长度任意的非空字符串,比如“%.c”就是所有的以.c 结尾的 文件,类似与通配符,a.%.c 就表示以 a.开头,以.c结束的所有文件

通过模式规则我们就可以使用一条规则来将所有的.c 文件编译为对应的.o 文件

使用方法如下:

1
%.o : %.c	命令

上一节代码可修改如下:

1
main: main.o input.o calcu.o	gcc -o main main.o input.o calcu.o%.o: %.c	命令	clean:	rm *.o	rm main

此处修了了之后命令也需要修改,因此引入自动化变量

  • Makefile自动化变量
自动化变量 变量
$@ 规则中的目标集合,在模式规则中,如果有多个目标的话,“$@”表示匹配模 式中定义的目标集合。
$% 当目标是函数库的时候表示规则中的目标成员名,如果目标不是函数库文件, 那么其值为空。
$< 依赖文件集合中的第一个文件,如果依赖文件是以模式(即“%”)定义的,那么 “$<”就是符合模式的一系列的文件集合。
$? 所有比目标新的依赖目标集合,以空格分开。
$^ 所有依赖文件的集合,使用空格分开,如果在依赖文件中有多个重复的文件, “$^”会去除重复的依赖文件,值保留一份。
$+ 和“$^”类似,但是当依赖文件存在重复的话不会去除重复的依赖文件。
$* 这个变量表示目标模式中”%”及其之前的部分,如果目标是 test/a.test.c,目标模 式为 a.%.c,那么“$*”就是 test/a.test。

通过自动化变量,我们最终改版的代码如下:

1
main: main.o input.o calcu.o	gcc -o main main.o input.o calcu.o%.o: %.c	gcc -c $<	clean:	rm *.o	rm main
  • Makefile 伪目标

Makefile 有一种特殊的目标——伪目标,一般的目标名都是要生成的文件,而伪目标不代 表真正的目标名,使用伪目标主要是为了避免 Makefile 中定义的执行命令的目标和工作目录下的实际文件出 现名字冲突,例如上面的代码中clean规则,如果文件夹内真的存在clean命名的文件,那么clean规则就无法执行!!!因此,可以将 clean 声明为伪 目标,声明方式如下:

1
.PHONY : clean

上面实例代码进一步修改

1
main: main.o input.o calcu.o	gcc -o main main.o input.o calcu.o%.o: %.c	gcc -c $<.PHONY : cleanclean:	rm *.o	rm main

声明 clean 为伪目标以后不管当前目录下是否存在名 为“clean”的文件,输入“make clean”的话规则后面的 rm 命令都会执行

  • Makefile条件判断

makefile支持条件判断语法,具体有两种语法:

1
<条件关键字>	<条件为真时执行的语句>endif
1
<条件关键字>	<条件为真时执行的语句>else	<条件为假时执行的语句>endif

条件关键字有 4 个:ifeq、ifneq、ifdef 和 ifndef,这四个关键字其实分为两对、ifeq 与 ifneq、ifdef 与 ifndef,ifeq 用来判断是否相等,ifneq 判断是否不 相等,用法如下:

1
ifeq (<参数 1>, <参数 2>)ifeq ‘<参数 1 >’,‘ <参数 2>’ifeq “<参数 1>”, “<参数 2>”ifeq “<参数 1>”, ‘<参数 2>’ifeq ‘<参数 1>’, “<参数 2>”

ifdef 和 ifndef 的用法如下:

1
ifdef <变量名>

如果“变量名”的值非空,那么表示表达式为真,否则表达式为假。“变量名”同样可以是 一个函数的返回值。ifndef 用法类似,但是含义用户 ifdef 相反。

  • Makefile函数

Makefile 中的函数是已经定义好的,我们直接使用, 不支持我们自定义函数。make 所支持的函数不多,但是绝对够我们使用了,函数的用法如下:

1
$(函数名 参数集合)

或者

1
${函数名 参数集合}

常用函数:

  1. 函数 subst

函数 subst 用来完成字符串替换,调用形式如下:

1
$(subst <from>,<to>,<text>)

将字符串中的内容替换为,函数返回被替换以后的字符串

  1. 函数 patsubst

函数 patsubst 用来完成模式字符串替换,调用形式如下:

1
$(patsubst <pattern>,<replacement>,<text>)

此函数查找字符串中的单词是否符合模式,如果匹配就用来 替换掉,可以使用通配符“%”,表示任意长度的字符串,函数返回值就是替换后的字符串。如果中也包涵“%”,那么中的“%”将是中的那个 “%”所代表的字符串

例如:

1
$(patsubst %.c,%.o,a.c b.c c.c)
  1. 函数 dir

函数 dir 用来获取目录,使用方法如下:

1
$(dir <names…>)

此函数用来从文件名序列中提取出目录部分,返回值是文件名序列的目录部分,/src/a.c的目录部分为/src

  1. 函数 notdir

此函数用与从文件名序列中提取出文件名非目录部分,也就是提取文件名

1
$(notdir <names…>)
  1. 函数 foreach

foreach 函数用来完成循环

1
$(foreach <var>,<list>,<text>)

此函数的意思就是把参数中的单词逐一取出来放到参数中,然后再执行所 包含的表达式。每次都会返回一个字符串,循环的过程中,中所包含的每个字符串会以空格隔开,最后当整个循环结束时,所返回的每个字符串所组成的整个字符串将会是 函数 foreach 函数的返回值。

  1. 函数 wildcard

通配符“%”只能用在规则中,只有在规则中它才会展开,如果在变量定义和函数使用时, 通配符不会自动展开,这个时候就要用到函数 wildcard

1
$(wildcard PATTERN…)

例如:

1
$(wildcard *.c)

获取当前目录下所有的.c 文件

12.Shell脚本入门基础

12.1 什么是shell脚本

之前我们已经了解到终端下输入的一些常用Shell命令,但是我们都是一条一条输入命令,遇到大量的指令时会很

麻烦,所以我们通过shell脚本一次性执行大量指令!shell脚本类似windows的批处理文件,就是将连续执行的命

令写成一个文件,shell脚本提供数组、循环、条件判断的等功能,shell脚本一般是Linux运维或者系统管理员

要掌握的,作为嵌入式开发人员,我们只需要掌握shell脚本最基础的部分即可。

12.2 shell脚本写法

shell脚本是个纯文本文件,命令从上而下,一行一行的开始执行,shell脚本扩展名为.sh,shell脚本第一行一定要为:

1
#!/bin/bash

表示使用bash,因为linux里面不仅仅只有bash一个解析器,还有其它的,它们之间的语法会有一些不同,所以加上这一句话,告诉系统要用这个解析器

12.3 shell基本语法

  • shell变量

定义变量时,变量名不加美元符号

1
name=“666”

name为定义的变量

使用定义过的变量,只要在变量名前面加美元符号$,格式如下

1
echo $nameecho ${name}
  • shell输出

echo 指令用于字符串的输出,使用格式如下

1
#显示字符串echo "It is a test" #显示变量echo "$name It is a test"# #号为shell中注释符号
  • shell读取

read指令用于读取,可以带有-a, -d, -e, -n, -p, -r, -t, -s八个选项,语法如下

1
read [-ers] [-a aname] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]

8个参数功能描述

参数 功能
-d 后面跟一个标志符,其实只有其后的第一个字符有用,作为结束的标志。
-p 后面跟提示信息,即在输入前打印提示信a息
-e 在输入的时候可以使用命令补全功能。
-n 后跟一个数字,定义输入文本的长度,很实用。
-r 屏蔽\,如果没有该选项,则\作为一个转义字符,有的话 \就是个正常的字符了。
-s 安静模式,在输入字符时不再屏幕上显示,例如login时输入密码。
-t 后面跟秒数,定义输入字符的等待时间。
-u 后面跟fd,从文件描述符中读入,该文件描述符可以是exec新开启的
  • shell数值计算

shell脚本中数值仅支持整形,数值计算表达式如下

1
$((表达式))

例如:

1
#!/bin/basha=1b=2c=$((a+b))echo "$a+$b=$c"

20210606232012

注意:shell语法内 ‘=’号的使用前后不能有间隔!

  • shell的test命令

test命令用于查看文件是否存在、权限等信息,可以进行数值,字符,文件三方面的测试。

数值测试

参数 说明
-eq 等于则为真
-ne 不等于则为真
-gt 大于则为真
-ge 大于等于则为真
-lt 小于则为真
-le 小于等于则为真

字符串测试

参数 说明
= 等于则为真
!= 不相等则为真
-z 字符串 字符串的长度为零则为真
-n 字符串 字符串的长度不为零则为真

文件测试

参数 说明
-e 文件名 如果文件存在则为真
-r 文件名 如果文件存在且可读则为真
-w 文件名 如果文件存在且可写则为真
-x 文件名 如果文件存在且可执行则为真
-s 文件名 如果文件存在且至少有一个字符则为真
-d 文件名 如果文件存在且为目录则为真
-f 文件名 如果文件存在且为普通文件则为真
-c 文件名 如果文件存在且为字符型特殊文件则为真
-b 文件名 如果文件存在且为块特殊文件则为真

&&和||命令:

cmd1 && cmd2:当cmd1执行完并且正确,那么cmd2开始执行,如果cmd1执行完毕错误,那么cmd2不执行。

cmd1 || cmd2: 当cmd1执行完毕并正确,那么cmd2不执行,反之cmd2执行。

根据以上指令编写测试程序

1
#!/bin/bashecho "please input two string:"read -p "first:" str1 #一一对应输入参数read -p "second:" str2#运用 && 和 || 判断test结果test $str1 == $str2 && echo "str1 = str2" || echo "str1 != str2"

测试结果

20210606234957

  • shell中括号[]判断符

[ ]为test命令的另一种形式,但要注意:

1.必须在左括号的右侧和右括号的左侧各加一个空格,否则会报错。

2.test命令使用标准的数学比较符号来表示字符串的比较,而用文本符号来表示数值的比较。

3.大于符号或小于符号必须要转义,否则会被理解成重定向。

[ ] 将判断内容框起来,代替test判断结果,使用方法如下

1
[ "$str1"=="str2" ]

注意:参数必须加””号表示一个整体参数,[]与内容必须间隔一个空格

  • shell默认变量

shell脚本提供许多默认参数,具体如下:

参数 作用
$0 输出当前执行脚本的路径
$n 运行脚本时,后面跟的参数,例:./test.sh 1 2 3 那么在test.sh中,$0=./test.sh ,$1=1 ,$2=2,$3=4
$# 命令行参数的个数
$@ 所有参数的值,每个参数用引号包起来
$* 所有参数的值,所有参数用一个引号包起来
$? 判断上一条命令是否执行成功
$$ 获得当前进程进程号
$! 上一个指令的PID
$_ 在执行此命令之前的前一个命令

主要介绍如下一个:

$0~$n,表示shell脚本的参数,包括shell脚本命令本身,shlle脚本执行脚本的路径为$0,$1-n则可以在我们运行脚本时直接传入参数,例如以下代码

1
1 #!/bin/bash  2 echo "input dat=" $1  3 echo "pos of shell=" $0

运行结果

20210607095931

  • shell条件判断

shell脚本支持条件判断,虽然可以通过&&和||来实现简单的条件判断,但是稍微复杂一点的场景就不适合了。shell脚本提供了if then条件判断语句,写法

1
if [条件判断] ; then #判断成立要做的事情fi

还有if then else 语句,写法

1
if [条件判断] ; then #条件判断成立要做的事情else #条件判断不成立要做的事情。fi

或:

1
if [条件判断] ; then #条件判断成立要做的事情elif [条件判断]; then #条件判断成立要做的事情else #条件判断不成立要做的事情。fi

实例代码:

1
1 #!/bin/bash  2 echo "please input two string:"  3 read -p "first:" str1 #一一对应输入参数  4 read -p "second:" str2  5   6   7   8 if [ "&str1"=="$str2" ] ; then  9     echo "str1=str2" 10 else 11     echo "str1!=str2" 12 fi

执行结果

20210607094428

最后还有case语句

1
case $变量 in“第1个变量内容”)   程序段   ;;   #表示该程序块结束!!“第2个变量内容”)   程序段   ;;“第n个变量内容”)   程序段   ;;esac

示例代码:

1
1 #!/bin/bash  2 case $1 in  3 "a")  4    echo "dat A"  5    ;;   #表示该程序块结束!!  6   7 "b")  8    echo "dat B"  9    ;; 10  11 *)     # *号表示其他所有情况 12    echo "dat other" 13    ;; 14 esac

执行结果:

20210607101551

  • shell函数

shell脚本支持自定义函数,函数写法如下:

1
[ function ] funname [()]{    #代码段;    [return int;]}

说明:

  1. 可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。

  2. 参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255

实例代码

1
#!/bin/bashfunction help(){  case $1 in  "-a")     echo "help a"     ;;     "-b")     echo "help b"     ;;    *)     # *号表示其他所有情况     echo "unknow"     ;; esac}#执行函数help -ahelp -bhelp -c

运行结果

20210607102639

  • shell循环

shell脚本也支持循环,比如 while do done,表示当条件成立的时候就一直循环,直到条件不成立,写法如下:

1
while [条件]  #括号内的状态是判断式do         #循环开始    #循环代码段done 

还有另外一种until do done,表示条件不成立的时候循环,条件成立以后就不循环,写法如下:

1
until [条件]do	#循环代码段done

示例循环代码:

1
1 #!/bin/bash  2 read -p "please input name:" name  3   4 while [ "$name" == "jeck" ]  5 do    6     read -p "please input name:" name  7 done  8 echo "While Over!"

运行结果:

20210607103845

for循环,使用for循环可以知道循环次数,写法:

1
for var in con1 con2 con3……do	#循环代码段done

示例代码:

1
#!/bin/bashfor var in a b c d edo 	echo $vardone

执行结果,依次输出:

20210607104121

for循环数值处理,写法:

1
for((初始值; 限制值; 执行步长))do	#循环代码段done

示例代码:

1
#!/bin/bashfor((i=0; i<5; i++))do	echo $idone

执行结果如下:

20210607104359

以上就是Linux驱动开发,Ubuntu入门需要的基本知识了,完结撒花

wechat