导图社区 嵌入式系统组成详解
详细讲解了嵌入式的组成部分,以及学习方法和学习路线。如 硬件发展历程有MPU:微处理器、MCU:微控制器(MPU+外围器件)、Soc:片上系统(MCU+系统)、Sip(多Soc)。
编辑于2023-08-09 15:44:11 北京市嵌入式系统
硬件
发展历程
MPU:微处理器
Micro Processor Unit
为什么?
因为嵌入式产品的普及,需要一个运算核心控制硬件。所以就由CPU(计算机运算核心统称)演变而来,在CPU基础上保留了与嵌入式应用紧密相关的功能硬件
是什么?
主要组成
控制单元
组成
指令计数器
指令寄存器IR
作用
暂存当前正在执行的指令
按指令集分类
RISC(精简指令集)
特点
减少指令集
指令单周期执行
目标代码大
种类
ARM(闭源)
概念:英国ARM公司是全球领先的半导体知识产权(IP)提供商。全世界超过95%的智能手机和平板电脑都采用ARM架构 [1] 。ARM设计了大量高性价比、耗能低的RISC处理器、相关技术及软件
架构
ARMv1
ARMv2
ARMv3
ARMv4
ARM7:没有MMU(内存管理单元),只能叫做MCU(微控制器),不能运行诸如Linux、WinCE等这些现代的多用户多进程操作系统,因为运行这些系统需要MMU,才能给每个用户进程分配进程自己独立的地址空间。ucOS、ucLinux这些精简实时的RTOS不需要MMU,当然可以在ARM7上运行
ARMv5
ARM9:是嵌入式CPU(处理器),带有MMU,可以运行诸如Linux等多用户多进程的操作系统,应用场合也不同于ARM7
ARMv6
ARM11:是嵌入式CPU(处理器),带有MMU,可以运行诸如Linux等多用户多进程的操作系统,应用场合也不同于ARM7
ARMv7
ARM-Cortex
A系列:面向尖端的基于虚拟内存的操作系统和用户应用
M系列:对微控制器
框图
举例
STM32
tumb-2
R系列:针对实时系统
ARMv8
MIPS
PowerPC
RISC-V(开放)
CISC(复杂指令集)
特点
减少目标代码的数量
增强指令的能力
指令复杂,指令周期长
种类
X86
intel
AMD
指令译码器ID
作用
对现行指令分析,确定要完成的操作及寻址方式
操作控制器OC
...
运算单元(执行部件)
接收控制单元的命令,完成算术运算和逻辑运算
存储单元(暂时存放数据的地方)
专用寄存器和通用寄存器
知识点
是一个小的存储设备,由一些字长大小的寄存器组成,这些寄存器每个都由唯一的名字
分类
R0-R12:通用寄存器
32 位通用寄存器,用于数据操作。但是注意:绝大多数16 位Thumb 指令只能访问R0‐R7,而32 位Thumb‐2 指令可以访问所有寄存器
Banked R13: 两个堆栈指针
Cortex‐M3 拥有两个堆栈指针,然而它们是banked,因此任一时刻只能使用其中的一个
主堆栈指针(MSP)
复位后缺省使用的堆栈指针,用于操作系统内核以及异常处理例程(包 括中断服务例程)
进程堆栈指针(PSP)
由用户的应用程序代码使用
备注
堆栈指针的最低两位永远是0,这意味着堆栈总是4 字节对齐的
R14:连接寄存器LR
作用
当呼叫一个子程序时,由R14 存储返回地址
举例
当你在使用BL(分支并连接,Branch and Link)指令时, 就自动填充LR 的值
R15:程序计数寄存器
作用
指向当前的程序地址
备注
如果修改它的值,就能改变程序的执行流
特殊功能寄存器
程序状态字寄存器组(PSRs或xPSR)
应用程序APSR
中断号IPSR
执行EPSR
中断屏蔽寄存器组(PRIMASK, FAULTMASK,以及BASEPRI)
作用
用于控制异常的使能和除能
控制寄存器(CONTROL)
操作模式和特权级别
作用
用于定义特权级别,还用于选择当前使用哪个堆栈指针
框图
它们只能被专用的MSR 和MRS 指令访问,而且它们也没有存储器地址
框图cm3
体系结构
冯.诺伊曼结构
将程序指令存储器和数据存储器合并在一起的存储器结构
程序指令和数据的宽度相同
哈佛结构
将程序指令和数据分开存储
指令和数据可以有不同的数据宽度
采用了独立的程序总线和数据总线
概要
存储器映射图
其他组成部分
内核中
MPU存储器保护单元(可选)
引入
它会使嵌入式系统变得更加健壮,更加可靠
作用
可以对特权级访问和用户级访问分别施加不同的访问限制
管理中断和异常的控制器内核外设
NVIC嵌套向量中断控制器
框图
cortex-M
240个中断请求
IRQ
1个不可屏蔽中断
NMI
用途
在多数情况下,NMI 会被连接到一个看门狗定时器
是电压监视功能块
1个滴答定时器中断
System timer
多个系统异常
内核触发
作用
可嵌套中断支持
作用范围
覆盖了所有的外部中断和绝大多数系统异常
概念
高优先级的异常会抢占低优先级的异常
向量中断支持
概念
当开始响应一个中断后,CM3会自动定位一张向量表,并且根据中断号从表中找出ISR 的入口地址,然后跳转过去执行
向量表
在复位后,该寄存器的值为0。因此,在地址0 处必须包含一张向量表,用于初始时的 异常分配
动态优先级调整支持
软件可以在运行时期更改中断的优先级
中断延迟大大缩短
引入了好几个新特性
自动的现场保护和恢复
其他
中断可屏蔽
既可以屏蔽优先级低于某个阈值的中断/异常
设置BASEPRI 寄存器
全体封杀
设置PRIMASK 和FAULTMASK 寄存器
寄存器
对应的结构体
NVIC_Type
应用
中断和异常
异常
框图
个数
16-1-4=11
中断
框图
个数
240
SCB:系统控制块
作用
提供系统控制以及系统执行信息,包括配置,控制,上报系统异常等
寄存器
对应的结构体
SCB_Type
ALU
执行算术(AU)和逻辑(LU)操作
备注
可能含有一个以上AU,去执行浮点运算
FPU(可选)
Cortex-M4、Cortex-M7、Cortex-M33、Cortex-M35P、Cortex-M55处理器中都具备FPU硬件
L1/L2高速缓存
解决问题
针对处理器和主存之间的差异,设计处更小更快的存储设备
本质
SRAM
作用
用来暂时的集结区域,存放处理器在不久的将来可能会需要的信息
框图
用途
可以使用高速缓存提高程序的性能,加快访问速度
总线
概念
贯穿整个系统的是一组电子管道
作用
携带信息字节并负责在各个部件间传递
分类
地址
数据
控制
传递的单位
字word
字中的字节长是一个基本的系统参数,各系统不一致
框图
接口
指令存储区总线(两条)
负责对代码存储区的访问
分类
I‐Code
取指
是一条基于 AHB‐Lite 总线协议的 32 位总线,负责在 0x0000_0000 –0x1FFF_FFFF 之间的取指操作。取指以字的长度执行,即使是对于 16 位指令也如此。因此CPU 内核可以一次取出两条 16 位 Thumb 指令
D‐Code
查表
是一条基于 AHB‐Lite 总线协议的 32 位总线,负责在 0x0000_0000 –0x1FFF_FFFF 之间的数据访问操作
系统总线
用于访问内存和外设
覆盖的区域包括SRAM,片上外设,片外RAM,片外扩展设备,以及系统级存储区的部分空间
是一条基于 AHB‐Lite 总线协议的 32 位总线,负责在 0x2000_0000 –0xDFFF_FFFF 和0xE010_0000 – 0xFFFF_FFFF 之间的所有数据传送,取指和数据访问都算上。和 D‐Code 总线一样,所有的数据传送都是对齐的
私有外设总线
负责一部分私有外设的访问,主要就是访问调试组件
是一条基于 APB 总线协议的 32 位总线。此总线来负责 0xE004_0000 – 0xE00F_FFFF 之间的私有外设访问。但是,由于此 APB 存储空间的一部分已经被 TPIU、ETM 以及 ROM 表用掉了,就只留下了 0xE004_2000‐E00F_F000 这个区间用于配接附加的(私有)外设
其他接口
调试接口
CPU 提供称为“调试访问接口(DAP)”的总线接口
3种方式使用
由一个调试端口(DP)设备完成的
SWJ‐DP
既支持传统的JTAG 调试,也支持新的串行线调试协议
SW‐DP
去掉了对JTAG 的支持
ARM CoreSignt 产品家族的JTAG‐DP 模块
备注
还能挂载一个所谓的“嵌入式跟踪宏单元(ETM)
ETM 可以不断地发出跟踪信息,这些信息通过一个被称为“跟踪端口接口单元(TPIU)”的模块而送到内核的外部,再在芯片外面使用一个“跟踪信息分析仪”,就可以把TIPU 输出的“已执行指令信息”捕捉到,并且送给调试主机——也就是PC
内核外
处理器本身的辅助支持电路
时钟
复位
I/O设备
概念
是系统与外界的联系通道
主存
概念
临时存储设备
作用
处理器执行程序时,用来存放程序和程序处理的数据
内存状态
用户空间(用户态)
应用程序
调用内核态的方法
系统调用
不会直接调用系统调用函数,会通过API函数间接调用,比如POSIX、API和c库
异常(中断)
陷入
内核空间(内核态)
操作系统内核和驱动程序
层次结构的存储设备
在处理器和一个较大较慢的设备(主存)之间插入一个更小更快的存储设备(高速缓存存储器)
框图
处理器内的寄存器文件属于L0
主要思想
一个层次上的存储器作为下一层次上的存储器的高速缓存
工作原理
取指(Fetch)
根据指令计数器从存储器中取出各条指令,放在指令寄存器IR中
译码(Decode)
指令译码器ID确定了应该进行的操作
执行(Execute)
通过操作控制器OC向相应的部件发出控制信号,执行命令(运算单元+存储单元)
写回(Writeback)
更新指令计数器指向下一条指令
解释(执行)存储在主存中指令的引擎(从系统通电开始,直到断电,重复执行相同的基本任务)
特点
强处理力
怎么做?
举例
ARM的Cortex-A芯片
其他
名词解析
加载
从主存拷贝一个字节或者一个字到寄存器,覆盖寄存器原来的内容
存储
从寄存器上拷贝一个字节或者一个字到主存的某个位置,覆盖这个位置上原来的内容
更新
IO读/写
转移
常用性能评估标准
MIPS
每秒百万条指令
用来计算同一秒内系统的处理能力,即每秒执行了多少百万条指令
DMIPS
Dhrystone Million Instructions executed Per Second
每秒执行百万条指令,整数运算
Dhrystone
整数运算测试程序下的MIPS
主要用于测整数计算能力
他表示了在Dhrystone这样一种测试方法下的MIPS
举例
一个处理器达到 200 DMIPS的性能 是指:这个处理器测整数计算能力为(200*100万)条指令/秒
ARM各架构整型运算能力对比-DMIPS/MHz
A系列
R系列
M系列
MFLOPS
Million Floating-point Operations per Second
主要用于测浮点计算能力
采用Whetstone 主要用于测浮点计算能力
MCU:微控制器(MPU+外围器件)
为什么?
早期在工业控制领域,需要一种体积小的芯片直接放到仪器内部。所以就产生了集成化很高的MCU
是什么?
组成
将整个计算机系统集成到一块芯片中
MPU
外围电路
存储器
掉电丢失
RAM 随机存取存储器 (人们常说的内存,访问速度比较快)
SRAM
DRAM
分类
SDRAM
它是同步动态存储器,利用单一的系统时钟同步所有的地址数据和控制信号。使用SDRAM不但能提高系统表现,还能简化设计、提供高速的数据传输,在嵌入式系统中经常使用
DDR SDRAM
区别
同时钟频率下的数据传输速度
DDR加倍
上升和下降沿都传输数据
特定类型的RAM
DPRAM:双端口RAM
优点
通信速度快、实时性强、接口简单,而且两边处理器都可主动进行数据传输
CAM:内容寻址RAM
工作机制
同时将一个输入数据项与存储在CAM 中的所有数据项自动进行比较,判别该输入数据项与CAM 中存储的数据项是否相匹配,并输出该数据项对应的匹配信息
优点
数据检索能提高系统性能
FIFO:先进先出队列
FIFO 多 用 于 数 据 缓 冲
NVRAM
...
区别
数据存储位置
SRAM
利用双稳态触发器来保存信息的
只要不掉电,信息是不会丢失的
DRAM
利用MOS(金属氧化物半导体)电容存储电荷来储存信息的
因此必须通过不停地给电容充电来维持信息
定期刷新
SRAM
无需刷新
供电就会保持一个值
DRAM
需要定期刷新
电容器会因漏电出现电荷丢失
组成
SRAM
6个晶体管
DRAM
1个晶体管和一个电容器
DRAM的成本、集成度、功耗等明显优于SRAM
掉电不丢失
ROM(只读存储器)
ROM(不可编程)
PROM(可编程)
EPROM(可擦除可编程)
E2PROM(电可擦除可编程)
flash (非易失闪存技术,由于它具有和ROM一样掉电数据不会丢失的特性)
编程原理
只能1->0
所以编程前要擦除对应的块
分类
NOR Flash
NAND Flash
区别
与CPU接口
NOR
属于典型的SRAM,不需增加额外的控制电路
NAND
必须由相应的控制电路进行转换
访问
NOR
NAND
以块方式访问
能提供极高的单元密度,可以达到高存储密度,NAND读和写操作采用512字节的块
是否支持芯片内执行
NOR
支持
(在芯片内执行(Execute In Place),这样应用程序可以直接在Flash内运行,不必再把代码读到系统RAM中)
NAND
不支持
单元尺寸
NOR
2
NAND
1
单元尺寸几乎是NOR器件的一半,同时由于生产过程很简单,大大降低了生产的成本
擦写次数
NAND Flash中每个块的大擦写次数是100万次,是NOR Flash的10倍,这些都使得NAND Flash越来越受到人们的喜爱)
擦除编程速度
NAND远超过NOR
光/磁介质存储器
接口与总线
串口
RS-232
RS-422
RS-485
串行数据接口标准
IIC
两线式串行总线
总线组成
数据线SDA
时钟线SCL
作用
用于连接微控制器及其外围设备
特点
支持多主控(Multi-Mastering)模式
任何能够进行发送和接收的设备都可以成为主设备
主控能够控制数据的传输和时钟频率,在任意时刻只能有一个主控
各设备连接到总线的输出端必须是开漏输出或集电极开路输出的结构
为了避免总线信号的混乱
总线空闲时,上拉电阻使SDA 和SCL 线都保持高电平
根据开漏输出或集电极开路输出信号的“线与”逻辑,I2C总线上任意器件输出低电平都会使相应总线上的信号线变低
SPI
USB
数据传输率高、易扩展、支持即插即用和热插拔的优点
以太网接口
PCI和PCI-E
SD和SDIO
CPLD和FPGA
显示设备
显示屏
特点
集成化高,体积小
可放在仪表内部。可以直接加简单的外围器件(电阻,电容)就可以运行代码了
存储量小,输入输出接口简单,功能较低
一般跑跑裸机,最多跑RTOS(多线程),不会跑Linux(多进程),运行简单的代码
怎么做?
举例
STM32
ARM的Cortex-M芯片
Soc:片上系统(MCU+系统)
为什么?
随着功能越来越多,MCU集成化与MPU强处理力各优点二合一
是什么?
定制功能版本的MCU/MPU,专用芯片
组成
MPU/CPU+特定功能外设
MCU+特定功能模块外设
特点
SOC可以跑Linux或者QNX系统,最大的差别就是多核,多进程多线程。QNX也是实时操作系统,但是可以实现多进程的,多线程的功能,Linux的分时系统
怎么做?
举例
iMX6ULL(NXP)
ARM Cortex A7
Sip(多Soc)
其他知识点
CPU核数
单核
单个CPU
仅有一个执行单元
多核
8核8线程
有8个执行单元
8核16线程
有16个执行单元
实际8个CPU,但是一个CPU两个通路,模拟两个核,但是性能肯定没两个核强大
机器对于多字节的存储方式
大小端
大端
低地址存放整数的高位字节
大低高
小端
低地址存放整数的低位字节
小低低
举例:将0x12345678存放到0x00开始的地址上
按应用领域
通用处理器(GPP)
Soc
数字信号处理器(DSP)
概念
专门用来对离散时间信号进行极快的处理计算,提高编译效率和执行速度
包含
独立的硬件乘法器
乘法指令一般在单周期内完成
作用
针对通信、图像、语音和视频处理等领域的算法而设计
优化了卷积、数字滤波、FFT(快速傅里叶变换)、相关矩阵运算等算法中的大量重复乘法
分类
浮点DSP
用硬件来实现,可以在单周期内完成,因而其浮点运算处理速度高于定点 DSP
定点DSP
定点运算模拟浮点运算
融合,数字信号控制器(DSC)MCU+DSP
专用处理器(ASP)及ASIC
网络处理器
音视频编解码器
...
软件
驱动层
为什么?
将底层硬件和系统上层分离开来,使得系统上层人员无需关注硬件,只要调用BSP提供的接口即可操作硬件
是什么?
功能
初始化底层硬件
对CPU、内存、中断等相关的寄存器及协处理器进行正确的配置
引导操作系统
设计硬件相关的设备驱动
Flash驱动、RTC/定时器驱动、串口驱动、以太网驱动、LCD驱动、键盘驱动等其他驱动
特点
BSP是针对操作系统的,不同的操作系统BSP也不同
怎么做?
操作系统层
为什么?
防止硬件被失控的应用程序滥用
在控制复杂而又不同的低级硬件设备方面,为应用程序提供简单一致的方法
是什么?
组成
内核
文件系统
嵌入式GUI
TCP/IP网络系统
电源管理
种类
freertos
Linux
怎么做?
其他
提供了三个抽象概念
文件
对IO设备的抽象
虚拟存储器
对主存和磁盘的抽象
进程
处理器、主存和IO设备的抽象
不同操作系统之间的那些事
Linux和Windows互通
分类
Linux和Windows在一个硬件上时
VMware tools
安装目的
1.可以在Windows下和虚拟机安装的系统(这里安装的Ubuntu)进行复制粘贴
2.可以设置Windows和虚拟机安装的系统(这里安装的Ubuntu)之间的共享文件夹
1.在Windows下创建一个文件夹
2.在VMware下设置/选项/共享文件夹下选择总是开启,并添加创建的文件夹路径
安装步骤
点击VMware下的安装tools或下载离线安装包
解压安装包
打开解压好的文件夹运行./vmware-install.pl,以来回车
重启Ubuntu
特点
具有局限性,只适合在一台硬件上
Linux和Windows在不在一个硬件上,Linux服务器在机房
远程登录到Linux服务器的软件 (通过SSH服务)
SSH服务
概念
可以通过SSH去远程到服务器
特点
1. 数据传输是加密的,可以防止信息泄露
2. 数据传输是压缩的,可以提高传输速度
安装
sudo apt-get install openssh-server
默认配置文件/etc/ssh/sshd_config
启动
sudo service ssh start
启动过后会监听22号端口
重启服务
/etc/init.d/ssh restart
查看
sudo ps -e |grep ssh
XShell 5
安装
网址
https://xshell.en.softonic.com/
https://www.xshell.com/zh/xshell/
傻瓜式安装即可
使用
新建会话
问题
目前只能通过普通用户登录,不能通过root直接登录
SecureCRT安装
网址
https://www.xitongbuluo.com/jiaocheng/52551.html
操作
问题
目前只能通过普通用户登录,不能通过root直接登录
实现文件互传的软件 (通过FTP默认端口21,SFTP默认端口22)
开启Ubuntu下的FTP服务
sudo apt-get install vsftpd
sudo vi /etc/vsftpd.conf
确保 local_enable=YES write_enable=YES 没有#
保存退出
sudo /etc/init.d/vsftpd restart
FileZilla
Windows下安装FTP客户端(FileZilla)
下载网址
https://filezilla-project.org/download.php?type=client
站点管理器新建连接
出现乱码情况,修改字符集
XFtp 5
网址
https://www.xshell.com/zh/xftp/
配置
\r和\r\n的区别
\r
回车
把打印头定位在行首
0x0D
\n
换行
把打印纸向下移动一行
0x0A
分类
Windows
每行结尾有“<回车><换行>”,即“\r\n”
0x0D 0x0A
unix/Linux
每行结尾只有“<换行>”,即"\n"
0x0A
mac
每行结尾只有“<回车>”,即"\r"
0x0D
产生的结果
Unix/Linux/Mac系统生成的文本文件,当在Windows里打开时,会变成一行
Windows文件在Unix/Linux/Mac系统下打开时,会在每行的结尾会多出一个^M符号
中间层
为什么?
介于应用层和操作系统层,主要作用是对嵌入式应用屏蔽底层操作系统的异构性,常见功能有网络通信、内存管理、数据处理等
是什么?
面向应用领域的中间件
举例
嵌入式CORBA
嵌入式JAVA
嵌入式DCOM
应用层
为什么?
针对特定应用领域,用来实现用户预期目标的软件
是什么?
知识点
C/C++
编译器
为什么?
为了使人编写的高级语言能被机器识别。 1. 所以每句C语句都必须被转换成一系列低级机器语言指令; 2. 这些指令按照一种可执行目标程序的格式进行打包,然后以二进制磁盘文件的形式存放起来
是什么?
就是一个程序
编译过程
框图
步骤
预处理阶段
作用
提供了极大的灵活性,以适应不同计算机和操作系统环境的限制
一个环境中所需的代码可能与另一环境中所需的代码不同,因为可用的硬件或操作系统不同. 在许多情况下,您可以将不同环境的代码放在同一文件中,然后在预处理阶段修改代码以使其适应当前环境
预处理器cpp
c-》i
原理
根据字符#开头的指令,修改原始的C程序,生成.i文本文件
执行的操作
展开include包含的头文件
替换宏定义内容
去注释
处理条件编译
指令
gcc -E cc.c -o cc.i
-E表示让编译器在预处理后就退出
cpp cc.c -o cc.i
编译
作用
读取源程序(字符流),分析其词法和语法,并将高级语言指令转换为功能上等效的汇编代码
编译器cc1
执行的操作
将文本文件hello.i翻译成hello.s(汇编程序)
汇编的每一条语句都是以一种标准的文本格式确切的描述了一条低级机器语言指令
文本格式
人能看懂的
机器语言指令
处理需要执行的指令
一条汇编语言对应一条机器指令
为不同的高级语言的不同编译器提供了通用的输出语言
将C程序的指令和数据分开,分别映射到不同的程序段中
优化
两种方式
中间代码的优化. 此优化不依赖于特定的计算机
删除通用表达式,循环优化(代码外推,强度降低,变换循环控制条件,已知数量的合并等),复制传播以及删除无用的赋值,以及还有很多
主要针对目标代码的生成
与机器的硬件结构密切相关. 最重要的是考虑如何充分利用存储在机器硬件寄存器中的相关变量的值,以减少对内存的访问次数. 另外,如何根据机器硬件执行指令(如流水线,RISC,CISC,VLIW等)的特性对指令进行一些调整,以使目标代码更短,执行效率相对较高
等级
-O
指令
gcc -S cc.c -o cc.s
-S指让编译器在编译之后停止,不执行后续过程,生成汇编代码cc.s
汇编
作用
提供可读性更好的的文本格式,来理解机器指令
汇编器as
执行的操作
将hello.s汇编语言代码翻译成目标机器语言指令
为每个源文件生成对应的目标文件
打包这些指令成为一种叫做可重定位目标程序的格式,并将结果保存到目标文件hello.o(二进制文件)
知识点
汇编代码可见的处理器状态
程序计数器
表示将要执行的下一条指令在存储器中的地址
整数寄存器文件
个数
包含8个
存储的位数
分别存储32位的值
存储的内容
地址
对应于C的指针
整数数据
有的寄存器用来记录某些重要的程序状态,而其他的寄存器用来保存临时数据,例如过程的局部变量
条件码寄存器
作用
实现控制流中的条件变化,比如if或while
存放内容
保存最近执行的算术指令的状态信息
浮点寄存器文件
个数
8个位置
存放内容
浮点数据
程序存储器
存放内容
程序的目标代码
操作系统需要的信息
用来管理过程调用和返回的运行时栈,以及用户分配的存储器块
用虚拟地址寻址,然后操作系统负责管理虚拟地址,将虚拟地址转换成物理地址
机器指令
作用
只执行非常基本的操作
特点
常用的字节少,不常用的多
指令格式:可以将字节唯一的解码成机器指令
举例
将两个存放在寄存器中的数字相加
在存储器和寄存器之间传递数据
条件分支转移到新的指令地址
指令
as cc.s -o cc.o
gcc -c cc.s -o cc.o
链接
作用
安排目标代码的各个部分,使某些部分的功能能够成功地调用其他部分的功能
添加包含程序所使用的库函数指令的片段
链接器ld
执行的操作
将多个目标文件以及需要的库文件链接成最终的可执行文件(链接过程:将各个独立的目标地址空间编排到一个统一的地址空间中,生成一个完成的与实际物理内存相符合的内存映像文件,在有MMU的系统中可以为每个任务单独分配一个地址空间)
可执行文件加载到存储器后,由系统负责执行
知识点
链接库的两种方式
静态
本质
静态链接库实际上是对象文件的集合,每个对象文件包含库中一个或一组相关功能的代码
该功能的代码将从其所在的静态链接库中复制到最终的可执行程序中,在执行程序时,这些代码将被加载到进程的虚拟地址空间中
动态
功能代码被放置在称为动态链接库或共享库的目标文件中
作用
在最终的可执行程序中记录共享对象的名称和其他少量注册信息. 当执行此可执行文件时,动态链接库的全部内容将在运行时映射到相应进程的虚拟地址空间. 动态链接程序将根据可执行程序中记录的信息找到相应的功能代码
优点
多进程访问共享库时,可节省内存
链接器的配置原则(ARM)
RO处于低地址
地址映射本着“RO第一,RW第二,ZI最后”
同一模块,代码的配置优于数据
之后按着名字字母的顺序来配置
指令
ld -o cc.out cc.o ...libraries...
备注
目标代码中必须有一个main函数
反汇编
引入
把可执行文件翻译成汇编指令,调试代码
本质
确定可执行文件所表示的指令序列的工具
原理
根据目标文件中的字节序列来确定汇编代码
OBJDUMP
objjump -d xxx.o
知识点
目标文件的类型
可重定位文件
产生
汇编器
内容
能够链接到其他目标文件以创建可执行文件或共享文件的代码和数据
结构图
构成
由一些段构成(section)ARM
.text(代码段)
存放程序的机器指令
通常是可读和可执行的,但通常是不可写的
.data(数据段)
存放各种全局变量或静态数据
常规数据段是可读,可写和可执行的
.bss(未初始化的数据段)
存放未初始化的局部静态变量
特点
对于未初始化的全局变量(或初始化为0的全局变量)不同语言与编译器的实现有不同的处理方式
.rdata/.rodata(只读数据段)
存放程序中只读变量
如const修饰的变量和字符串常量
设立此段的优点
语义上支持了C的const常量
.symtab(符号表段)
存放符号表
特点
每个目标文件都有一个相应的符号表,记录目标文件中用到的所有符号,每个符号都有相应的值,叫符号值。(符号值可以是符号对应的数据在段中的偏移量,可以是该符号的对齐属性)
在链接中,我们将函数和变量统称为符号(Symbol),函数或变量名就是符号名(Symbol Name)
其他一些特殊的段
存放调试信息的段
1.全局变量和局部变量同名,优先识别局部变量
2..bss段会把未初始化的全局变量初始化为0
3.定义变量开辟空间的时候才会初始化, 静态局部变量只能被初始化一次
其他
链接时所需要的一些信息
比如重定位信息和符号表等
备注
将这些不同的信息按照不同的属性,以“节(section)”也叫“段(segment)”的形式进行存储
特点
每个section和指令的地址都是相对与0的偏移,因为具体存放在内存哪里,编译阶段并未知道,链接时才确定
程序运行时的堆和栈在运行时决定,和目标文件无关
目标文件的格式和平台相关,Linux的.o是ELF格式,Windows的.obj是PE/COFF格式
一般低地址放代码,高地址放数据
共享目标文件
产生
链接器
内容
存储适合在两个上下文中链接的代码和数据
链接器可以将其与其他可重定位文件和共享目标文件一起处理,以创建另一个目标文件
动态链接器使用另一个可执行文件和其他共享对象文件对其进行处理,将它们组合在一起以创建一个过程映像
可执行文件
产生
汇编器
内容
包含一个文件,操作系统可执行该文件创建进程
构成
是由多个可重定位的文件各自的段拼接到一起的
框图
编译器的安装和配置
把下载好的文件上传到Ubuntu
拷贝、解压
配置环境变量,重启Ubuntu
验证编译器版本
编译参数
-std=c99 或 -std=gun99
gcc 默认使用的是 C89 的标准,而 C89 的标准不支持在 for 中定义循环变量,而在 for 循环中需要定义循环变量的话,需要在 C99 标准中才支持,因此需要增加 -std=c99 或 -std=gun99 参数才能编译通过
等级优化
-O
-O0 表示没有优化
-O1 为缺省值,提供基础级别的优化
-O2 提供更加高级的代码优化,会占用更长的编译时间
是性能优化和使用方便之间的妥协
-O3 提供最高级的代码优化
优点
程序运行更快
缺点
编译时间更长了
堆代码调试更困难
-Wall
编译后显示所有警告
-fPIC
保证so库能被正确加载,最好显式的添加上
编译器种类
运行在X86架构的PC上的gcc编译器
gcc
特点
编译X86架构的代码,也就是说编译出来的可执行文件是在X86架构上运行的
arm-linux-gnueabihf-gcc(交叉编译器)
背景
现在没有比较成熟的ARM架构的编译器,所以需要在另外的架构上的编译器去编译ARM架构的代码,生成可以在ARM架构上运行的可执行文件
下载网址
https://releases.linaro.org/components/toolchain/binaries/4.9-2017.01/arm-linux-gnueabihf/
安装和配置
安装配置参考网址
https://blog.csdn.net/cq17805982133/article/details/124251555?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165319967916781818733784%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=165319967916781818733784&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-124251555-null-null.nonecase&utm_term=linux&spm=1018.2226.3001.4450
把下载好的文件上传到Ubuntu
拷贝,解压
//1.若没有此路径,则创建 sudo mkdir /usr/local/arm //2.拷贝工具链到/usr/local/arm路径下 sudo cp gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz /usr/local/arm/ //3.解压 sudo tar -vxf gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf.tar.xz
这里的路径无所谓,主要是把这个路径添加到环境变量就行
配置环境变量,重启Ubuntu使能环境变量
//打开配置文件 sudo vi /etc/profile //最后面添加如下信息 export PATH=$PATH:/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin
//重启Ubuntu reboot
验证版本
//验证版本 arm-linux-gnueabihf-gcc -v
aarch64-linux-gnu-gcc(交叉编译器)
下载网址
https://releases.linaro.org/components/toolchain/binaries/6.3-2017.05/aarch64-linux-gnu/
自动化编译工具
make工具
是一个自动化编译工具
可以使用gcc自动完成编译工作,是通过Makefile文件来完成自动编译工作,这个文件描述了整个工程的编译、连接规则
make的工作方式
读入所有的Makefile
读入被include的其他Makefile
初始化文件中的变量
如果定义的变量被使用了,那么,make会把其展开在使用的位置。但make并不会完全马上展开,make使用的是拖延战术,如果变量出现在依赖关系的规则中,那么仅当这条依赖被决定要使用了,变量才会在其内部展开
推导隐晦规则,并分析所有规则
为所有的目标文件创建依赖关系链
根据依赖关系,决定哪些目标要重新生成
执行生成命令
make的参数
-r
禁止make使用任意隐含规则
-R
禁止make使用任何作用于变量上的隐含规则
--inlcude-dir=$(CURDIR) /-I
指明搜索路径
make是如何工作的
在当前目录下寻找Makefile或makefile文件
若找到,则会找文件中第一个目标文件aaa(target),并把这个文件作为最终的目标文件
若aaa文件不存在或aaa后面的依赖文件修改时间比aaa新,那么就会执行command生成aaa
若aaa的依赖文件存在,会在当前文件中找目标为.o文件的依赖性,若找到,则根据command生成.o文件
c和h文件是存在的,make会生成.o文件,然后再用.o文件生成终极目标aaa
makefile
整理
使用条件判断
ifeq
用于判断两个值是否相等
ifeq ("$(origin V)", "command line")
V变量如果在命令行定义,那么两个变量就相等了,因为origin返回定义的位置
规则
ifep(A,B) xxx else xxx endif
判断AB是否相等
条件关键字
变量
quiet
为空
显示整个命令
Q
控制编译的时候是否在终端输出完整的命令
Q
规则
$(Q)$(MAKE) $(build)=tools
V=0
@make$(build)=tools
不会在终端输出命令了
V=1
make$(build)=tools
在终端会输出完整的命令
quiet
规则
$($(quiet)$(cmd))
quiet取值
quiet为空
完整命令
quiet为quiet_
短命令
quiet为silent_
不输出命令
举例
sym
cmd_sym
输出完整命令
quiet_cmd_sym
输出短命令
功能一样,区别在于make执行的时候输出的命令不同
函数
origin
告诉你变量哪来的
规则
$(origin <variable>)
variable 是变量名,origin 函数的返回值就是变量来源,因此$(origin V)就是变量 V 的来源
如果变量V是在命令行定义的,那么origin的返回值就是command line
filter
过滤函数
规则
$(filter <pattern...>,<text>)
表示以 pattern 模式过滤 text 字符串中的单词,仅保留符合模式 pattern 的单词,可以有多个模式
返回值
符合pattern的字符串
$(filter 4.%,$(MAKE_VERSION))
表示在MAKE_VERSION中找到符合4.%的字符,并返回4.%
MAKE_VERSION通过make -v查看
MAKE_VERSION=4.1
返回4.1
filter-out
反过滤函数
格式
$(filter-out PATTERN…,TEXT)
返回值
空格分割的“TEXT”字串中所有不符合模式“PATTERN”的字串
举例
firstword
作用
获取首单词
规则
$(firstword <text>)
取出 text 字符串中的第一个单词,函数的返回值就是获取到的单词
举例
$(firstword x$(MAKEFLAGS))
当MAKEFLAGS=-rR xxx xxx
返回xrR
去掉-
if
作用
在函数上下文中实现条件判断的功能
格式
$(if CONDITION,THEN-PART,[ELSE-PART])
返回值:有效表达式的计算结果
CONDITION
非空
则条件为真,就将第二个参数“ THEN_PATR”作为函数的计算表达式
为空
将第三个参数“ ELSE-PART”作为函数的表达式
关键字
.PHONY
作用
防止在Makefile中定义的只执行命令的目标和工作目录下的实际文件出现名字冲突
用法
.PHONY:clean
表示clean是一个伪目标,和目录中实际的同名文件无关,告诉make执行clean的指令
变量
特殊变量
MAKECMDGOALS
记录了命令行参数指定的终极目标列表
举例
make are you ok
MAKECMDGOALS= are you ok
核心规则
target ... :prerequisite ... command
target
目标文件
obj中间文件
执行文件
标签
伪目标
prerequisite
要生成target所需要的文件或是目标
command
make需要执行的命令
任意的shell命令
执行command的条件
prerequisites文件的日期要比targets文件的日期要新
target不存在
注意
命令要以tab键作为开头
告诉make两件事
文件的依赖关系
如何生成目标文件
第一条规则中的第一个目标是终极目标
特殊用法
目标: command
目标后面不添加依赖,执行make不会去执行command,只有在执行“make 目标”,command才会执行
可以定义一些不用编译的命令,比如删除中间文件,程序打包,备份
clean: rm -rf xxx
指定特定的makefile文件
make -f xxx
make --file xxx
如果命令太长,你可以使用反斜框(‘\’)作为换行符
里面有什么?
显式规则
隐晦规则
变量定义
文件指示
在一个Makefile中引用另一个Makefile
和include类似
根据某些情况制定Makefile中的有效部分
和#if类似
定义一个多行的命令
注释
只有行注释
用#
注意
若要用#,则用\#进行转义
语法规则
赋值
=
变量的值是整个makefile中最后被指定的值
VIR_A = A VIR_B = $(VIR_A) B VIR_A = AA B = AAB
:=
直接赋值,赋予当前位置的值
VIR_A := A VIR_B := $(VIR_A) B VIR_A := AA B = AB
?=
如果该变量没有被赋值,则赋予等号后的值
VIR ?= new_value VIR = new_value
VIR := old_value VIR ?= new_value VIR = old_value
+=
表示将等号后面的值添加到前面的变量上
子主题
关键字
include
作用
包含别的Makefile
包含的文件会展开放到当前位置
用法
include <filename>
filename
若未制定相对路径和绝对路径
会在当前目录下寻找
有“-I”或“--include-dir”参数,那么make就会在这个参数所指定的目录下去寻找
如果目录<prefix>/include(一般是:/usr/local/bin或/usr/include)存在的话,make也会去找
include foo.make *.mk $(bar)
备注
如果有文件没有找到的话,make会生成一条警告信息,但不会马上出现致命错误。它会继续载入其它的文件,一旦完成makefile的读取,make会再重试这些没有找到,或是不能读取的文件,如果还是不行,make才会出现一条致命信息。如果你想让make不理那些无法读取的文件,而继续执行,你可以在include前加一个减号“-”。
-include <filename>
wildcard
vpath
作用
可以指定不同的文件在不同的搜索目录
用法
vpath <pattern> <directories>
为符合模式<pattern>的文件指定搜索目录<directories>
vpath %.h ../headers
要求make在“../headers”目录下搜索所有以“.h”结尾的文件
vpath <pattern>
清除符合模式<pattern>的文件的搜索目录
vpath
清除所有已被设置好了的文件搜索目录
备注
我们可以连续地使用vpath语句,以指定不同搜索策略。如果连续的vpath语句中出现了相同的<pattern>,或是被重复了的<pattern>,那么,make会按照vpath语句的先后顺序来执行搜索
vpath %.c foo:bar vpath % blish
而上面的语句则表示“.c”结尾的文件,先在“foo”目录,然后是“bar”目录,最后才是“blish”目录
变量
分类
特殊变量
VPATH
作用
make若在当前目录下未找到文件,会到指定的目录找寻文件
用法
VPATH = src:../headers
代表src和../headers两个路径
用:隔开
系统级的变量
MAKEFLAGS
作用
用来传递MAKE选项的
如果在命令行中make后面有选项,则在此处,会在原来make选项后加上 -rR --include-dir=$(CURDIR)
举例
命令行中执行的make --no-print-directory
则此处的MAKEFLAGS值为 --no-print-directory -rR --include-dir=当前目录
只要定义了就会传递到底层Makefile中,除非unexport
环境变量
MAKEFILES
如果你的当前环境中定义了环境变量MAKEFILES,那么,make会把这个变量中的值做一个类似于include的动作。这个变量中的值是其它的Makefile,用空格分隔。只是,它和include不同的是,从这个环境变中引入的Makefile的“目标”不会起作用,如果环境变量中定义的文件发现错误,make也会不理
备注
不介意使用
自动化变量
$@
目前规则中所有的目标的集合
$^
依赖集合
$<
依赖集合第一个文件
未分类变量
GREP_OPTIONS
表示grep搜索的时候shell下应该有搜索属性或者选项
高亮
export GREP_OPTIONS=’–color=XXX’
引用变量的方式
${}和${}无区别
伪目标
不是一个文件,只是一个标签
如果你的Makefile需要一口气生成若干个可执行文件,但你只想简单地敲一个make完事,可以使用伪目标
all : prog1 prog2 prog3 .PHONY : all
静态模式
作用
更加容易地定义多目标的规则
用法
<targets ...>: <target-pattern>: <prereq-patterns ...> <commands>
targets
定义了一系列的目标文件,可以有通配符。是目标的一个集合。
target-parrtern
指明了targets的模式,也就是的目标集模式
prereq-parrterns
目标的依赖模式,它对target-parrtern形成的模式再进行一次依赖目标的定义
举例
objects = foo.o bar.o all: $(objects) $(objects): %.o: %.c $(CC) -c $(CFLAGS) $< -o $@
上面的例子中,指明了我们的目标从$object中获取,“%.o”表明要所有以“.o”结尾的目标,也就是“foo.o bar.o”,也就是变量$object集合的模式,而依赖模式“%.c”则取模式“%.o”的“%”,也就是“foo bar”,并为其加下“.c”的后缀,于是,我们的依赖目标就是“foo.c bar.c”
自动生成依赖性
-M
作用
自动找寻源文件中包含的头文件,并生成一个依赖关系
用法
cc -M main.c
备注
如果你使用GNU的C/C++编译器,你得用“-MM”参数,不然,“-M”参数会把一些标准库的头文件也包含进来
通配符
*
?
[...]
让make自动推导
作用
它可以自动推导文件以及文件依赖关系后面的命令
只要make看到一个.o文件他就会自动把对应的.c文件加在依赖关系中
用法
main.o : defs.h
相当于 main.o : main.c defs.h cc -c main.c
是一种隐晦规则
清空目标文件的规则
写法
.PHONY:clean clean: -rm xxx
rm前加了-,表示也许某些文件出现问题,但不要管,继续做后面的事
编译选项
CC
C编译器的名称,默认为cc
CXX
C++编译程序。默认是"g++"
-I
指定头文件路径
sed
set -e
替换
sed -e 's/wang/w/g;s/xu/x/g' user.txt,
's/wang/w/g;s/xu/x/g'的意思,s代表search,g是尽可能多的匹配,有多少替换多少,因而意思是将user.text文本中的wang 替换成w,xu 替换成x
tr '[:upper:]' '[:lower:]
将所有的大写字母替换为小写字母
include和snclude
读取指定文件的内容
sinclude 读取的文件如果不存在的话不会报错
word
统计单词的个数
$(words <text>)
LC_X
LC表示locale
是根据计算机用户所使用的语言,所在国或地区及当地文化习俗所定义的一个runtime语言环境。
C是系统默认的locale
LC_COLLATE=C
一组变量
LC_COLLATE
表示比较规则和习惯
LC_NUMERIC
表示数字
LC_ALL
若设置了该值,则会覆盖前面所有的LC_*设置,除了LC_LANG
bsp工程管理下的通用makefile
变量的定义
指定编译器
指定目标文件
生成的文件
...
链接
ld
objcopy
objdump
编译
gcc
清除
清除生成文件
注意
编译源码的时候需要指定头文件路径
make 在执行的时候默认会在终端输出命令,但是在命令前面加上“@”就不会在终端输出命令了
使用“make -s”编译的时候,“-s”会作为 MAKEFLAGS 变量的一部分传递给 Makefile
内置的标准变量
CURDIR
表示Makefile 所在的当前目录目录
备注
如果在 make 中使用 --directory 或 -C 参数指定目录,那么 make 就会切换到所指定的目录去寻找 Makefile 文件
MAKE_VERSION
make 命令的版本号,也就是执行 make -v 时看到的版本号
特点
make支持递归调用,比如在Makefile文件中使用make可以执行其他的Makefile,一般都是子目录的Makefile
$(MAKE) -C subdir
$(MAKE) 就是使用make命令
-C 指定子目录
subdir为当前目录下的一个子目录
向子make传递变量
export
export VARIABLE ……
导出变量给子make
unexport
unexport VARIABLE……
不导出变量给子make
两个特殊变量除非使用“unexport”声明, 否则的话在整个make的执行过程中,它们的值始终自动的传递给子make
SHELL
MAKEfLAGS
make若没指定目标,就会使用默认目标
cmake工具
CMakeLists.txt
语法
变量
获取变量值
${变量名}
设置变量
set
作用
用来定义变量的值,相当于编程语言中的赋值操作(VAR=VALUE)
用法
SET(VAR [VALUE])
定义SRC_LIST变量为三个cpp文件的列表
SET(SRC_LIST main.cpp sqrt.cpp pow.cpp)
预定义变量
当前文件路径
${CMAKE_CURRENT_SOURCE_DIR}
安装路径
${CMAKE_INSTALL_PREFIX}
默认值为 /usr/local
项目编译路径
PROJECT_BINARY_DIR/CMAKE_BINARY_DIR/_BINARY_DIR
运行cmake命令的目录,即工程编译发生的路径
项目路径(CMakeLists.txt)
PROJECT_SOURCE_DIR/CMAKE_SOURCE_DIR/_SOURCE_DIR
为包含PROJECT()命令的最近一个CMakeLists.txt文件所在的文件夹路径
概要
CMAKE也隐式地定义了另外两个变量
项目名
${PROJECT_NAME}
编译选项
生成对应的版本
CMAKE_BUILD_TYPE
debug
cmake会使用变量CMAKE_CXX_FLAGS_DEBUG和CMAKE_C_FLAGS_DEBUG中的字符串作为编译选项生成Makefile
release
cmake会使用变量CMAKE_CXX_FLAGS_RELEASE和CMAKE_C_FLAGS_RELEASE选项生成Makefile
编译链接标志
指定编译标志
CMAKE_FLAGS变量
CMAKE_C_FLAGS
C语言编译器选项
对应于环境变量CFLAGS
CMAKE_CXX_FLAGS
C++语言编译器选项
对应于环境变量CXXFLAGS
指定特定构建类型的编译标志,这些编译标志将被加入到 CMAKE_C_FLAGS 或 CMAKE_CXX_FLAGS 中去
CMAKE_C_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
CMAKE_CXX_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
链接标志相关变量
CMAKE_EXE_LINKER_FLAGS
CMAKE_EXE_LINKER_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
CMAKE_MODULE_LINKER_FLAGS
CMAKE_MODULE_LINKER_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
CMAKE_SHARED_LINKER_FLAGS
链接动态库指定的参数
CMAKE_SHARED_LINKER_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
CMAKE_STATIC_LINKER_FLAGS
CMAKE_STATIC_LINKER_FLAGS_[DEBUG|RELEASE|MINSIZEREL|RELWITHDEBINFO]
系统名字
CMAKE_SYSTEM_NAME
Linux
FreeBSD
Windows
指定二进制文件保存路径
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)
概要
指定最终二进制文件(可执行文件及库文件,不包含中间文件)的位置
可执行文件
生成可执行文件
add_executable
用法
ADD_EXECUTABLE(name sourceFile)
sourceFile
单个文件
ADD_EXECUTABLE(${PROJECT_NAME} main.cpp)
多个文件
ADD_EXECUTABLE(${PROJECT_NAME} main.cpp pow.cpp)
源文件变量
ADD_EXECUTABLE(${PROJECT_NAME} ${SRC_FILE} ${LIB_FILE})
add_executable(executable main.c xxx.c)
作用
用sourceFile源文件生成一个名为name的可执行文件
sourceFile可以是单个文件,也可以是定义的文件列表变量
库
生成库
add_library
用法
ADD_LIBRARY(<name> [SHARED|STATIC|MODULE] [EXCLUDE_FROM_ALL] source1 [source2...])
name
指定生成的库文件名字,会自动加上前缀和后缀
[STATIC | SHARED | MODULE]
STATIC
生成静态库
SHARED
生成动态链接库
MODULE
这个生成的库注重于动态加载,而不是编译链接(官网说的),但是我实测和 SHARED 没什么区别
source
源码列表
add_library(${PROJECT_NAME} STATIC sub.c sub.h)
作用
生成库
备注
[EXCLUDE_FROM_ALL] 这个库不会被默认构建,除非有其他的组件依赖或者手工构建
生成最终共享库的文件名为,libname.so。会自动在库名前加lib
指定库路径的方式
link_directories
用法
include_directories(xxx)
link_directories(${PROJECT_SOURCE_DIR}/lib)
g++命令的-L选项的作用
环境变量中增加LD_LIBRARY_PATH的路径
概要
(可执行文件or库)链接库
不需要全路径
target_link_libraries
用法
TARGET_LINK_LIBRARIES(可执行文件名 库名(不带-l)) #大小写随便
三种
target_link_libraries(executable cc)
默认链接动态库
target_link_libraries(executable libcc.so)
链接动态库
target_link_libraries(executable libcc.a)
链接静态库
参数
-Wl,-Map=${targt_map_file}
生成map文件
target_link_libraries(${PROJECT_NAME} m -Wl,-Map=${targt_map_file})
m
数学库
备注
有时需要link_directories指定库路径
依赖库的顺序
依赖的库 被依赖的库
target_link_libraries(executable a b)
a依赖b
link_directories
添加需要链接的库文件目录(全路径)
link_libraries
用法
link_libraries(xxx)
link_libraries("/opt/MATLAB/R2012a/bin/glnxa64/libeng.so" "/opt/MATLAB/R2012a/bin/glnxa64/libmx.so")
概要
相同点
可以同时链接多个库
不同点
位置
target_link_libraries
用在add_executable之后
link_libraries
用在add_executable之前
增加编译定义
target_compile_definitions
作用
为指定target增加编译定义
举例
target_compile_definitions(target PUBLIC FOO)
add_compile_definitions
用法
add_compile_definitions(<definition> ...)
作用
预编译命令会添加到COMPILE_DEFINITIONS目录属性中
举例
add_compile_definitions(FOO)
-std=gnu99
-g
add_definitions
举例
add_definitions(-DFOO)
概要
为当前以下层路径的所有源文件和target增加编译定义
头文件
添加头文件路径
include_directories
用法
include_directories(xxx)
include_directories(${PROJECT_SOURCE_DIR}/include)
源文件
扫描指定文件夹下的所有源文件,并将源文件以列表的形式存放在变量中
aux_source_directory
用法
AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} SRC_FILES)
向当前项目添加存放源文件的子目录
add_subdirectory
用法
ADD_SUBDIRECTORY(directory [BINARY_DIR] [EXCLUDE_FROM_ALL])
[BINARY_DIR] 指定生成的二进制文件的存放位置
[EXCLUDE_FROM_ALL] 将这个目录从编译中排除
打印
message
用法
MESSAGE([SEND_ERROR|STATUS|FATAL_ERROR] "Content")
SEND_ERROR
报错误信息,不终止CMake构建过程
STATUS
普通输出信息
FATAL_ERROR
报错误信息,终止CMake构建过程
作用
相当于编程中的打印指令(python的print、C++的std::cout)
复制文件
将SOURCE目录文件or文件夹复制到BINARY目录
file(COPY ${PROJECT_SOURCE_DIR}/resource DESTINATION ${PROJECT_BINARY_DIR})
其他
cmake_minimum_required
作用
指定cmake的最小版本
用法
cmake_minimum_required (VERSION 3.12.0)
备注
cmake编译版本大于这里指定的版本
放在整个文件最开头
project
作用
设置工程名
可有可无
用法
PROJECT(projectname [CXX] [C] [JAVA])
[CXX] [C] [JAVA] 表示项目支持的语言,一般忽略这部分,默认情况下支持所有语言
project(cheche)
备注
这个指令隐式地定义了两个CMake变量
<projectname>_SOURCE_DIR
CMakeLists.txt文件所在目录
<projectname>_BINARY_DIR
执行cmake的目录
举例
假若projectname为cheche,则cheche_BINARY_DIR
备注
cheche_BINARY_DIR和CMAKE_BINARY_DIR值一样
projectname修改后,所有使用了这两个变量的CMakeLists.txt脚本的相应位置都需要更改
install
用法
INSTALL(FILES|PROGRAM|DIRECTORY|TARGETS xxx DESTINATION xxx)
DESTINATION后可以写绝对路径,也可以写相对路径。相对路径是${CMAKE_INSTALL_PREFIX}/<相对路径>
安装目录时,指定路径为directoryName是安装该文件夹到目标目录,指定路径为directoryName/是安装该文件夹中的所有文件到目标目录中
作用
可以指定是安装文件、非目标文件的可执行程序、目录、可执行文件
备注
CMake的指令可以大写、小写或大小混写,但是一般约定俗称都用大写
CMake指令的参数用括号括起来,参数之间用空格隔开,参数是大小写相关的,不要乱写
CMake参数也可以用分号“;”隔开,但不是约定俗成的用法,不建议使用
文件名带空格
处理办法是给文件名加引号
SET(HELLO_SRC_FILE "hello world.cpp")
将hello world.cpp文件赋值给HELLO_SRC_FILE变量
清除工程
make clean
清除Makefile生成的中间文件
rm -rf *
清除CMake生成的中间文件
外部构建
创建一个build文件夹存放中间生成文件
使用cmake ..
路径要指定到存放CMakeLists.txt的地方
模板
其他
cmake指定编译器的方式
在编译时指定
cmake .. -DCMAKE_CXX_COMPILER=/usr/local/bin/gcc
指定/usr/local/bin/gcc路径下的gcc来编译
在CMakeLists.txt文件中指定
在project(filename)前添加
set(CMAKE_C_COMPILER "/xxx/xxx/gcc")
set(CMAKE_CXX_COMPILER "/xxx/xxx/g++")
备注
这两条命令应该放在文件的开始位置(cmake_minimum_required命令之下,其他命令之上),否则可能无效
设置编译器的编译选项
针对所有类型编译器的
add_compile_options
用法
add_compile_options(-std=c++11 -Wall -Werror)
作用
添加编译参数
备注
这里添加的选项会在所有的编译器中运用
此命令添加的参数是递归的
在多层目录结构中,根文件下设置选项后,在所有的子目录编译时都会运用
针对指定类型的编译器
通过设置CMAKE_CXX_FLAGS来配置
作用
针对C++编译器的参数选项
默认保存环境变量CXX_FLAGS的内容,但是如果直接修改这个参数值,那么系统会忽略原CXX_FLAGS的内容
用法
set(CMAKE_CXX_FLAGS -std=c++11 -Wall -Werror )
备注
这个变量只在当前文件有效,如果项目中有多个模块,多个编译文件,那么需在每一个CMakeLists.txt文件中都添加对应的命令和参数
怎么做?
shell
用于用户和内核的交互
shell是一种命令行解释器,等待输入命令,然后执行命令,返回结果
执行的规则
如果第一个单词是内置shell命令,则执行
若不是shell命令,则shell就会假设这是一个可执行文件的名字,要加载和执行这个文件
1.
学习方法
1. 先建立整体框架(思维导图),然后细节
苏轼:不识庐山真面目,只缘身在此山。
2. 模块化
3. 适当囫囵吞枣
4. 举一反三,同类问题一举攻破
5. 一知识点三问题
为什么?
对应一个需求,解决了一个问题
是什么?
组成
工作原理
子主题
怎么做?
每个知识点要实践
学习路线
1. C语言
2. 裸机驱动
3. freertos
4. Linux
应用
驱动
uboot
kernel
rootfs
5. c++/qt
过程中穿插
工具的使用
shell脚本
嵌入式C编码规范