• 334查看
  • 0回复

[Autosar] AUTOSAR入门-AS开源代码编译过程详解

[复制链接]


该用户从未签到

发表于 3-3-2024 09:00:30 | 显示全部楼层 |阅读模式

汽车零部件采购、销售通信录       填写你的培训需求,我们帮你找      招募汽车专业培训老师


AUTOSAR入门-AS开源代码编译过程详解

AUTOSAR入门-AS开源代码编译过程详解w1.jpg

拿到一份完整的软件代码,面对成千上万的源码文件,都会觉得有点无从下手。这时候软件对你来说像一个黑盒子,里面有什么你不知道,想最快速的了解这个盒子里面有什么,就要去研究这个盒子怎么造出来的,反推第一步也就是编译的过程。分析代码编译过程,我自己总结有下面几点好处:

    确定那些源码参与了编译,俗话说顺藤摸瓜,编译就是藤顺着走,有几个瓜,啥样都会清楚。

    要对代码进行修改移植调试必须要了解编译的过程,要具有再造能力。

    很多中间代码的生成放在了编译过程,直接看代码是不完整的,像残缺的武功秘籍,缺失的部分需要在编译里面找。


1.  Scons编译工具介绍

AUTOSAR入门-AS开源代码编译过程详解w2.jpg

     首先我们回顾下AS代码编译的过程,参考:AUTOSAR入门-AS开源代码运行环境搭建中2.2节代码编译过程:
git clone https://github.com/thatway1989/ascd assconsexport BOARD=x86export RELEASE=ascorescons
注意:如果你环境还没配置好,AS代码还没编译通过,可能你是伪程序员,建议不用往下看了,本系列文章强调动手调试,直接研究代码,搞代码才能有无穷乐趣,,All is in the code.  Code can tell you everything。

可以看到编译的过程一直在用scons命令,那么scons是什么,下面进行介绍。

1.1 Scons介绍

      文章封面中编译器可以把c语言文件编程二进制,例如:gcc hello.c -o hello

但是对于大型工程项目,有很多c文件要一块编译成一个二进制文件,就需要制定一个编译规则,规定那些文件参与编译,怎么去编译,这时有人会想到makefile,的确makefile是干这个事的,但是时过境迁,很多懒人觉得makefile太麻烦了,makefile中的代码需要写的太多,能不能智能化一点,不关注过程,直接关注结果,过程让机器去搞,这样就可以少写一点编译脚本,然后就进化出来两个方向:

第一种 (cmake) 你makefile麻烦,我造一个工具例如cmake来生成makefile,cmake脚本里面只关心要编译那些文件,编译出来的目标文件是什么,其他cmake工具去搞定;

第二种(scons)你makefile麻烦,我不用你了,直接重新搞一套例如scons,直接调用编译器,同样达到cmake那些简单方便。另外scons的语法不是自己定义的,直接使用的python,对python程序员很友好。可以理解scons脚本实际就是python脚本。

2.2 Scons使用基础

AUTOSAR入门-AS开源代码编译过程详解w3.jpg

上面说到scons脚本里面都是用的python语言,scons基于python封装了一些库函数,下面挑一些主要的进行简单介绍

Program函数:

src_files=Split('main.cpp file1.cpp  file2.cpp')

Program('program', src_files)

Program函数规定编译的目标文件,这里为program,规定了要编译的源文件,这里为src_files 这个集合。

SConscript函数:

在配置文件SConstruct中可以使用函数SConscript()函数来定附属的配置文件。例如:objs = SConscript('SConscript',variant_dir=BDIR,duplicate=0)

当然这里SConscript是配置文件,是用python语法写的,也可以随意命名。

Env环境:

构造Env环境,一个环境就是一些变量的集合。例如:

Env['CC']='arm-none-eabi-gcc -std=gnu99'

Env是一个变量集合,其中一个名为CC的变量值是gcc编译器。

参考scons官网文档:https://scons.org/doc/production/PDF/scons-user.pdf

2.  scons命令编译过程

2.1 SConstruct和building.py

执行scons命令的时候,首先会执行根目录下as/SConstruct,整体的执行流程为

PrepareEnv-》Conscript-》building

