草庐IT

XCode Coverage Data 为0 的解决历程

那个推车的人 2023-03-28 原文

笔者最近在做单元测试框架的搭建,做到输出代码覆盖率的时候,发现app的代码覆盖率一直是0,然后就开启了历程一周的找碴过程,其中嫌弃电脑太慢,直接花了1w4买入了新的macbook pro(M1 pro),不得不说,生产力杠杠的,不过现在系统有个问题会造成播放音乐时出现噗噗的声音有点烦人。

好,进入主题:

问题描述:
如图,跑完单元测试后XCode Coverage Report 显示为零。Log显示提示语是:
Failed to generate coverage for target 'XXX.app' at paths (xxxxxxx): Failed to decompress coverage data (zlib)


image.png

但是,Test target还是有报告出来的。
为此,笔者几乎搜遍了google baidu bing,没有一个相同的问题,我想我遇到了所有人都没有遇到过的棘手的问题。

·初步思考
1、工程比较复杂,可能没法正常输出结果
2、XCode可能有bug,就是没法输出结果
3、工程有问题,没法正常输出结果

·并尝试解决:
1、通过新建一个空的工程,并跑一次单元测试,正常输出。
2、新工程引入一个原工程的文件,并把各种库链接完成,跑一次单元测试,并重复几次操作,发现,当库文件还比较少时,还是可以输出测试报告,但一旦库引用接近原工程时,报告就无法生成了。
最后,初步定性为3,工程有问题,结合网上压根没有相关的资料,就比较肯定了,毕竟笔者的工程结构是真的过于复杂。

·尝试细致定位问题:
工程有问题,可能是其中某个库导致的。着手尝试逐个库引入并进行单元测试,最终发现引入libprotobuf时,同时other linker flag 设为-ObjC时,会出现该问题。-ObjC标记是链接时,会将所有静态库中的Objective C class和category加载到包中。那估计就是libprotobuf中的东西引进去导致了问题。
试图绕开libprotobuf,通过force_load逐个将需要的包加载,结果,失败。

来到这里,人都崩溃了,搞了大半天,回到原点,可能并不是单单libprotobuf的问题,有可能是加载Objective C category的问题。

·高阶尝试:
绕开不行,那我换一种单元测试方案,不用XCode输出报告了,直接走精准测试的方案,毕竟XCode是个黑盒,查了那么多资料至今也不知道XCode的覆盖率报告用的是哪个方案(后来知道了)。
1、llvm gcov方案 ,通过.gcda .gcno的方案,但是无法检测swift的代码
2、llvm Source-Based Code Coverage方案,通过生成.profraw .profdata,比较完整的方案,而且精测基本上走得这个方案,可行性高,社区信息丰富。
3、SanitizerCoverage,另一种插桩方式,几乎没人用来做覆盖率报告,难度高

经过实施,
第1方案是可行的,但是无法生成swift的代码
第2方案,历经千辛万苦,最后工具报错 Failed to decompress coverage data (zlib)。

崩溃了。。。

可以看出,其实XCode的单元测试代码覆盖率报告是用llvm Source-Based Code Coverage的方案进行的,只是最后在.profdata输出的基础上进行ui层面的加工,我们也可以在编译中间文件中找到Coverage.profdata。

第3方案,是一个大工程,根本不可能短时间完成,但是几乎可以肯定,报告肯定可以做出来的。

·lvm-cov Source-Based Code Coverage方案Deep Dive:
无论通过自己走llvm SourceBaseCodeCoverage方案生成的profdata,还是xcode收集的profdata,在llvm-cov工具执行 show的时候,都会报同样的错误 Failed to decompress coverage data (zlib)。
只能迎难而上,找出问题的根本原因了。也就是工程为什么会导致该搞错。

1、下载LLVM Project:
2、执行 All_Build target,完整编译一次llvm
3、找到llvm-cov工具文件,阅读源码,并进行Debug
4、使用xcode生成的profdata,执行llvm-cov show命令,并进行断点研究

