• 移动跨平台框架开发之一:ios重用c++库


    最近我们在开发一款游戏,包含四块:c++服务器,ios客户端,android客户端以及c++的客户端。C++客户端用于集成测试以及压力测试。我们希望达到最大限度的重用。C++是自然的选择。我们需要把c++的源代码以库的形式重用在ios和andriod上。这样网络通信和model部分只要维护一套c++代码,ios和android只要写UI和线程。后续将分篇讲述开发中碰到的问题和解决方案。

    今天讲述ios重用c++库。

    这里有两个难点:

    1. 我们用到了大量的第三方库,主要有:

    l   zmq                    socket通讯

    l   protobuf            协议

    l   cryptopp           加密鉴权

    这些库的源代码有的比较旧;有的有好几个来源,不知该选择哪个;脚本都需要改动才能在你的平台下运行,但文档并没有提及。

    1. c++与obj-c的混合编码

    一般人可能觉得这很简单,只要把整个工程的.m和.cpp文件全部改为.mm就可以了。如果你写一个简单的helloword程序,这样确实没问题。前面我们说过,我们要以库的形式重用c++,就有一点tricky了。

    言归正传,以下阐述过程中遇到的问题和解决方案。

    1. 编译protobuf

    下载c++的代码库,最新版本是2.5.0。按照

    http://www.giraffe-games.com/using-protobuf-protocol-buffers-on-iphone-ios/

    step by step就可以了。其中有一步执行脚本:

    https://github.com/dinote/protobuf-mobile-build/blob/master/ios-config.sh

    这个脚本比较新。只要把其中的

    export SDKVER="6.0"

    替换成你的sdk版本,比如我替换成6.1。

    提醒一点,由于以上编译出来的是适用于移动终端的lite版本,因此请在.proto文件的头部加上这一行,否则链接失败。

    option optimize_for = LITE_RUNTIME;

    lite版本的体量小很多,但它的代价是不能在程序中使用DebugString()等方便调试的函数了。

    不要用for objc的代码库。它编译后生成包含c++和objc wrapper的单一库。它的最新版本是2.2.0。由于这个编译出来的库是现成的(我同事编译的),我曾经尝试用2.2.0的protoc来编译.proto文件,生成.h和.cc文件,并在objc程序中以c++的方式调用,结果链接失败。

    1. 编译cryptopp

    这个库资料不完整并且不正确。首先容易弄错的是下载了不正确的库。请下载

    https://github.com/yep/CryptoPP-for-iOS

    这里你需要改动的是文件:external / scripts / build-cryptopp.sh

           export DEV_ROOT="/Applications/Xcode.app/Contents/Developer/Platforms/${PLATFORM}.platform/Developer"

           export TOOL_ROOT="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain"            //加这一行

           export SDK_ROOT="${DEV_ROOT}/SDKs/${PLATFORM}${SDK_VERSION}.sdk"

           BUILD_PATH="${WORK_PATH}/objs/${PLATFORM}${SDK_VERSION}-${ARCH}.sdk"

           export CC="${DEV_ROOT}/usr/bin/gcc -arch ${ARCH}"

           export LD=${DEV_ROOT}/usr/bin/ld

            if [ "${ARCH}" == "i386" ]; then

                  export CXX=${DEV_ROOT}/usr/bin/g++

            else

                  export CXX=${TOOL_ROOT}/usr/bin/clang          //改这一行

    不要下载在google搜索中排名靠前的

    https://github.com/3ign0n/CryptoPP-for-iOS

    前者比后者略新,错误少点,改起来就没那么费劲了。我因为下载了这个库,浪费了大量时间。

    编译出来的库很大,有100+M,没有关系。链接程序只会选择用到的部分,生成的.app只会增加很小的体量。

    1. 编译zeromq

    我同事以前编译的,生成两个库:libzmq.a和libzmqobjc.a。只需要用前者就行。

    1. c++和objc混合编程

    这里的关键是要保持代码的隔离。工程中混合的需要改名为.mm的文件越少越好。

    Objc调用c++相对简单,只要在Objc的类中包含c++的成员对象,并且调用该对象的成员函数就可以了。例如我的一个NSOperation子类中只包含这几行代码

    - (id)init

    {

        self = [super init];

        msgDispatcher = new MsgDispatcher();

        return self;

    }

     

    - (void)main

    {

        @autoreleasepool

        {

            msgDispatcher->dispatch();

        }

    }

    其中msgDispatcher类在c++编译成的库中。

    c++调用Objc就很有讲究了,因为这部分代码是不能包含Objc的头文件和成员变量的。为了防止c++对Objc的依赖,按照正常的逻辑,声明一个c++虚类,这个类位于需要重用的c++编译成的库中。由Objc继承并实现它的虚函数。遗憾的是,objc与c++之间不能互相继承,双方向都不行。接下来你会想到用什么?对,cast。以下是代码示例。

    MsgHandlerImpl.h

    class MsgHandlerImpl

    {

    public:

        MsgHandlerImpl ( void );

        ~MsgHandlerImpl( void );

       

        void onCheckin ();

       

    private:

        void * viewControllerAdapter;

    };

    MsgHandlerImpl::MsgHandlerImpl()

    {

        viewControllerAdapter = (void *)CFBridgingRetain([[ViewControllerAdapter alloc] init]);

    }

     

    MsgHandlerImpl.cpp

    MsgHandlerImpl::~MsgHandlerImpl()

    {

       

    }

     

    void MsgHandlerImpl::onCheckin()

    {

        [(ViewControllerAdapter *)CFBridgingRelease(viewControllerAdapter) onCheckin];

    }

    这里关键中的关键就是CFBridgingRetain和CFBridgingRelease。作用类似于cast。

    千万不要用(__bridge void *)作强制类型转换。

    viewControllerAdapter = (__bridge void *) [[ViewControllerAdapter alloc] init];

    1. 其它问题

    以下都是我走了很多弯路之后得来的。

    5.1.     文件类型

    问题:

    编译时提示大量系统头文件内部的问题

    解决方案:

    多半是你没有把.m文件或者.cpp文件改为.mm文件。虽然你的.m文件没有直接包含c++代码,但只要是include c++的头文件,或者import的objc头文件中间接include c++的头文件,都需要改后缀名为.mm文件,或者在file inspector中改file type为object c++ source。后者更为方便。

    5.2.     std链接

    问题:

    编译时提示大量std::string的问题

    解决方案:

    In main project -> Build Settings scroll and find out the options, C++ Language Dialect and C++ Standard Library. Select options "Compiler Default" for both of them.

    5.3.     Zmq包含的头文件找不到

    问题:

    ‘algorithm’ it not found

    解决方案:

    header search path中添加/usr/include/c++/4.2.1

  • 相关阅读:
    现在, Delphi 的多线程已经非常易用了!
    发现 TSplitter 在嵌套时不好用, 索性写了个替代品
    关于显示透空歌词的思路 回复 "zhaoboaidelphi" 的问题
    简单获取钢琴 88 个键的音高频率值
    准备理一下菜单和工具栏相关的组件
    在 StringGrid 上画线时, 使用 GDI+ 以消除锯齿 回复 "gsjn_8888_6666" 的问题
    解压 svgz 到 svg
    jQuery能做到,PHP能做到,C#也能做到
    监测ASP.NET应用程序性能最简单的方法
    支持高并发的IIS Web服务器常用设置
  • 原文地址:https://www.cnblogs.com/mobileinternet/p/3185124.html
Copyright © 2020-2023  润新知