首先给sys添加了环境变量,方便直接访问这个目录
studio=os.path.abspath('./com/as.tool/config.infrastructure.system/')sys.path.append(studio)from building import *asenv = PrepareEnv()
from building是python语法从building这个包里面加载类,这个包的位置在

./com/as.tool/config.infrastructure.system/building.py

所以PrepareEnv函数就是在这个building.py里面声明的。进入这个函数,

ASROOT变量没赋值,先找到值
asenv=Environment(TOOLS=['ar', 'as','gcc','g++','gnulink'])os.environ['ASROOT'] = ASROOTasenv['ASROOT'] = ASROOT

构造环境asenv,然后把ASROOT变量加进去

同时把ASROOT也加到了os.environ里面
  BOARD = os.getenv('BOARD')if(BOARD not in board_list):print('Error: no BOARD  specified!')help()exit(-1)
检查系统环境变量里面有BOARD设置没,没设置就会提醒:

AUTOSAR入门-AS开源代码编译过程详解w4.jpg

在com/as.tool/config.infrastructure.system/building.py中,PrepareEnv函数的最后
PrepareBuilding(asenv)return asenv

PrepareBuilding函数,
GetConfig('%s/.config'%(env['BDIR']),env)
之后添加了一些变量,和一些选项打印出来第一个参数为:as/build/posix/x86/ascore/.config,没这个文件
AddOption('--menuconfig',        dest = 'menuconfig',        action = 'store_true',default = False,        help = 'make menuconfig for  Automotive Software AS')
如果使用scons --menuconfig命令,则下面这个if就会进去,执行menuconfig函数,进行系统配置,详细说明见2.5使用AddOption函数定义自己的命令行选项。
if(GetOption('menuconfig')):        menuconfig(env)
获取环境变量后,就开始执行SConscript函数,后面详细介绍最后还回到as/SConstruct,PrepareEnv()执行完,
objs = SConscript('SConscript',variant_dir=BDIR, duplicate=0)
objs就是要编译的文件的集合,读取objs完毕后,执行编译
Building(target,objs)
这个Building函数还是在com/as.tool/config.infrastructure.system/building.py中定义target打印出来为:as/build/posix/x86/ascore/x86

Building函数中,首先对sobjs中要编译的文件,进行了分类:arxml、xml、py、dts、其他。

2.2 SConscript生成objs

根目录下SConscript文件,如下
from building import *objs = SConscript('com/SConscript')objs += SConscript('release/SConscript')Return('objs')

可以知道,这个脚本是一个嵌套格式,就是把要编译的文件加入到objs里面

AUTOSAR入门-AS开源代码编译过程详解w5.jpg

如果想加入一个功能,需要修改这个脚本,让源码文件能编译进去。

2.3 arxml生成LCfg文件

这个流程也是xml生成c源码的过程,Building函数中,如下对arxml进行了处理
if( ( (not os.path.exists(cfgdone)) and (not GetOption('clean')) )or forceGen ):  MKDir(cfgdir)  RMFile(cfgdone)  xcc.XCC(cfgdir, env, True)if(arxml != None):      arxmlR = PreProcess(cfgdir, str(arxml))for xml in xmls:           MKSymlink(str(xml),'%s/%s'%(cfgdir,os.path.basename(str(xml))))      xcc.XCC(cfgdir)       argen.ArGen.ArGenMain(arxmlR,cfgdir)  MKFile(cfgdone,  SHA256(glob.glob('%s/*xml'%(cfgdir))))
先判断cfgdone:as/build/posix/x86/ascore/config/config.done是否存在,不然不存在,则上面代码是对arxml的处理

新建文件夹cfgdir:as/build/posix/x86/ascore/config--生成代码位置

xcc.XCC(cfgdir, env, True)函数在xcc.py中定义
fp = open('%s/asmconfig.h'%(gendir),'w')fp.write('#ifndef _AS_MCONF_H_\n\n')if('MODULES'in env and env['MODULES'] isnotNone):for m in env['MODULES']:        fp.write('#ifndef  USE_%s\n#define USE_%s 1\n#endif\n\n'%(m,m))if('CONFIGS'in env and env['CONFIGS'] isnotNone):
根据env里面MOUDLES生成宏例如:#defineUSE_ARCH_X86 1

根据env里面CONFIGS生成宏例如:#define ARCHx86写入asmconfig.h文件中。

