Makefile & README文件分析

Makefile介绍

Makefile
    Makefile是一个工程管理文件,简化编译的流程,完成自动化编译的过程
    在Makefile中,会把编译的过程分为两步,先生成.o文件,再对.o文件链接,生成可执行文件

make工具
    make是一个GNU的工具,make会读入文件并完成自动化编译的过程,
    make默认读入文件是名为Makefile和makefile的文件,
    如果makefile和Makefile同时存在,默认读入makefile
    可以使用-f参数指定make工具的读入文件 ----->make -f Makefile clean

Makefile的语法规则
    Makefile由变量,函数和规则构成

Makefile中规则的构成
    目标:依赖
    <tab>指令

注意事项:
    1、一条规则必须有一个目标
    2、一个目标可以有多个依赖
    3、一条规则可以没有依赖,只完成相关的指令
    4、一条规则可以没有指令,只描述依赖关系    

第一版Makefile

all:fun      #一般Mkefile会有一个all目标
#该目标通常写在Makefile中的第一个位置,用于保证Makefile文件一定会生成一个可执行性文件

main.o:main.c
    gcc -c main.c -o main.o
fun:main.o fun.o
    gcc main.o fun.o -o fun
fun.o:fun.c
    gcc -c -o fun.o fun.c
clean:
    rm *.o fun

引入Makfile中的变量,赋值

=:递归赋值    ---->取变量最后一次的值
+=:追加赋值   ---->把值追加到原有值的后面,并带空格
:=:立即赋值   ---->在哪赋值在哪展开
?=:条件赋值   ---->如果前面出现过该变量,就不赋值否则赋值

Makefile中的自动变量,都是针对一条规则而言的
    $@:所有目标
    $^:所有依赖    
    $<:第一个依赖

第二版Makefile

EXE=fun     #定义EXE表示可执行文件名
OBJs+=main.o  #定义中间代码文件(二进制文件)
OBJs+=fun.o
CC=gcc      #定义编译器gcc为CC变量
CFLAGs=-c -g -o   #定义CFLAGs保存gcc的编译参数


all:$(EXE)      #一般Mkefile会有一个all目标
#该目标通常写在Makefile中的第一个位置,用于保证Makefile文件一定会生成一个可执行性文件

$(EXE):$(OBJs)
    $(CC) $^ -o $@
main.o:main.c
    $(CC) $(CFLAGs) $@ $^
fun.o:fun.c
    $(CC) $(CFLAGs) $@ $^
clean:
    rm $(OBJs) $(EXE)

第三版Makefile---->引入通配符

引入%通配符做模式匹配,能实现目标和依赖之间的唯一匹配关系

EXE=fun     #定义EXE表示可执行文件名
OBJs+=main.o  #定义中间代码文件(二进制文件)
OBJs+=fun.o
CC=gcc      #定义编译器gcc为CC变量
CFLAGs=-c -g -o   #定义CFLAGs保存gcc的编译参数


all:$(EXE)      #一般Mkefile会有一个all目标
#该目标通常写在Makefile中的第一个位置,用于保证Makefile文件一定会生成一个可执行性文件

$(EXE):$(OBJs)   
    $(CC) $^ -o $@
%.o:%.c
    $(CC) $(CFLAGs) $@ $^
clean:
    rm *.o $(EXE)

%.o:%.c ----->会根据上面规则提供的依赖文件,找到OBJs里面的所有.o文件
main.o ---->%会自动获取到main,并且继续匹配%.c--->%.c会被展开为main.c

引入内置函数

使用以下内置函数时,要求工作路径下,只存在可执行文件需要的.c文件
i)wildcard
获取当前工作路径下,所有满足格式的文件
$(wildcard 指定的文件格式)
$(wildcard *.c)    ----->获取当前路径下的所有.c后缀的文件
ii)patsubst
模式匹配,把指定格式符字符串替换为另一个格式
$(patsubst 模式1,模式2,要转换的字符串)
$(patsubst %c,%o,1.c 2.c 3.c····· )

