1.背景
现在的移动端开发,越来越追求iOS和Android能够使用一套代码就能二者兼得的模式。这种情况下由于不需要维护两套代码,因此在某种程度下能够降低错误的风险。
二者融合的模式中,一种方式便是使用w3c标准的web形式,这也是Hybrid的主要概念来源。于是各种Hybrid框架层出不穷,从PhoneGap到现在流行的React-Native都属于此类。
然而,事实上还有一种方式,便是采取纯c/c++编写程序,iOS和Android共享底层代码来达到相同目的的方法。这里的标准叫做POSIX。我们也正是基于这种考虑,让iOS, Android, PC 都公用一套代码,增加代码的复用,减少问题的发生概率。
2.我们的解决方案
在iOS端,为了达到复用同一套C/C++代码,并且不对原代码破坏的目的,我们采用的也是CocoaPods的方案。使用CocoaPods将该功能所有的C/C++建立一套Pod库,编译成静态库,来达到共享的目的。
3.问题的产生
工程师兄弟都知道,需求是在不断进(keng)步(die)的。基于此,底层的共享库也会经常地有所变动。为了达到这次需求的目的,底层的兄弟直接从纯C改用了C++编写,而这也是困扰了我整整两天的问题根源。看到这里,可能会有懂行的产生疑问,C++不是兼容C的吗?
对,没错,C++是兼容C;但是问题在于C,并不兼容C++。
4.寻源
Apple的OS底层是XNU(Mach+Darwin), 也是一套遵循了POSIX标准的内核,主要从UNIX中来。不过,它并不是100%兼容GNU/Linux的标准,因此在C/C++的编译上便会产生一系列偏差,虽然这种概率并不大。
XCode中的libc++就是采用了Apple自己标准的C++协议库。如上所说,这个库会导致一些在Linux下编译ok的库在iOS上无法链接成功(非100%兼容GNU/C++)。
这种情况下,就需要使用Apple提供的另一个库:libstdc++(libstdc++.6.0.9代表不同版本的libstdc++),这个东西是GNU/C++ 100%兼容的。
5.兼容
原以为解决以上问题就可以成功连接,却还是出现undefine symbols错误。
仔细想想,发现原来问题的关键在于.m文件。
事实上,iOS中除了Object-C 开发,还有一个东西叫做Object-C++。Object-C++文件是以.mm后缀结尾的。当llvm编译器看到.mm文件时,会自动调用Object-C++的标准来编译和连接该文件。
在之前的版本中,底层的兄弟采用的是.c文件来编写相关的代码;这次换成.cpp文件后,llvm编译这样文件时候编的是c++。而直接调用这些函数的代码又是.m,即Object-C,遵循C标准。最后Linking阶段导致了符号表找不到的问题。
修改.m文件后缀为.mm,编译,通过,收工。
6.经验
C/C++并不一样。如果.m文件要调用的是在.cpp文件内的函数,一定改成.mm。
libstdc++、libstdc++.6.0.0、libc++都是不一样的。如果一种库连接不起来,尝试使用另一种,说不定可以带来惊喜。