makefile和cmake

linux驱动


一、makefile

1.makefile常见语法

CROSS_COMPILE 	?= arm-linux-gnueabihf-
TARGET		  	?= beep

CC 				:= $(CROSS_COMPILE)gcc
LD				:= $(CROSS_COMPILE)ld
OBJCOPY 		:= $(CROSS_COMPILE)objcopy
OBJDUMP 		:= $(CROSS_COMPILE)objdump

INCDIRS 		:= imx6ul \
				   bsp/clk \
				   bsp/led \
				   bsp/delay  \
				   bsp/beep
				   			   
SRCDIRS			:= project \
				   bsp/clk \
				   bsp/led \
				   bsp/delay \
				   bsp/beep
				   
				   
INCLUDE			:= $(patsubst %, -I %, $(INCDIRS))

SFILES			:= $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
CFILES			:= $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))

SFILENDIR		:= $(notdir  $(SFILES))
CFILENDIR		:= $(notdir  $(CFILES))

SOBJS			:= $(patsubst %, obj/%, $(SFILENDIR:.S=.o))
COBJS			:= $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
OBJS			:= $(SOBJS) $(COBJS)

VPATH			:= $(SRCDIRS)

.PHONY: clean    
	
$(TARGET).bin : $(OBJS)
	$(LD) -Timx6ul.lds -o $(TARGET).elf $^
	$(OBJCOPY) -O binary -S $(TARGET).elf $@
	$(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis

$(SOBJS) : obj/%.o : %.S
	$(CC) -Wall -nostdlib -c -O2  $(INCLUDE) -o $@ $<

$(COBJS) : obj/%.o : %.c
	$(CC) -Wall -nostdlib -c -O2  $(INCLUDE) -o $@ $<
	
clean:
	rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)

	

(1)Binutils(bin utility),位于/usr/bin目录下,是GNU二进制工具集,通常跟GCC编译器一起打包安装到系统在进行程序开发的时候通常不会直接调用这些工具,而是在使用GCC编译指令的时候由GCC编译器间接调用。下面是其中一些常用的工具:

as:汇编器,把汇编语言代码转换为机器码(目标文件)。

ld:链接器,把编译生成的多个目标文件组织成最终的可执行程序文件。

readelf:可用于查看目标文件或可执行程序文件的信息。

nm : 可用于查看目标文件中出现的符号。

objcopy: 可用于目标文件格式转换,如.bin 转换成 .elf 、.elf 转换成 .bin等。

objdump:可用于查看目标文件的信息,最主要的作用是反汇编。

size:可用于查看目标文件不同部分的尺寸和总尺寸,例如代码段大小、数据段大小、使用的静态内存、总大小等。

(2)glibc:gcc自带的函数集文件
glibc库是GNU组织为GNU系统以及Linux系统编写的C语言标准库,因为绝大部分C程序都依赖该函数库,该文件甚至会直接影响到系统的正常运行,例如常用的文件操作函数read、write、open,打印函数printf、动态内存申请函数malloc等。

2.gcc编译流程

从 hello.c 编译得到 hello 或者 a.out 要经历四个步骤:预处理,编译,汇编,链接。

预处理,在预处理过程中,对源代码文件中的文件包含(include)、 预编译语句(如宏定义define等)都放在一起,生成.i文件。

编译,把预处理后的.i文件通过编译成为汇编语言,生成.s文件,即把代码从C语言转换成汇编语言,这是GCC编译器完成的工作。

汇编,将汇编语言文件经过汇编,生成目标文件.o文件,每一个源文件都对应一个目标文件。即把汇编语言的代码转换成机器码,这是as汇编器完成的工作。

链接,最后将每个源文件对应的.o文件链接起来,就生成一个可执行程序文件,这是链接器ld完成的工作。

-o作用是指定生成的文件名字
  
#直接编译成可执行文件
gcc hello.c -o hello

#以上命令等价于执行以下全部操作
#预处理,可理解为把头文件的代码汇总成C代码,把*.c转换得到*.i文件
gcc –E hello.c –o hello.i

#编译,可理解为把C代码转换为汇编代码,把*.i转换得到*.s文件
gcc –S hello.i –o hello.s

#汇编,可理解为把汇编代码转换为机器码,把*.s转换得到*.o,即目标文件
gcc –c hello.s –o hello.o

