博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
将模块代码量精简为2%的实践
阅读量:5326 次
发布时间:2019-06-14

本文共 8401 字,大约阅读时间需要 28 分钟。

 

说明

     本文通过目录和代码两个层面分析某产品xDsl驱动模块代码,将其精简为原始代码量的2%。

 

一  完整代码

     某产品xDsl驱动模块目录结构如下所示。其中,二级目录Lxx1通常为芯片厂家代码,Lxx2为自定义适配代码。

     ├─L010

     │  ├─include

     │  └─source

     ├─L020

     │  ├─include

     │  ├─source

     …… ……

     ├─L200

     │  ├─L210

     …… ……

     │  ├─L260

     │  │  ├─L261

     │  │  │  ├─include

     │  │  │  └─source

     │  │  └─L262

     │  │      ├─include

     │  │      └─source

     …… ……

     │  └─SELT_DELT

     │      ├─include

     │      └─source

    该产品xDsl模块存在大量已废弃的目录,而在用的目录中也存在大量无用的代码。

 

二  精简代码

     此处“精简”意指直接剔除无用代码,而非借助重构等手段来削减代码量。精简主要分为两个步骤:1. 分析makefile文件,清理不予编译的目录;2. 分析预编译宏,删除当前在用目录中无用的代码。

2.1 清理废弃目录

     lnxmkdep.ini文件中定义各编译目录(待编译代码所在目录),xDSL驱动目前用于编译的代码目录如下: 

1 [DSLADDR] 2 USE=YES 3 PATH=../../../xDSL/L030 4 COPT_EXTRA= 5 DEPEND_MODULES= all 6  7  8 [L261] 9 USE=YES10 PATH=../../../xDSL//L200/L260/L26111 COPT_EXTRA=12 DEPEND_MODULES= all13 14 [L262]15 USE=YES16 PATH=../../../xDSL//L200/L260/L26217 COPT_EXTRA=18 DEPEND_MODULES= all19 20 [L271]21 USE=YES22 PATH=../../../xDSL//L200/L270/L27123 COPT_EXTRA=24 DEPEND_MODULES= all25 26 [L272]27 USE=YES28 PATH=../../../xDSL//L200/L270/L27229 COPT_EXTRA=30 DEPEND_MODULES= all31 32 [L290]33 USE=YES34 PATH=../../../xDSL//L200/L29035 COPT_EXTRA=36 DEPEND_MODULES= all37 COPT_EXTRA=38 DEPEND_MODULES= all39 40 [SELTDELT]41 USE=YES42 PATH=../../../xDSL/L200/SELT_DELT43 COPT_EXTRA=-Os44 DEPEND_MODULES= all
Listed Directories

     结合头文件包含情况,可知编译需要L010、L030、L200(L210、L230、L260、L270、L290、SELT_DELT)目录。进一步分析得知,仅用到L210和L230目录的若干头文件,而L260目录存在同名头文件且版本更新,故可替代前两个目录。同时,L270目录用于提供30A功能,而当前产品不需要支持该功能,故可删除。

    此时,在用的目录已精简为L010、L030、L200(L260、L290、SELT_DELT)。

