其实就是用dlopen之类的解析符号来调用。但是其实我们可以做得更多,因为这些动作都是比较机械话的。于是我搞了个小项目 https://github.com/wang-bin/dllapi
为什么不用链接?
1. 开发环境中可能没有那个库,但是希望能在有这个库的运行环境上能工作。
2. 不依赖运行时库的版本
为什么不手工写解析符号代码? 比如xbmc是为每个库写个类,然后把要用的接口作为类的成员函数,还有比如Qt的QOpenGLFunctions,mozilla的opengl函数调用等也是类似的方法,看上去像手写的,多麻烦;而且调用类的成员函数破坏了库原生接口的样子,不太喜欢
我的项目能做什么?举个例子吧
比如现有一些调用SDL接口的代码:
#include <SDL/SDL.h>
int main()
{
SDL_Init(SDL_INIT_VIDEO);
SDL_SetVideoMode(640, 480, 0, SDL_HWSURFACE | SDL_DOUBLEBUF);
SDL_WM_SetCaption("SDL Start", 0);
SDL_Event event;
bool gameRunning = true;
while (gameRunning) {
if (SDL_PollEvent(&event))
gameRunning = event.type != SDL_QUIT;
}
SDL_Quit();
return 0;
}
代码是通过链接到sdl库才能工作的。现在改成这样
#include "dllapi/SDL/SDL.h"
using namespace DllAPI::SDL;
int main()
{
SDL_Init(SDL_INIT_VIDEO);
SDL_SetVideoMode(640, 480, 0, SDL_HWSURFACE | SDL_DOUBLEBUF);
SDL_WM_SetCaption("SDL Start", 0);
SDL_Event event;
bool gameRunning = true;
while (gameRunning) {
if (SDL_PollEvent(&event))
gameRunning = event.type != SDL_QUIT;
}
SDL_Quit();
return 0;
}
只是修改了包含路径和加了namespace,其他代码不变,就变成不用链接sdl运行时动态解析的版本了。当然如果你愿意的话,include路径也可以不变,只要编译参数加个CPATH,INCLUDE之类的,namespace也可以不加,只要在
dllapi/SDL/SDL.h
加上using namespace DLLAPI:SDL; 这样等于不修改原来的代码了!
dllapi/SDL/SDL.h是什么?
要实现那样的功能,自己还是要其他地方加点代码的,比如dllapi/SDL/SDL.h就是声明了sdl的接口,可以直接复制sdl头文件里的。然后写个SDL.cpp,里面的内容也很简单
#include "dllapi_p.h"
#include "dllapi.h"
#include "SDL.h"
namespace DllAPI {
namespace SDL {
DEFINE_DLL_INSTANCE("SDL")
DEFINE_DLLAPI_ARG(1, int, SDL_Init, Uint32)
DEFINE_DLLAPI_ARG(2, void, SDL_WM_SetCaption, const char*, const char*)
DEFINE_DLLAPI_ARG(1, int, SDL_PollEvent, SDL_Event*)
DEFINE_DLLAPI_ARG(4, SDL_Surface*, SDL_SetVideoMode, int, int, int, Uint32)
DEFINE_DLLAPI_ARG(0, void, SDL_Quit)
} //namespace SDL
} //namespace DllAPI
奥妙都在dllapi.h, dllapi_h里,它们可以让你很方便很有规律地用宏生存代码。
所以是不是应该有个代码自动生成工具来做这些事情而不是手写呢?虽然手写也很简单
是的!我刚开始做这方面的事情,代码在tools/mkapi下。目前是打算用clang来自动生成代码,可能有点杀鸡用牛刀的感觉,可能随便用什么脚本语言解个头文件解析的也蛮方便的。目前功能还不完善,问题也比较多。