有几个发现,
1、zlib其实是对二进制码进行解压的工具,llvm执行编译时,是通过对代码插桩,从而收集代码执行的情况。.profdata应该是执行的Log。llvm-cov show是通过zlib解压二进制包和代码,关联.profdata,最终整合出报告。
2、llvm-cov show时崩溃,触发了CoverageMappingReader.cpp中的assert((CovMapVersion)CovHeader->getVersion<Endian>() == Version)。原因是getVersion = 2, Version = 4 。
3、注释掉该行assert代码,程序跑完后报错 Failed to decompress coverage data (zlib)。

问题关键点找到了!

但是,为什么呢?

继续对llvm-cov show执行过程进行debug,发现,其实zlib解析了大部分代码都是正常的,但是一到某个地方就version对不上,上下文也无法定位,因为解析的信息出来是空的。
经过对代码继续排查,试图找到哪个包出现问题,最后发现,还是执行到解析libprotobuf相关代码出现问题。

醉了,最终还是libprotobuf的问题,反思了一下,之前force_load时为什么还是不行?而且,libprotobuf的代码不应该在里面,因为其他静态库文件都是没有在里面的,libprotobuf应该没有插桩的啊,怎么会收集上来呢。

重新拉protobuf工程,编一个iOS的lib,替换,执行单测。
结果,报告出来了,醉了醉了。肯定是原来的包混进了奇怪的东西。(后面对比了一下,好像也没什么问题,确实protobuf的.m会被插桩,protobuf-iOS的编译跟普通的库还是不一样,难道是版本编译出的问题?对于llvm还是不熟,最终原因还有待确定)

总结:
本次问题还是很棘手的,每一步都没有参考的方法和思路。由于xcode是黑盒,不知道用的哪种代码覆盖收集方案导致一开始就没有走正确的路线。其次,一提到llvm觉得是很难的东西,没有静下心来细看。最后,还是因为知识匮乏,导致弯路走了很多。经此一战,以后llvm工具报错出问题都不用担心了。