最后,XCC函数里面还执行了两个生成函数
from argen.KsmGen import *from argen.OsGen import *__gen__ = [KsmGen,OsGen]for g in __gen__:    print('  %s ...'%(g.__name__))    g(gendir)
OsGen在argen/OsGen.py中定义,这里因为没有xml文件,没有生成os的cfg文件KsmGen在argen/KsmGen.py中定义,生成ksm_cfg.h

上面的过程可以理解为python代码生成.h代码的过程。

PreProcess(cfgdir, str(arxml))函数中arxdml打印出来为:com/as.application/common/autosar.arxml--xml文件位置

filR:as/build/posix/x86/ascore/config/autosar.arxml

filC:as/build/posix/x86/ascore/config/autosar.arxml.h为一个链接文件
autosar.arxml.h ->/home/XXX/autosar/as/com/as.application/common/autosar.arxml

执行命令:
gcc -E --include/home/XXX/autosar/as/build/posix/x86/ascore/config/asmconfig.h/home/XXX/autosar/as/build/posix/x86/ascore/config/autosar.arxml.h
GCC -E选项:对源程序做预处理操作,但是没有-o参数,就没有输出到目标文件。但是以字符串的形式存储到了txt变量里面

err, txt = RunSysCmd(cmd)

简单处理,去掉#注释后存入了filR:as/build/posix/x86/ascore/config/autosar.arxml文件
for xml inxmls:     MKSymlink(str(xml),'%s/%s'%(cfgdir,os.path.basename(str(xml))))
lwip.xml -> /home/XXX/autosar/as/com/as.application/common/config/lwip.xmlas/build/posix/x86/ascore/config/目录下的xml文件都建立了软连接到对应的xml文件
argen.ArGen.ArGenMain(arxmlR,cfgdir)#生成config.done文件MKFile(cfgdone, SHA256(glob.glob('%s/*xml'%(cfgdir))))
argen.ArGen.ArGenMain函数在argen/ArGen.py中定义
defArGenMain(wfxml,gendir):import xml.etree.ElementTree as  ETif(os.path.exists(wfxml)):        root =  ET.parse(wfxml).getroot();for arxml in root:            ArGen(arxml,gendir)
找一个简单的模块,例如Eawfxml是autosar.arxml,对这个文件进行xml解析,找到tag,就子目录的标识
<Ea><GeneralComment="*"DevelopmentErrorDetection="ON"NvmJobEndNotification="NULL"NvmJobErrorNotification="NULL"SetModeApi="ON"VersionInfoApi="OFF"VirtualPageSize="8" /><BlockListMax="TBD"><BlockArraySize="2"BlockSize="32"Comment="*"ImmediateData="False"IsArray="False"Name="EaTest1"NumberOfWriteCycles="0xFFFFFFFF" /><BlockArraySize="2"BlockSize="32"Comment="*"ImmediateData="False"IsArray="False"Name="EaTest2"NumberOfWriteCycles="0xFFFFFFFF" /></BlockList></Ea>
--》engine(arxml,dir)ArGen函数调用

--》‘Ea':GenEa

在argen/GenEa.py中,
defGenEa(root,dir):global __dir    GLInit(root)    __dir = '%s'%(dir)if(len(GLGet('BlockList')) ==  0):return    GenH()    GenC()    print('    >>> Gen Ea DONE <<<')
GLInit函数在argen/GCF.py中定义
defGLInit(root):global __root    __root=root
如果没有BlockList,则推出。我们查看arxml文件里面Ea下有这个的。GLGet也在argen/GCF.py中定义,作用是找到xml里面的某项

先看GenC()生成Ea_Cfg.c文件
fp =  open('%s/Ea_Cfg.h'%(__dir),'w')    fp.write(GHeader('Ea'))
整个过程就是根据arxml里面的生成c文件的,这里业务部分不具体分析了。GHeader在argen/GCF.py中定义,用于生成版权文件头部分。

生成代码的位置为:./build/posix/x86/ascore/config/Ea_Cfg.c

GenH()也是同样的过程。