2.2 删除无用代码

    xDsl驱动代码中包含对于其他各种单板和功能的支持,而多数单板已不再使用,某些功能也并未使用。这些支持在代码中主要通过预处理宏(即#if、#ifdef、#ifndef、#elif等含"#+if"关键字的条件编译语句,统称为#if语句)来控制,例如fsap_prj.h文件定义功能宏(INSTALL_MAP_BONDING等),config.mak文件定义编译宏(_INSTALL_VSLC等),其他宏定义则分散于xDsl目录下各文件中。

     删除无用代码,即寻找哪些控制编译的宏未定义,并将其控制的代码删除。但鉴于宏定义的分散性,人工查找和删除条件编译分支显然不现实,必须借助自动化工具。

     通过工具剔除未使用的条件编译分支,其原理如下:

     1. 在待处理代码(*.c、*.h)中#if语句句首插入gcc扩展的预编译头#warning。

     2. 编译待处理代码获取gcc编译输出并进行分析。

     3. 编译结果中”#warning”警告所对应的#if语句为TRUE,即所控制的代码段正在使用,应予保留;反之可删除。

     开源工具stripcc可较好地完成上述工作。在小工程上试用效果符合期望,但应用到本产品时似乎出现死锁,无法正常工作。该问题在研读和调试其源代码后仍未解决。

     以下将基于相同工作原理,借助Python脚本处理,分析预编译宏,标记在用的#if代码段。处理后的源代码示例如下(剔除/*TRUE*/ 标记后即为原始代码):

1 #define BCM_BONDING_ENABLED 2 #define BCM_ENABLED 3  4 /*TRUE*/ #ifdef BCM_BONDING_ENABLED 5          CodeLine1; 6 #endif 7  8 #ifdef BCM_DISABLED 9           CodeLine2;10 /*TRUE*/ #elif defined BCM_ENABLED11           CodeLine3;12 #else13         #error Defination of BCM_DISABLED or BCM_ENABLED is Required!14 #endif15 16 #ifdef BCM_TEST17       CodeLine4;18 /*TRUE*/ #else19       CodeLine5;20 #endif
Processed Code

     其中,若#if句前出现:

  • 一个/*TRUE*/:表示该#if句为逻辑真;
  • 多个/*TRUE*/:多出现于被广泛引用的头文件内,每次引用对为真的#if处增加一个/*TRUE*/;
  • 没有/*TRUE*/:表示该#if句为逻辑假。

     注意,若某文件“期望”出现/*TRUE*/ 标记(如#ifndef <头文件宏>)但未出现,则该文件很可能并未编译——可用于甄别无用的文件。

 

    【脚本示例】文件布局如下:

 

     其中,AddWarnsEx.py对源代码添加预编译头#warning。

1 #!/usr/bin/python 2 # -*- coding: utf-8 -*- 3  4 import os, re 5  6  7 CodeDirName = r"E:\ValidMacroExample" 8  9 def AddWarnToFile(strPath):10     OrigFd = open(strPath)11     BackFd = open(strPath+"b", 'w+')12 13     OrigLineNo = 0;14     while(1):15         CurCodeLine = OrigFd.readline()16         OrigLineNo = OrigLineNo + 117         if(len(CurCodeLine) == 0):18             break;19 20         BackFd.write(CurCodeLine)21         MacthRes = re.compile(".*#\s*(el|if).*").match(CurCodeLine)22         if MacthRes != None:23             InsertCodeLine = "#warning Reach code " + '
'+ '
' + "\n";24 BackFd.write(InsertCodeLine)25 26 OrigFd.close()27 BackFd.close()28 return29 30 31 def SwapFileStatus(strPath):32 os.rename(strPath, strPath+'t')33 os.rename(strPath+'b', strPath)34 os.rename(strPath+'t', strPath+'b')35 return36 37 38 def DirTravel(DirPath):39 40 #遍历目录中的文件41 if os.path.isdir(DirPath) == True:42 FileList = os.listdir(DirPath)43 else:44 FileList = [os.path.basename(DirPath)]45 46 if FileList != []:47 for File in FileList:48 #检查目录名或文件名49 if os.path.isdir(DirPath) == True:50 FilePath = DirPath + os.sep + File51 else:52 FilePath = DirPath53 54 #文件类型为目录,递归55 if os.path.isdir(FilePath) == True:56 DirTravel(FilePath)57 continue58 59 #识别C文件和H文件60 SplitList = File.split('.')61 #忽略无后缀名的文件62 if len(SplitList) < 2:63 continue64 FileType = SplitList[-1]65 if FileType == 'c' or FileType == 'h':66 AddWarnToFile(FilePath)67 SwapFileStatus(FilePath)68 return69 70 71 DirTravel(CodeDirName)
AddWarnsEx

     ChkMacrosEx.py分析编译结果并标记为真的#if语句。

1 #!/usr/bin/python 2 # -*- coding: utf-8 -*- 3  4  5 import os, re 6  7 CodeDirName = r"E:\ValidMacroExample" 8 WarnFileName = CodeDirName + r"\Warns.txt" 9 10 11 def RestoreFileStatus(strPath):12     os.remove(strPath)13     os.rename(strPath+'b', strPath)14     return15 16 17 def ValidMacroInFile():18     Fd = open(WarnFileName, 'r')19 20     while(1):21         CurCodeLine = Fd.readline()22         if(len(CurCodeLine) == 0):23             break;24 25         MacthRes = re.compile(".*#warning.*
").match(CurCodeLine)26 if MacthRes != None:27 #根据编译警告信息打开相应的源文件(MacthRes.group(1)),修改相应行(MacthRes.group(2))28 #全文读入,修改一行,全文写入。同一文件内多行#warning时,效率较低29 SrcFd = open(MacthRes.group(1), 'r')30 FileLines = SrcFd.readlines()31 ModLineNo = int(MacthRes.group(2))-132 FileLines[ModLineNo] = "/*TRUE*/ " + FileLines[ModLineNo]33 SrcFd.close()34 35 SrcFd = open(MacthRes.group(1), 'w')36 SrcFd.writelines(FileLines)37 SrcFd.close()38 39 Fd.close()40 return41 42 43 def RemoveBackFile(DirPath):44 45 #遍历目录中的文件46 if os.path.isdir(DirPath) == True:47 FileList = os.listdir(DirPath)48 else:49 FileList = [os.path.basename(DirPath)]50 51 if FileList != []:52 for File in FileList:53 #检查目录名或文件名54 if os.path.isdir(DirPath) == True:55 FilePath = DirPath + os.sep + File56 else:57 FilePath = DirPath58 59 #文件类型为目录,递归60 if os.path.isdir(FilePath) == True:61 RemoveBackFile(FilePath)62 continue63 64 #识别C文件和H文件65 SplitList = File.split('.')66 #忽略无后缀名的文件67 if len(SplitList) < 2:68 continue69 FileType = SplitList[-1]70 if FileType == 'c' or FileType == 'h':71 RestoreFileStatus(FilePath)72 #os.remove(FilePath)73 return74 75 76 RemoveBackFile(CodeDirName)77 ValidMacroInFile()
ChkMacrosEx

     Macro.c等为待处理的C源文件。

1 //Macro.c(dir1) 2 #define BCM_BONDING_ENABLED 3 #define BCM_ENABLED 4  5 #ifdef BCM_BONDING_ENABLED 6       CodeLine1; 7 #endif 8  9 #ifdef BCM_DISABLED10       CodeLine2;11 #elif defined BCM_ENABLED12       CodeLine3;13 #else14       #error Defination of BCM_DISABLED or BCM_ENABLED is Required!15 #endif16 17 #ifdef BCM_TEST18       CodeLine4;19 #else20       CodeLine5;21 #endif22 23 24 //Macro1.c(dir2)25 #define BCM_BONDING_ENABLED26 #define BCM_ENABLED27 28 #ifdef BCM_BONDING_ENABLED29       CodeLine4;30 #endif31 32 #ifdef BCM_ENABLED33       CodeLine8;34 #endif35 36 37 //Macro2.c(dir2)38 #define BCM_ENABLED39 40 #ifdef BCM_VECTOR_ENABLED41       CodeLine4;42 #endif43 44 #ifdef BCM_ENABLED45       CodeLine8;46 #endif
Macros

     Warns.txt为编译结果(暂以模拟内容代替)。

1 #warning Reach code 
2 #warning Reach code
3 #warning Reach code
4 #warning Reach code
5 #warning Reach code
6 #warning Reach code
Warns

     根据实际情况调整代码路径(当前为E:\ValidMacroExample)后,按如下步骤运行:

     1. 执行AddWarnsEx.py,生成添加#warning后的代码文件f.c(h)及其备份f.cb(hb)。

     2. 编译处理后的代码文件f.c(h),将编译结果重定向到Warns.txt内。

     3. 执行ChkMacrosEx.py,生成添加/*TRUE*/的代码文件,并自动删除备份文件。

     将Python脚本内待处理代码路径修改为xDsl模块路径后,即可用于实际工程代码的精简。经过处理的实际代码片段截图如下:

     更进一步,可分析处理后的/*TRUE*/标记,自动删除未编译的代码段,但需要严密的语法分析。此外,目前的脚本实现未考虑执行效率。因时间精力有限,暂时不予改进。     

 

三  效果评价

     清理目录和代码后,比较完整代码(Full)和精简代码(Lite)的规模如下:

版本

代码量()

系数

Full

9,024,746

1

Lite

221,964

0.0246

     可见,Lite代码行数约为Full代码的2%(考虑到BCM芯片SDK后续可能更新,为便于同步相应代码未做精简)。编译后经验证,可正常配置和查询。

 

 

转载于:https://www.cnblogs.com/clover-toeic/p/3757194.html

你可能感兴趣的文章
加固linux
查看>>
WPF中Image显示本地图片
查看>>
[poj1006]Biorhythms
查看>>
Hyper-V虚拟机上安装一个图形界面的Linux系统
查看>>
js千分位处理
查看>>
Mac---------三指拖移
查看>>
字符串类型的相互转换
查看>>
HTTP状态码
查看>>
iOS如何过滤掉文本中特殊字符
查看>>
基础学习:C#中float的取值范围和精度
查看>>
javaagent 简介
查看>>
python升级安装后的yum的修复
查看>>
Vim配置Node.js开发工具
查看>>
web前端面试题2017
查看>>
ELMAH——可插拔错误日志工具
查看>>
MySQL学习笔记(四)
查看>>
【Crash Course Psychology】2. Research & Experimentation笔记
查看>>
两数和
查看>>
移动设备和SharePoint 2013 - 第3部分:推送通知
查看>>
SOPC Builder中SystemID
查看>>