DSP

将webrtc的p2p模块编译成dll并移植到qt

2019-07-13 17:21发布

    前端时间一直在做P2P文件传输的工作,基于开源库webrtc,有关webrtc的下载、编译在此不做复述,可以在我之前的小文章中找到整个过程。vs2015下编译成功p2p dll,然后移植到qt中,qt使用mingw编译,那么问题来了,qt mingw编译环境和vs2015 msvc不是同一个编译系统,qt mingw自然不能像在msvc中导入dll的方式去导入 前面的 p2p dll!这个问题让我头疼,查阅webrtc的官方文档,居然看到说可以将webrtc的编译指定编译器去编译,而ninja只是用来构建工程项目,支持的编译器有vs2015 、 qt mingw、xcode什么的,顿时欣喜如狂,就没看仔细了,心想先弄个qt的版本,按照webrtc 手册的步骤来构建,真是错误百出!后来到群里一问,一哥们早就用过这种方法来移植到qt平台了,结果他说这个方法行不通!就算构建出了qt的工程,也是编译不出可用的依赖dll和lib,这会果断去看文档,文档上也是对这种做法持不确定态度!说由webrtc源码构建qt等其他平台下的工程可能行但是可能也不能使用!没办发,经群中高手点拨,还是每个平台下都编译一个版本的dll吧!这,才是苦难的开始。     之前使用webrtc的源码和依赖库写好了P2P文件传输的dll,qt mingw编译器是不识别msvc编译的dll的,初步想法是使用qt自带的加载dll的函数去加载dll中的导出函数接口,不得要传给QLibrary对应api导出函数在dll中对应的函数符号,大家都知道如果不是用纯C的方式(extern "C")修饰导出函数,编译器在导出函数、类到dll中的时候,根据调用约定(__stdcall 、 __cdcel)会在函数符号名添加特定的字符,结果dll中的导出函数的名字和原来的名字发生了很大的差别,所以如果导出dll和导入dll的两个编译器是相同的那没问题,函数符号都是按照固定的格式去修饰的,平常的方法都是直接引入dll,然后显式或者隐式调用dll中的接口,但是当导出dll和导入dll的编译器不一样,就不能按照平常的方式去使用dll了,所以就需要用到extern "C"来修饰导出函数,我使用__cdcel的调用约定,为了最大程度地支持C,毕竟dll就是以C作为设计目标的。如此做后,重新在vs2015中编译dll,将得到的dll添加到qt的pro文件中,很庆幸,dll中的函数的函数符号和源码中的是一样的,所以我不打算使用QLibrary显示去调用dll中的函数了,直接使用隐式的方式调用,居然变得和在vs中调用dll的时候一样,这听起来确实有点前后矛盾,可事实就是这样!     dll能够正常导入到qt项目工程中去了,这没什么值得高兴的!没准调用的dll还是有问题呢,结果还真是!因为dll不是在同一个编译器导入和导出,不同的编译器对非基本数据类型的处理,不一样,这也只是猜测,现未证明!就像是你感觉到山洞里黑乎乎很吓人而不敢进去一样,我之所以有这个想法也是遇到了一些具体的事情,比如,我在dll的一个接口函数中使用了std::string类型作为参数类型,我在vs里面调用此接口没有任何问题,可是当我在qt中创建了一个std::string对象并将此对象作为参数传进此接口的时候,程序会莫名崩溃、闪退,查看调试信息知道是内存和堆栈出了问题,同样是std::string 类型,不同编译其中的内存处理确实是不一样的,可能我qt中的std::string一传进dll中去,dll对此std::string的处理破坏了此std::string的堆栈布局呢?也许吧,留待回去验证!于是在vs2015中重新设计导出函数,将所有导出接口中使用到的std::string全部用基本数据char*代替,基本语言类型在各个编译系统下被处理的方式就是兼容了吧,修改后导出dll,在qt中导入测试,问题解决!     在跨平台的时候尽量使用C的接口方式,在导出接口的时候,最好使用语言的基本类型,非语言标准的类型在接口传参的时候会有大麻烦!