第四版Makefile

把用wildcard找到的所有.c文件文件名,转换成.o的字符串

EXE=fun     #定义EXE表示可执行文件名
files=$(wildcard *.c)   #使用内置函数wildcard获取当前路径下的所有.c文件 
OBJs=$(patsubst %.c,%.o,$(files))
CC=gcc      #定义编译器gcc为CC变量
CFLAGs=-c -g -o   #定义CFLAGs保存gcc的编译参数


all:$(EXE)      #一般Mkefile会有一个all目标
#该目标通常写在Makefile中的第一个位置,用于保证Makefile文件一定会生成一个可执行性文件

$(EXE):$(OBJs)     #main.o  fun.o
    $(CC) $^ -o $@
%.o:%.c
    $(CC) $(CFLAGs) $@ $^

.PHONY:clean     #clean可以作为一个伪目标,这个目标不生成任何文件直接执行规则里的指令
clean:
    rm *.o $(EXE)

分析Makefile

# 指定交叉编译工具链前缀变量
CROSS_COMPILE = arm-linux-gnueabihf-
#指定文件名字变量
NAME = interface
#=============================================================================#
#-g:编译时添加gdb调试信息   -marm: 将程序编译生成arm指令集   -Wall:编译时显示所有警告信息 
#-O0:编译时添加优化等级 -O0:不优化 -O1:一级优化  
#-fno-builtin: 不使用linux操作系统,提供内置函数
#-nostdinc: 不可以包含linux操作系统提供的头文件
#-I:指定头文件路径
CFLAGS += -g -marm -Wall -O0 -mabi=apcs-gnu -mfpu=neon -mfloat-abi=softfp -fno-builtin \
            -nostdinc -I./common/include    -I./include 
