这里记录一些关于在Windows上调试CEF/Chromium/WebRTC源码的一些心得体会,也是怕时间久了就忘记了其中一些细节。
因为经常有需要对CEF以及WebRTC的源码进行分析和修改,所以修改后如何调试就成了首要解决的问题。CEF,或者说Chromium与普通的小工程不同,他的庞大是众所周知的。所以为什么Google专门创造了GN和ninja。
在编译了CEF以后,在out目录下会有各种版本的编译中间代码文件、二进制文件等等,包括以下目录:
Debug_GN_x64\
Debug_GN_x64_sandbox\
Debug_GN_x86\
Debug_GN_x86_sandbox\
Release_GN_x64\
Release_GN_x64_sandbox\
Release_GN_x86\
Release_GN_x86_sandbox\
以 Debug_GN_x86 举例,这里面有一个1MB多的 cef.sln文件,如果用Visual Studio 2017打开它,在解决方案列表里,你会看到一个超级超级长的project列表,整个工程加载也是需要很长的时间。我目前的笔记本是 i7 8550,16G,海康威视SSD,加载速度也是让我不太能够忍受的。而且经常动不动Visual Studio 2017就崩溃重启了。
所以,如果不用 cef.sln,我们怎么调试CEF以及WebRTC呢?
我这里提供一种方法,就是代码的浏览、修改使用VS Code或VS 2017(直接打开.h/.cc文件),修改后,使用ninja在命令行中手动编译,然后把CEF示例程序(例如cefclient.exe)运行起来,之后在Visual Studio 2017中打开需要调试的代码,设好断点,之后用 Debug菜单下的 Attach to process 命令,attach到对应的进程上(由于Chromium是多进程架构,所以需要根据调试内容attach到不同的进程)。
如果你打开的源码正确,断点也确保可以执行到,且attach到的进程也正确,那么当你在CEF中执行相应功能时候,就会发现在Visual Studio 2017中,你刚才设置的断点生效了。
下面举个例子,比如我想看一下在CEF中使用js创建一个H.264编码的视频流,WebRTC是如何创建和初始化H.264编码器的,以及编码视频帧的函数调用。按照上面介绍的方法,我们需要先找到CEF中,WebRTC H.264编码器的源码在哪里:
\src\third_party\webrtc\modules\video_coding\codecs\h264\h264_encoder_impl.h/.cc
注:由于WebRTC代码变化频繁,本文以CEF 3729(对应的WebRTC版本是M74分支)为蓝本介绍。
启动Visual Studio 2017,打开h264_encoder_impl.cc,并随便在几个函数入口设置断点。例如在 H264EncoderImpl构造函数,InitEncode()、Encode()我设置了3个断点:
然后在命令行中运行 out\Debug_GN_x86\cefclient.exe,启动命令行参数我指定的是:
--enable-media-stream --no-proxy-server --ignore-certificate-errors --enable-logging --v=1
参数说明:
--enable-media-stream:授权CEF可以使用本地摄像头麦克风设备
--no-proxy-server:防止Debug版本的cefclient崩溃
--ignore-certificate-errors:我用来测试的页面是https的但是我没有配置站点证书,用这个来忽略一下
--enable-logging --v=1:启用详细日志。默认会产生在命令行窗口以及产生一个debug.log文件(和cefclient.exe同级目录下)
更多的启动参数,可以参考:https://peter.sh/experiments/chromium-command-line-switches/
在启动的cefclient.exe浏览器窗口中,打开用于视频推流测试网页,先不要执行推流。
回到Visual Studio 2017,执行 Debug菜单下的Attach to process,会发现进程列表里有3个cefclient.exe:
视频的编码不再主进程(有标题文字的那个),在另外的一个进程中。由于另外的2个进程没有标题,所以需要逐一试一下。
attach到指定的进程以后,VS2017进入调试模式。现在我们回到网页,开始执行视频推流:
按下推流按钮,果然如我们期望的,在VS2017中,我们刚刚在H264EncoderImpl的构造函数中设置的断点生效了,程序停留在我们设置的断点位置,相关变量的值,以及程序调用堆栈,一览无余。
F5运行,会发现我们刚才设置的其他两处断点也相继生效了:
OK,这种调试方法,不需要打开整个sln工程,避免查看庞大的project列表,避免启动慢、解析慢等问题。缺点是需要你对CEF、WebRTC代码工程源码结构有一定的了解,以便准确知道你要调试内容的源码位置并直接打开。
最后介绍一下修改CEF/WebRTC源码后的编译方法。
在首次全量编译CEF的时候,我们一般是使用CEF官网提供的 automate-git.py完成的,这个python脚本集下载、编译、打包为一体,在网络代理(你懂得)强大的情况下,用这个脚本是十分轻松方便的。但是如果我们只修改了几个文件,就不用再动用automate-git.py了,只需要使用 ninja命令来编译即可。
举例如下,我们随便修改一个文件,例如:\src\third_party\webrtc\video\video_stream_encoder.cc,我随便挑了一个函数 VideoStreamEncoder::ConfigureEncoderOnTaskQueue(),修改了一条日志语句,加了几个字符:
修改以后,在命令行窗口中转到CEF的src目录下,运行以下命令:
ninja -C out\Debug_GN_x86 cefclient
ninja将会帮我们进行针对修改部分的增量编译。在我机器上,即便只是修改了刚才那一个地方,用ninja也编译了几分钟……不知道到底是机器性能不行还是真的编的慢……
OK,编译成功后,再次启动cefclient.exe(别忘记增加 --enable-logging --v=1),执行视频推流,然后在cefclient.exe同级目录下找到debug.log,打开,搜索关键字:ConfigureEncoder,会看到,我们刚才的修改生效了:
当然,直接把源码拖到VS 2017中调试,不在debug.log中查看也是可以的。
好了,工欲善其事必先利其器,掌握了基本的编译和调试方法,对CEF/WebRTC代码的研究和修改、试验就方便多了。
除此以外,阅读一下Debugging Chromium on Windows,也会得到不小的收获