有关XCode Coverage Data 为0 的解决历程的更多相关文章

  1. 屏幕录制为什么没声音?检查这2项,轻松解决 - 2

    相信很多人在录制视频的时候都会遇到各种各样的问题,比如录制的视频没有声音。屏幕录制为什么没声音?今天小编就和大家分享一下如何录制音画同步视频的具体操作方法。如果你有录制的视频没有声音,你可以试试这个方法。 一、检查是否打开电脑系统声音相信很多小伙伴在录制视频后会发现录制的视频没有声音,屏幕录制为什么没声音?如果当时没有打开音频录制,则录制好的视频是没有声音的。因此,建议在录制前进行检查。屏幕上没有声音,很可能是因为你的电脑系统的声音被禁止了。您只需打开电脑系统的声音,即可录制音频和图画同步视频。操作方法:步骤1:点击电脑屏幕右下侧的“小喇叭”图案,在上方的选项中,选择“声音”。 步骤2:在“声

  2. 【高数】用拉格朗日中值定理解决极限问题 - 2

    首先回顾一下拉格朗日定理的内容:函数f(x)是在闭区间[a,b]上连续、开区间(a,b)上可导的函数,那么至少存在一个,使得:通过这个表达式我们可以知道,f(x)是函数的主体,a和b可以看作是主体函数f(x)中所取的两个值。那么可以有,  也就意味着我们可以用来替换 这种替换可以用在求某些多项式差的极限中。方法: 外层函数f(x)是一致的,并且h(x)和g(x)是等价无穷小。此时,利用拉格朗日定理,将原式替换为 ,再进行求解,往往会省去复合函数求极限的很多麻烦。使用要注意:1.要先找到主体函数f(x),即外层函数必须相同。2.f(x)找到后,复合部分是等价无穷小。3.要满足作差的形式。如果是加

  3. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

  4. ruby - 如何更快地解决 project euler #21? - 2

    原始问题Letd(n)bedefinedasthesumofproperdivisorsofn(numberslessthannwhichdivideevenlyinton).Ifd(a)=bandd(b)=a,whereab,thenaandbareanamicablepairandeachofaandbarecalledamicablenumbers.Forexample,theproperdivisorsof220are1,2,4,5,10,11,20,22,44,55and110;therefored(220)=284.Theproperdivisorsof284are1,2,

  5. ruby - 为什么这些方法没有解决? - 2

    这个问题在这里已经有了答案:WhydoRubysettersneed"self."qualificationwithintheclass?(3个答案)关闭29天前。给定这段代码:classSomethingattr_accessor:my_variabledefinitialize@my_variable=0enddeffoomy_variable=my_variable+3endends=Something.news.foo我收到这个错误:test.rb:9:in`foo':undefinedmethod`+'fornil:NilClass(NoMethodError)fromtes

  6. 电脑启动后显示器黑屏怎么办?排查下面4个问题,快速解决 - 2

    电脑启动出现显示器黑屏是一个相当常见的问题。如果您遇到了这个问题,不要惊慌,因为它有很多可能的原因,可以采取一些简单的措施来解决它。在本文中,小编将介绍下面4种常见的电脑启动后显示器黑屏的原因,排查这些原因,快速解决! 演示机型:联想Ideapad700-15ISK-ISE系统版本:Windows10一、显示器问题如果出现电脑启动后显示器黑屏的情况。那么首先您需要检查一下显示器是否正常工作。您可以通过更换另一个显示器或将当前显示器连接到另一台计算机来检查显示器是否存在问题。如果问题仍然存在,那么您可以排除显示器故障的可能性。 二、显卡问题如果您的电脑配备了独立显卡,那么显卡故障也可能是导致电脑

  7. 关于Qt程序打包后运行库依赖的常见问题分析及解决方法 - 2

    目录一.大致如下常见问题:(1)找不到程序所依赖的Qt库version`Qt_5'notfound(requiredby(2)CouldnotLoadtheQtplatformplugin"xcb"in""eventhoughitwasfound(3)打包到在不同的linux系统下,或者打包到高版本的相同系统下,运行程序时,直接提示段错误即segmentationfault,或者Illegalinstruction(coredumped)非法指令(4)ldd应用程序或者库,查看运行所依赖的库时,直接报段错误二.问题逐个分析,得出解决方法:(1)找不到程序所依赖的Qt库version`Qt_5'

  8. 【RuntimeError: CUDA error: device-side assert triggered】问题与解决 - 2

    RuntimeError:CUDAerror:device-sideasserttriggered问题描述解决思路发现问题:总结问题描述当我在调试模型的时候,出现了如下的问题/opt/conda/conda-bld/pytorch_1656352465323/work/aten/src/ATen/native/cuda/IndexKernel.cu:91:operator():block:[5,0,0],thread:[63,0,0]Assertion`index>=-sizes[i]&&index通过提示信息可以知道是个数组越界的问题。但是如图一中第二行话所说这个问题可能并不出在提示的代码段

  9. ruby-on-rails - 如何解决#<Book::ActiveRecord_Relation:0x007fb709a6a8c0> 的未定义方法 `to_key'? - 2

    我遇到了未定义方法`to_key'的问题这是我的books_controller.rbclassBooksController和我的索引页如下。index.html.erb......现在当我要访问索引页面时出现如下错误。undefinedmethod`to_key'for# 最佳答案 index通常返回一个集合。事实上,您的Controller符合要求。但是,您的View试图为其定义一个表单。正如您所发现的,这不会成功。表单适用于实体,而不适用于集合。该错误在您看来以及您希望如何处理index。

  10. ruby-on-rails - 本地 gem 的“bundle 安装”没有解决依赖关系,而 'gem install' 可以 - 2

    我在目录“/home/enterprise/pkg”中有一个本地gem(enterprise-0.0.1.gem)。它依赖于active_directorygem(v1.5.5),这是在它的enterprise.gemspec文件中指定的,如下所示:-gem.add_dependency("active_directory")在我的应用程序的Gemfile中,我添加了以下行:-gem'enterprise','0.0.1',path=>'/home/enterprise/pkg'当我做的时候bundleinstall在我的应用程序的源目录中,只安装了企业gem。因此,我遇到了引用act

随机推荐