为我的C ++应用程序提供SDK

时间:2016-01-12 21:35:21

标签: c++ sdk

假设我正在用C ++创建一个游戏引擎,我想只提供一些标题而不是提供完整的源代码,并且需要这些标题来创建新的游戏实例,提供Script类,提供游戏对象类和组件,数学等。

是的,显然我想为我的游戏引擎提供SDK但是怎么做,如何只提供一些公共标题并隐藏源文件和仅引擎头?如何将这些标题链接到源的其余部分?

我在Linux平台上使用Eclipse CDT。

2 个答案:

答案 0 :(得分:2)

一般情况下,通过提供共享(动态)库并在头文件中提供纯虚拟接口,您可以获得最佳(轻松)可实现的二进制兼容性,并具有一些外部C入口点(用于交叉编译器兼容性,如C ++每个编译器对名称进行了不同的修改。

一个很好的起点可能是这篇文章:http://chadaustin.me/cppinterface.html - 它主要针对Windows,但它也可以应用于Linux。

我实际上在设计共享库时使用它作为起点(在Windows和Linux中工作),但是我放弃了自定义操作符delete,而是直接调用destroy方法(实际上是通过自定义的智能指针)

在Linux下,建议使用编译器的“visibility”标志,默认情况下隐藏所有内容(“-fvisibility = hidden”)并仅将__attribute__ ((visibility ("default")))标记为需要导出的函数(请注意,您只需要导出extern“C”入口点,并且不需要导出纯虚拟接口)。

为了获得更好的二进制兼容性,您甚至需要避免虚拟方法并实现自己的虚拟表(与用户可能使用的每个编译器兼容),但纯虚拟接口实际上足够兼容。

使用静态库可能会遇到问题,因为您可能需要为用户可能使用的每个编译器(有时甚至是同一编译器的不同版本)提供静态库。

例如,界面可能如下所示:

class Interface {
public:
   virtual void destroy() = 0;
protected:
   // prevent to call delete directly
   // - needs to be done in every public interface class
   ~Interface() {}
};

class IGameComponent: public Interface {
public:
    virtual int32_t someMethod() const = 0;
protected:
   ~IGameComponent() {}
};

class IGameEngine: public Interface {
public:
    // call component->destroy() when done with the component
    virtual IGameComponent * createComponent() const = 0;
protected:
   ~IGameComponent() {}
};

extern "C"
__attribute__ ((visibility ("default")))
IGameEngine * createEngine();

实现可以如下所示:

// CRTP to avoid having to implement destroy() in every implementation
template< class INTERFACE_T >
class InterfaceImpl: public INTERFACE_T {
public:
   virtual void destroy() { delete this; }
   virtual ~InterfaceImpl() {}
};

class GameComponentImpl: public InterfaceImpl<IGameComponent> {
public:
    virtual int32_t someMethod() const
    { return 5; }
};

class GameEngineImpl: public InterfaceImpl<IGameEngine> {
public:
    virtual IGameComponent * createComponent() const
    {
        try {
            return new GameComponentImpl;
        } catch (...) {
            // log error
            return NULL;
        }
    }
};

extern "C"
IGameEngine * createEngine()
{
    try {
        return new GameEngineImpl;
    } catch (...) {
        // log error
        return NULL;
    }
}

这就是我如何实现库的接口的原则。建议将已分配的对象包装在智能ptr中,但要进行自定义,以便调用Interface :: destroy()而不是delete。

另请注意int32_t的使用 - 通常,如果希望接口尽可能与交叉编译器兼容,则应使用固定大小类型(即不是例如size_t,这也适用于bool和enums,这些都是高度依赖编译器的,但对于int,short,long等也是如此。)。

进一步注意使用try / catch防护,一般情况下,如果您希望API可能来自不同的编译器(或者有时甚至在调试/非调试版本之间),则不应允许异常传递API边界。相同的编译器,但更适用于Windows;但是当库与太多不同的版本(例如GCC编译器)一起使用时,仍然可能会出现问题。

答案 1 :(得分:0)

这是你想要的视频 - &gt;在eclipse CDT中创建一个静态库 https://www.youtube.com/watch?v=kw3UD_YCoEk

你也可以创建一个动态库,但先从静态开始。