在Building函数中,如下定义了studio命令的处理方法,后续文章再详细分析
if(('studio'in COMMAND_LINE_TARGETS) and (env == Env)):     studio=os.path.abspath('%s/com/as.tool/config.infrastructure.system/'%(env['ASROOT']))  assert(arxml)    pd = os.path.abspath(cfgdir)    RunCommand('cd %s && %s  studio.py %s'%(studio,env['python3'],pd))       exit(0)
2.4 DTS、OFS、SWCS编译

BuildDTS(dts,BDIR)print('!!!Building ofs',)BuildOFS(ofs)print('!!!Building swcs',)BuildingSWCS(swcs)
从打印上看,没有dts of和py文件文件,所以上面上个函数都没文件要处理。

在building函数的结尾,会定义默认编译为可以执行文件:
if(BUILD_TYPE == 'exe'):    env.Program(target, objs)
objs是SConscript生成的,分析见2.2中,objs里面还添加了生成的cfg文件。target打印出来为:as/build/posix/x86/ascore/x86

2.5 生成TINIX.IMG

scons读完脚本后,就会去编译目标文件x86,这个过程是编译器gcc完成的
scons: done reading SConscript files.scons: Building targets ...scons: building associated VariantDir targets: build/posix/x86/ascore
会用gcc编译器对objs里面出现的c文件进行编译成o文件,最后进行链接为x86目标文件。

编译出来x86目标文件后,还执行了几个操作,在AddPostAction中定义。

AddPostAction:scons中的库函数,安排在构建指定目标之后执行的指定操作命令。如下:
if('POSTACTION'in env):for action in env['POSTACTION']:        env.AddPostAction(target, action)
target 为:as/build/posix/x86/ascore/x86

action 打印出来为:
dd if=/dev/zero of=TINIX.IMG bs=512 count=2880/home/XXX/autosar/as/com/as.infrastructure/system/fs/fatfs/fatfs.exe  mkfs TINIX.IMGdd conv=notrunc if=/home/XXX/autosar/as/com/as.infrastructure/arch/x86/boot/boot.bin  of=TINIX.IMG bs=512 count=1/home/XXX/autosar/as/com/as.infrastructure/system/fs/fatfs/fatfs.exe  cp /home/XXX/autosar/as/com/as.infrastructure/arch/x86/boot/loader.bin  /loader.bin TINIX.IMGobjcopy -S build/posix/x86/ascore/x86  kernel.bin/home/XXX/autosar/as/com/as.infrastructure/system/fs/fatfs/fatfs.exe  cp kernel.bin /kernel.bin TINIX.IMG
dd 可从标准输入或文件中读取数据,根据指定的格式来转换数据,再输出到文件、设备或标准输出。进行制作文件系统,最后形成IMG文件。

? if=文件名:输入文件名,默认为标准输入。即指定源文件。

? of=文件名:输出文件名,默认为标准输出。即指定目的文件。

? bs=bytes:同时设置读入/输出的块大小为bytes个字节。

? count=blocks:仅拷贝blocks个块,块大小等于ibs指定的字节数。

if=/dev/zero,就是创建一个新的文件,块大小为512个字节,有2880个块。

文件大小计算:2880*512/1024/1024=1.4M

FatFs是一个用于小型嵌入式系统的通用FAT/exFAT文件系统模块。下载下来在download/ff13文件夹下。

conv=notrunc:不截断输出文件。把boot.bin放到TINIX.IMG结尾

objcopy -S :不从源文件拷贝符号信息和relocation信息。

fatfs.exe cp命令,把二进制文件复制进IMG文件

生成的TINIX.IMG有三部分:boot.bin、loader.bin、x86-》kernel.bin

TINIX.IMG 镜像文件,怎么在qemu里面加载运行,涉及那部分代码,这里篇幅有限,下次更新了再详细说明。

后记:

     首先感谢各位的关注,这里也不搞什么圈粉变现什么的,就是开源软件分享。说点感悟,用微信公众号来写文章,主要还是得用口语化的语言,图文并茂,方便轻松的去阅读。所以基本都是先不看其他的资料,先凭自己的理解口语化的表述出来,其实挺费时间,但这感觉可以锻炼表达能力,写作风格还是:口语化表述+code讲解。

Talk is cheap,show methe code,持续更新,纯干货分享,无广告,不打赏,欢迎转载,欢迎评论交流!

往期回顾:

AUTOSAR入门-江湖

AUTOSAR入门-AS开源代码运行环境搭建