#链接,把不同文件之间的调用关系链接起来,把一个或多个*.o转换成最终的可执行文件
gcc hello.o –o hello

3.链接的细节

1.链接和编译的区别 例如一个工程里包含了A和B两个代码文件,编译后生成了各自的A.o和B.o目标文件, 如果在代码A中调用了B中的某个函数fun,那么在A的代码中只要包含了fun的函数声明, 编译就会通过,而不管B中是否真的定义了fun函数(当然,如果函数声明都没有,编译也会报错)。 也就是说A.o和B.o目标文件在编译阶段是独立的,而在链接阶段, 链接过程需要把A和B之间的函数调用关系理顺,也就是说要告诉A在哪里能够调用到fun函数, 建立映射关系,所以称之为链接。若链接过程中找不到fun函数的具体定义,则会链接报错。

2.动态链接和静态链接
动态链接:GCC编译时的默认选项。动态是指在应用程序运行时才去加载外部的代码库, 例如printf函数的C标准代码库*.so文件存储在Linux系统的某个位置, hello程序执行时调用库文件*.so中的内容,不同的程序可以共用代码库。 所以动态链接生成的程序比较小,占用较少的内存。

静态链接,链接时使用选项“–static”,它在编译阶段就会把所有用到的库打包到自己的可执行程序中。 所以静态链接的优点是具有较好的兼容性,不依赖外部环境,但是生成的程序比较大。

换句话说说动态链接是告诉要执行的文件,要调用文件和函数的位置,并打包成可执行文件,当文件执行时,会根据链接时告诉的位置而调用其他相关函数,但当可执行文件链接和执行不是在相同的机子时则可能会因为在新的环境而找不到要调用文的位置而报错。但动态链接则是将执行文件和需要调用的文件打包在一起,所以生成的文件会比较大,而且换了机子也不会以为找不到要调用的文件而报错。

hello 可执行文件
gcc  hello.o -o hello1 -static

4.交叉编译器

我们编译时一般是在x86架构的电脑上,而编译的程序则是在arm架构的板子上运行。这种编译器和目标程序运行在不同架构的编译过程,被称为 交叉编译。

#在主机上执行如下命令安装交叉编译器
sudo apt install gcc-arm-linux-gnueabihf

#安装完成后使用如下命令查看版本
arm-linux-gnueabihf-gcc -v  或 arm-linux-gnueabihf-gcc --version

#用交叉编译器编译hello.c程序
arm-linux-gnueabihf-gcc hello.c –o hello

使有readelf查看交叉编译器生成的hello程序的目标架构、浮点类型、大小端等信息
readelf -a hello

我们安装的arm-linux-gnueabihf-gcc编译器,表示它的目标芯片架构为ARM,目标操作系统为Linux,使用GNU的C标准库即glibc,使用嵌入式应用二进制接口(eabi),编译器的浮点模式为硬浮点hard-float。而另一种名为arm-linux-gnueabi- gcc的编译器与它的差别就在于是否带“hf”,不带“hf”表示它使用soft-float模式。

字段含义
arch目标芯片架构
os操作系统
gnuC标准库类型
eabi应用二进制接口
hf浮点模式

目标芯片架构就是指交叉编译器生成的程序运行的平台,如ARM、MIPS,其中ARM交叉编译器又分为ARMv7、ARMv8及aarch64架构。i.MX 6ULL的内核为Cortex-A7,它使用的是ARMv7架构。 arm-linux-gnueabihf-gcc直接以arm表示ARMv7架构。
目标芯片的大小端模式,i.MX 6ULL使用的是小端模式。若是大端模式(big edian),编译器名字中会带“be”或“eb”字段进行标标注。
C标准库类型通常有gnu、uclibc等,分别表示GNU的glibc库和uclibc库,这取决于目标操作系统提供的C库类型,不过由于glibc和uclibc库是兼容的,所以开发者在编通常直接使用GNU类型的编译器而不管目标系统中的C库类型。
应用二进制接口(Application Binary Interface),描述了应用程序和操作系统之间或其他应用程序的低级接口。在编译器选项中主要有“abi”和“eabi”两种类型,abi通常用在x86架构上,而eabi表示embed abi,即嵌入式架构,如ARM、MIPS等。
浮点模式:部分ARM处理器带浮点运算单元,代码需要进行浮点运算时若交给fpu处理,可以加快运算速度。
(1) hard: 硬浮点类型(hard-float),采用fpu参与浮点运算。 arm-linux-gnueabihf-gcc、armeb-linux-gnueabihf-gcc都是硬浮点类型,即名字中带“hf”。