#LD:链接命令
LD    = $(CROSS_COMPILE)ld
#CC:编译命令
CC    = $(CROSS_COMPILE)gcc
#NM:查看符号表信息
NM  = $(CROSS_COMPILE)nm
#OBJCOPY:生成二进制文件
OBJCOPY = $(CROSS_COMPILE)objcopy
#OBJDUMP:生成反汇编文件
OBJDUMP = $(CROSS_COMPILE)objdump
#============================================================================#
#wildcard是Makefile中内置函数
#功能:将指定目录下,指定文件以字符串格式进行展开,并用空格隔开
#参数:指定目录指定要展开文件
#返回值:展开后的结果
OBJSss     := $(wildcard start/*.S) $(wildcard common/src/*.S) $(wildcard *.S)\
           $(wildcard start/*.c) $(wildcard common/src/*.c)                \
           $(wildcard src/*.c) $(wildcard *.c) 
#patsubst是Makefile中内置函数
#功能:将指定目录下某种格式,替换成另外一种格式
#参数:1)源字符串格式 2)目标字符串格式 3)指定替换目录
#返回值:替换后的结果
OBJSs      := $(patsubst %.S,%.o,$(OBJSss))
OBJS     := $(patsubst %.c,%.o,$(OBJSs))

%.o: %.S 
    @echo "  AS      $@"
    @# $(CC): 使用arm-linux-gnueabihf-gcc命令
    @$(CFLAGS): 指定编译参数
    @#-c:只编译不链接  $<:第一个依赖  $^:所有依赖 -o: 起别名 $@:目标 
    @#将所有的.s文件根据指定参数,编译生成.o文件 
    @$(CC) $(CFLAGS) -c   $< -o $@

%.o: %.c
    @echo "  CC      $@"
    @$(CC) $(CFLAGS) -c  $<  -o $@

all:clean  $(OBJS)
    @echo "  LD      Linking $(NAME).elf"
    @#将所有的.o文件,根据map.lds,通过LD链接生成.elf文件
    @$(LD)  $(OBJS) -T map.lds -o $(NAME).elf

    @echo "  OBJCOPY Objcopying $(NAME).bin"
    @#将.elf文件,通过OBJCOPY生成.bin文件
    @$(OBJCOPY)  -O binary  $(NAME).elf $(NAME).bin 

    @echo "  MAP     Generating $(NAME).map"
    @#将.elf文件符号表信息,重定向到.map文件
    @$(NM) $(NAME).elf > $(NAME).map 

    @echo "  OBJDUMP Objdumping $(NAME).dis"
    @#将.elf文件,通过OBJDUMP生成反汇编文件,并且重定向到.dis文件
    @$(OBJDUMP) -DS $(NAME).elf > $(NAME).dis 

distclean clean:
    @rm -rf $(OBJS) *.elf *.bin *.dis *.map
    @echo "  CLEAN   complete."

install:
    sudo cp $(NAME).bin /mnt/hgfs/share/

uboot移植前准备工作/make <board_name>_deconfig执行过程

1.进入uboot源码目录下,打开README文件,分析如下内容        
        193 For all supported boards there are ready-to-use default
        194 configurations available; just type "make <board_name>_defconfig".
        
        对于所有支持的板,有现成的默认配置可用;只需键入“make <board_name>_defconfig”。
        总结:通过以上分析可知,需要确定<board_name>名字,执行make <board_name>_defconfig这条命令就可以
        问题:如何确定<board_name>?

2.在uboot源码顶层目录下,执行make fsmp1a_defconfig
    出现如下错误信息:
    ***
    *** Can't find default configuration "arch/../configs/fsmp1a_defconfig"! ===> 不能找到默认配置“arch/../configs/fsmp1a_defconfig”
    ***
3.进入uboot源码顶层目录下,进入configs目录下,查看和<board_name>_defconfig相关信息

4.在uboot源码顶层目录下,打开Mkaefile文件,搜索config,添加如下打印信息    
     563 %config: scripts_basic outputmakefile FORCE
    
     569     $(MAKE) $(build)=scripts/kconfig $@  ===> 打印信息内容:make -f ./scripts/Makefile.build obj=scripts/kconfig fsmp1a_defconfig
      分析执行语句:make -f ./scripts/Makefile.build obj=scripts/kconfig fsmp1a_defconfig ===> make obj=scripts/kconfig fsmp1a_defconfig    
5.如何可以查看打印信息内容:在uboot源码顶层目录下,执行make fsmp1a_defconfig 
6.进入uboot源码scripts/Kconfig目录下,打开Makefile文件,搜索:defconfig,添加如下内容打印信息
     %_defconfig: $(obj)/conf
         $< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig) 
    
      ====> 打印信息内容:scripts/kconfig/conf  --defconfig=arch/../configs/fsmp1a_defconfig Kconfig  
        scripts/kconfig/conf:elf可执行文件
        --defconfig=arch/../configs/fsmp1a_defconfig:目标
        Kconfig:存放默认板子相关配置信息  
        总结:conf是一个可执行文件,目标和板子相关配置信息作为参数传递给conf

  

uboot 非安全版本移植脚本文件

使用脚本进行烧写 ./sdtools /dev/sdb

make menuconfig执行过程

1.在uboot源码顶层目录下,打开Mkaefile文件,搜索menuconfig,发现无法找到目录,所以搜索config,找到目标之后,   
     563 %config: scripts_basic outputmakefile FORCE

     569     $(MAKE) $(build)=scripts/kconfig $@  ===> 打印信息内容:make -f ./scripts/Makefile.build obj=scripts/kconfig menuconfig

      分析执行语句:make -f ./scripts/Makefile.build obj=scripts/kconfig menuconfig
           ===> make obj=scripts/kconfig menuconfig    
2.如何可以查看打印信息内容:在uboot源码顶层目录下,执行menuconfig 
3.进入uboot源码scripts/Kconfig目录下,打开Makefile文件,搜索:menuconfig,添加如下内容打印信息
     34 menuconfig: $(obj)/mconf
                                                                                     
     39     $< $(silent) $(Kconfig) =====>  scripts/kconfig/mconf  Kconfig

4.如何可以查看打印信息内容:在uboot源码顶层目录下,执行menuconfig 
5.总结:make menuconfig执行内容 
    =====>  scripts/kconfig/mconf  Kconfig  
      
     scripts/kconfig/mconf :elf可执行文件
     Kconfig :存放默认相关图形化界面配置信息内容
     mconf是一个可执行文件,Kconfig作为参数传递给mconf,因为Kconfig文件存放默认相关图形化界面配置信息内容,所以执行这条命令,生成图形化界面信息

make all执行过程

1.在uboot源码顶层目录下执行: make V=1 all
//打印信息注解
  arm-linux-gnueabihf-objdump -t u-boot > u-boot.sym
      解释:将u-boot可执行文件,通过objdump生成反汇编文件,将反汇编文件重定向到u-boot.sym   
  arm-linux-gnueabihf-objcopy -O srec u-boot u-boot.srec
        解释:将u-boot可执行文件,通过objcopy命令,生成u-boot.srec文件  
./tools/mkimage -T stm32image -a 0xC0100000 -e 0xC0100000 -d u-boot.bin u-boot.stm32 >u-boot.stm32.log  && cat u-boot.stm32.log
        解释: mkimage - Generate image for U-Boot ====> 生成uboot镜像文件
            -T:设置镜像文件类型
            -a:设置加载地址
            -e:设置入口地址
            -d:指定使用哪一个镜像文件
     使用mkimage工具,设置镜像文件类型stm32image,指定加载地址和入口地址0xC0100000
     指定使用  u-boot.bin 和 u-boot.stm32 重定向到>u-boot.stm32.log文件 并且 回显u-boot.stm32.log文件内容
       cp u-boot-dtb.bin u-boot.bin ====> 解释:将u-boot-dtb.bin复制为u-boot.bin
       cat u-boot-nodtb.bin dts/dt.dtb > u-boot-dtb.bin  ==> 解释:将u-boot-nodtb.bin和dts/dt.dtb进行拼接,重定向到u-boot-dtb.bin
        make -f ./scripts/Makefile.build obj=dts dtbs ===> 编译dts目录下设备树相关内容

        make -f ./scripts/Makefile.build obj=arch/arm/dts dtbs ===>  编译arch/arm/dts目录下设备树相关内容
       arm-linux-gnueabihf-objcopy -O binary u-boot u-boot-nodtb.bin  ===> 将 u-boot可执行文件,通过objcopy生成u-boot-nodtb.bin
     arm-linux-gnueabihf-ld -Ttext 0xC0100000 -o u-boot -T u-boot.lds *.o
     解释:将uboot源码目录下所有的.o文件,根据 u-boot.lds文件,指定链接地址0xC0100000,生成u-boot可执行文件
       

TF-A 的 README文档

1、分析如下目录信息
    Compilation of TF-A (Trusted Firmware-A):
    1. Pre-requisite  ======> 准备工作
    2. Initialise cross-compilation via SDK  ======> 安装交叉编译工具链
    3. Prepare tf-a source code  ======> 准备tf-a源码
    4. Management of tf-a source code  ======> 管理tf-a源码
    5. Compile tf-a source code  ======> 编译tf-a源码
    6. Update software on board  ======> 烧写步骤
2、解压tf-a源码
     $> tar xfz tf-a-stm32mp-2.2.r2-r0.tar.gz  
3、进入tf-a源码目录       
     $> cd tf-a-stm32mp-2.2.r2  
4、在tf-a源码目录下,执行打补丁命令     
      $> for p in `ls -1 ../*.patch`; do patch -p1 < $p; done 
5、编译tf-a源码命令
     $> make -f $PWD/../Makefile.sdk all     
     或者
     $ make -f $PWD/../Makefile.sdk TFA_DEVICETREE=stm32mp157c-ev1 TF_A_CONFIG=trusted ELF_DEBUG_ENABLE='1' all
6、生成镜像文件路径,以及名字      
     #> ../build/*/tf-a-*.stm32

分析Linux的README文档

1.分析README文档目录 
    1. Pre-requisite  ======> 准备工作
    2. Initialise cross-compilation via SDK  ======> 安装交叉编译工具链
    3. Prepare kernelsource code  ======> 准备tf-a源码
    4. Management of kernelsource code  ======> 管理tf-a源码
    5. Compile kernel source code  ======> 编译tf-a源码
    6. Update software on board  ======> 烧写步骤
2.需要安装库
    sudo apt-get install u-boot-tools
    sudo apt-get install libyaml-dev   
3.解压内核源码
    $> tar xfJ linux-5.10.61.tar.xz
4.进入内核源码目录下
      $> cd linux-5.10.61
5.打补丁命令            
     $> for p in `ls -1 ../*.patch`; do patch -p1 < $p; done  
6.配置补丁文件列表相关配置信息
     $ make ARCH=arm multi_v7_defconfig fragment*.config    
7. 编译内核源码的命令  
    $ make ARCH=arm uImage vmlinux dtbs LOADADDR=0xC2000000     
    解释:
        ARCH=arm :指定架构为arm架构    
        uImage:编译生成uImage镜像文件  
        vmlinux:内核源码目录下elf可执行文件  
        dtbs:编译设备树
        LOADADDR=0xC2000000  :指定加载地址     
8.内核采用模块化方式进行编译
     $ make ARCH=arm modules 
9. 产生镜像文件名字和位置
        uImage镜像文件:$PWD/arch/arm/boot/uImage  
        设备树镜像文件:$PWD/arch/arm/boot/dts/st*.dtb

驱动开发 动态编译的内核模块的Makefile

#定义变量存放内核源码顶层路径
#KERNELDIR:= /home/ubuntu/linux-5.10.61   #用于编译生成ARM架构的模块
KERNELDIR := /lib/modules/$(shell uname -r)/build  #用于生成x86架构的模块
#定义变量保存模块化编译的文件的路径
PWD:= $(shell pwd)
all:
#make modules是模块化编译的命令
#make -C $(KERNELDIR)表示读取KERNELDIR路径下的Makefile进行make编译
#M=$(PWD)指定模块化编译的路径
    make -C $(KERNELDIR) M=$(PWD) modules
clean: #编译清除
    make -C $(KERNELDIR) M=$(PWD) clean

obj-m:=demo.o  #指定将demo.o独立链接生成内核模块文件

驱动开发 动态编译的内核模块的Makefile通用版本

使用这个Makefile编译的时候可以在命令行指定编译的架构以及编译的模块名

modname?=demo  #给定一个默认的模块名
arch?=arm #给定一个架构的模块名
ifeq ($(arch),arm)#判断要编译的架构进而使用不同的Makefile规则进行编译
#定义变量存放内核源码顶层路径
KERNELDIR:= /home/ubuntu/linux-5.10.61   #用于编译生成ARM架构的模块
else
KERNELDIR := /lib/modules/$(shell uname -r)/build  #用于生成x86架构的模块
endif

#定义变量保存模块化编译的文件的路径
PWD:= $(shell pwd)
all:
#make modules是模块化编译的命令
#make -C $(KERNELDIR)表示读取KERNELDIR路径下的Makefile进行make编译
#M=$(PWD)指定模块化编译的路径
    make -C $(KERNELDIR) M=$(PWD) modules
clean: #编译清除
    make -C $(KERNELDIR) M=$(PWD) clean

obj-m:=$(modname).o  #指定将demo.o独立链接生成内核模块文件

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值