该用户从未签到

发表于 14-3-2025 14:28:00 | 显示全部楼层
关于AUTOSAR开源代码的编译过程详解,以下是我的专业回复:

编译AUTOSAR开源代码是了解软件架构、模块间关系及代码结构的关键步骤。首先,需准备相应的编译环境及工具链。接着,按照项目提供的编译指南进行配置,包括编译器设置、路径配置等。进入编译过程,会产生中间文件,如目标文件、链接脚本等。通过分析编译过程,可确定哪些源码参与编译,了解模块间的依赖关系。此外,对于代码的修改、移植和调试,了解编译过程至关重要。总之,深入研究AUTOSAR开源代码的编译流程,有助于更高效地理解代码结构、进行功能修改及优化。
回复 支持 反对

使用道具 举报



该用户从未签到

发表于 14-3-2025 14:28:00 | 显示全部楼层
关于AUTOSAR开源代码的编译过程详解,以下是对其入门及编译过程的简要介绍:

首先,获取AUTOSAR开源代码后,需了解其结构。编译过程大致如下:

1. 配置编译环境,包括安装编译器、构建工具等。
2. 阅读相关文档,了解代码的组织结构、模块划分等。
3. 根据项目需求,配置编译参数,如编译器选项、路径等。
4. 运行编译命令,生成中间文件和目标文件。此过程中会生成一些中间代码,有助于理解代码逻辑。
5. 分析编译输出,了解哪些源码参与了编译,以及编译过程中的依赖关系。
6. 若需修改或移植代码,了解编译过程有助于快速定位问题并进行调试。

总之,研究AUTOSAR开源代码的编译过程,有助于快速了解代码结构、模块划分及依赖关系,为后续的修改、移植和调试工作奠定基础。
回复 支持 反对

使用道具 举报



该用户从未签到

发表于 14-3-2025 14:28:00 | 显示全部楼层
针对您提到的AUTOSAR入门及AS开源代码编译过程详解,作为汽车工程师,我理解其重要性。关于编译过程,确实是一个深入了解软件结构的关键环节。针对您提出的几点好处,我有以下专业回复:

首先,通过研究编译过程,可以确定哪些源码文件被纳入编译,为后续的工作(如代码分析、功能测试等)提供明确方向。其次,对于代码的修改和移植,了解编译流程至关重要,这有助于我们快速定位问题并进行调试。再者,编译过程中会生成许多中间代码,这些代码对于完整理解软件逻辑至关重要,如同补全武功秘籍。

在实际操作中,建议从搭建开发环境开始,熟悉编译器及其配置。接着,按照编译流程逐步分析,从源文件到目标文件的转换过程。此外,还可以结合AUTOSAR的架构和标准,深入理解其在编译过程中的作用和影响。这样,您就能更好地掌握AUTOSAR开源代码的编译过程,为后续的开发和调试工作打下坚实的基础。
回复 支持 反对

使用道具 举报



该用户从未签到

 楼主| 发表于 14-3-2025 14:28:00 | 显示全部楼层
关于AUTOSAR开源代码的编译过程详解,以下是对其入门及编译过程的简要介绍:

首先,获取AUTOSAR开源代码后,需了解其结构。编译过程分为几个主要步骤:配置、预处理、编译、链接等。通过编译过程,可以确定哪些源码参与了编译,以及中间文件的生成情况。

对于初学者,建议首先了解AUTOSAR架构及代码组织方式。然后,按照官方文档或教程进行编译环境配置,如安装编译器、配置工具链等。接着,根据编译指令或脚本进行编译,了解每一步的输出和结果。

分析编译过程有助于理解代码逻辑和架构,对于修改、移植和调试代码至关重要。同时,这也是了解和掌握AUTOSAR开发流程的基础。

希望以上内容能为您入门AUTOSAR提供帮助。如需更详细的信息,建议查阅AUTOSAR官方文档或相关教程。
回复 支持 反对

使用道具 举报

快速发帖

您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|手机版|小黑屋|Archiver|汽车工程师之家 ( 渝ICP备18012993号-1 )

GMT+8, 19-8-2025 18:03 , Processed in 0.316828 second(s), 40 queries .

Powered by Discuz! X3.5

© 2001-2013 Comsenz Inc.