(2) soft:软浮点类型(soft-float),即使有fpu浮点运算单元也不用,而是使用软件模式,arm-linux-gnueabi-gcc、armeb-linux-gnueabi-gcc都是软浮点类型,即名字中不带“hf”。

(3) softfp:允许使用浮点指令,但保持与软浮点ABI的兼容性。

二、uboot

1.U-Boot 简介

(1)Linux 系统要启动先运行bootloader 程序,引导板子完成初始化。这段bootloader程序会先初始化DDR等外设,然后将Linux内核从flash(NAND,NOR FLASH,SD,MMC 等)拷贝到 DDR 中,最后启动 Linux 内核。bootloader 就相当于windows的 BIOS。
(2)uboot是一种bootloader,大部分板子有三种uboot:
在这里插入图片描述

2.U-Boot 编译安装过程

1.首先在 Ubuntu 中安装 ncurses 库,否则编译会报错

sudo apt-get install libncurses5-dev

2.将uboot压缩包拷到ubuntu中并解压

tar -vxjf uboot-imx-2016.03-2.1.0-g8b546e4.tar.bz2

3.创建mx6ull_alientek_nand.sh脚本并运行:

示例代码 30.2.2 mx6ull_alientek_nand.sh 文件代码
#!/bin/bash
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_ddr256_nand_defconfig
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4

mx6ull_alientek_nand.sh详解:sh脚本完成ARCH、CROSS_COMPILE 、mx6ull_14x14_ddr256_nand_defconfig参数的赋值,板子在加载编译好的uboot的,会执行makefile等文件时就知道了这些变量的值。
ARCH是指定架构,这里肯定是 arm
CROSS_COMPILE 用于指定编译器
distclean 表明这行语句的目的是清除工程
mx6ull_14x14_ddr256_nand_defconfig表明配置文件是哪一个
make -j12表明使用4核去编译uboot
V=1表示编译是信息的输出级别

4.Uboot的烧写与启动
使用 imxdownload 软件烧写,将 uboot.bin 烧写到 SD 卡中,然后通过 SD 卡来启动来运行 uboot。

chmod 777 imxdownload //给予 imxdownload 可执行权限,一次即可
./imxdownload u-boot.bin /dev/sdd //烧写到 SD 卡,不能烧写到/dev/sda 或 sda1 设备里面!

如果在倒计时结束以后没有按下回车键,那么 Linux 内核就会启动,Linux 内核一旦启动,uboot 就会寿终正寝。在板子启动倒计时3s内,可以按下回车键进入命令模式。

3.U-Boot 编译后的文件详解

U-Boot编译前文件夹中的内容
在这里插入图片描述
U-Boot编译后文件夹中的内容
在这里插入图片描述
U-Boot编译后文件夹中的一些文件夹和文件详解:
在这里插入图片描述在这里插入图片描述
我们在编译时的脚本文件中设置make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_ddr512_emmc_,实际上就是指定uboot选择arch文件夹中的arm文件夹、configs 文件夹中mx6ull_14x14_ddr256_nand_defconfig文件。

4.u-boot.imx文件的来源(烧到板子的最终文件)

built-in.o(链接)——ELF 格式的 u-boot(objcopy)——u-boot-nodtb.bin(拷贝)——u-boot.bin(添加头文件)——u-boot.imx

u-boot.bin:是通过.u-boot.bin.cmd指令拷贝 u-boot-nodtb.bin得到的。

u-boot-nodtb.bin:是通过.u-boot-nodtb.bin.cmd文件使用 objcopy 将 ELF 格式的 u-boot 文件转换为二进制的 u-boot-nodtb.bin 文件得到的。

u-boot:.u-boot.cmd 使用到了 arm-linux-gnueabihf-ld.bfd,也就是链接工具,使用 ld.bfd 将各个 built-in.o 文件链接在一起就形成了ELF 格式u-boot 文件。

u-boot.imx:如果我们要用 NXP 提供的 MFGTools 工具向开发板烧写 uboot,此时烧写的是 u-boot.imx文件,而不是 u-boot.bin 文件。u-boot.imx 是在 u-boot.bin 文件的头部添加了 IVT、DCD 等信息。这个工作是由文件.u-boot.imx.cmd 来完成的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值