xbmc的静态链接办法
xbmc的静态链接办法
XBMC是一个相当酷的音频/视频播放器,号称家庭影视中心。
我是希望静态将一些库链接进可执行程序的,这样我用的ArchLinux就不用天天在更新一些东西了
但XBMC试了很多次,编译成功后,总是在运行是段错误。
后面没办法,走读代码发现XBMC使用了一个很巧妙的办法实现动态链接库的载入。
XBMC定义了一个动态链接类DllDynamic,其中定义了Load/UnLoad/IsLoaded/ResolveExports几个接口
然后定义了一堆宏用于新类继承DllDynamic实现指定库的动态载入。
DynamicDll.h
DynamicDll.cpp
一个类继承自DllDynamic,按指定格式定义函数接口后,就可以较轻易的实现动态链接一个新库
比如:
#pragma once
/*
* Copyright (C) 2005-2012 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with XBMC; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*
*/
#if (defined HAVE_CONFIG_H) && (!defined WIN32)
#include "config.h"
#endif
/* undefine byte from PlatformDefs.h since it's used in mad.h */
#undef byte
#if defined(_LINUX) || defined(TARGET_DARWIN)
#include <mad.h>
#else
#include "libmad/mad.h"
#endif
#include "DynamicDll.h"
class DllLibMadInterface
{
public:
virtual ~DllLibMadInterface() {}
virtual void mad_synth_init(struct mad_synth *)=0;
virtual void mad_stream_init(struct mad_stream *)=0;
virtual void mad_frame_init(struct mad_frame *)=0;
virtual void mad_stream_finish(struct mad_stream *)=0;
virtual void mad_frame_finish(struct mad_frame *)=0;
virtual void mad_stream_buffer(struct mad_stream *, unsigned char const *, unsigned long)=0;
virtual void mad_synth_frame(struct mad_synth *, struct mad_frame const *)=0;
virtual int mad_frame_decode(struct mad_frame *, struct mad_stream *)=0;
virtual int mad_stream_sync(struct mad_stream *) = 0;
virtual char const* mad_stream_errorstr(struct mad_stream const *) = 0;
virtual void mad_frame_mute(struct mad_frame *) = 0;
virtual void mad_synth_mute(struct mad_synth *) = 0;
virtual void mad_timer_add(mad_timer_t *, mad_timer_t) = 0;
virtual mad_timer_t Get_mad_timer_zero() = 0;
};
class DllLibMad : public DllDynamic, DllLibMadInterface
{
DECLARE_DLL_WRAPPER(DllLibMad, DLL_PATH_LIBMAD)
DEFINE_METHOD1(void, mad_synth_init, (struct mad_synth * p1))
DEFINE_METHOD1(void, mad_stream_init, (struct mad_stream * p1))
DEFINE_METHOD1(void, mad_frame_init, (struct mad_frame * p1))
DEFINE_METHOD1(void, mad_stream_finish, (struct mad_stream * p1))
DEFINE_METHOD1(void, mad_frame_finish, (struct mad_frame * p1))
DEFINE_METHOD3(void, mad_stream_buffer, (struct mad_stream * p1, unsigned char const *p2, unsigned long p3))
DEFINE_METHOD2(void, mad_synth_frame, (struct mad_synth *p1, struct mad_frame const *p2))
DEFINE_METHOD2(int, mad_frame_decode, (struct mad_frame *p1, struct mad_stream *p2))
DEFINE_METHOD1(int, mad_stream_sync, (struct mad_stream *p1))
DEFINE_METHOD1(void, mad_frame_mute, (struct mad_frame *p1))
DEFINE_METHOD1(void, mad_synth_mute, (struct mad_synth *p1))
DEFINE_METHOD2(void, mad_timer_add, (mad_timer_t *p1, mad_timer_t p2))
DEFINE_METHOD1(char const*, mad_stream_errorstr, (struct mad_stream const *p1))
DEFINE_GLOBAL(mad_timer_t, mad_timer_zero)
BEGIN_METHOD_RESOLVE()
RESOLVE_METHOD(mad_synth_init)
RESOLVE_METHOD(mad_stream_init)
RESOLVE_METHOD(mad_frame_init)
RESOLVE_METHOD(mad_stream_finish)
RESOLVE_METHOD(mad_frame_finish)
RESOLVE_METHOD(mad_stream_buffer)
RESOLVE_METHOD(mad_synth_frame)
RESOLVE_METHOD(mad_frame_decode)
RESOLVE_METHOD(mad_stream_sync)
RESOLVE_METHOD(mad_frame_mute)
RESOLVE_METHOD(mad_synth_mute)
RESOLVE_METHOD(mad_timer_add)
RESOLVE_METHOD(mad_stream_errorstr)
RESOLVE_METHOD(mad_timer_zero)
END_METHOD_RESOLVE()
};
想实现静态链接库进来,就得在类继承这儿动手脚
我写了两个头文件,如下:
#ifndef __DEF_STATIC_LIB_METHOD_H__
#define __DEF_STATIC_LIB_METHOD_H__
#undef DECLARE_DLL_WRAPPER
#undef XDECLARE_DLL_WRAPPER
#undef RESOLVE_METHOD
#undef RESOLVE_METHOD_FP
#undef RESOLVE_METHOD_RENAME
#undef RESOLVE_METHOD_RENAME_FP
#define DECLARE_DLL_WRAPPER(classname, dllname) \
XDECLARE_DLL_WRAPPER(classname,dllname)
#define XDECLARE_DLL_WRAPPER(classname, dllname) \
public: \
classname () : DllDynamic( dllname ) {} \
virtual bool Load() { if (m_dll) return true; m_dll = (LibraryLoader*)1; return ResolveExports(); } \
virtual void Unload() { m_dll = 0; }
#define RESOLVE_METHOD(method) \
( m_##method##_ptr = (void*) & :: method ) &&
#define RESOLVE_METHOD_FP(method) \
( method##_ptr = (void*) & :: method ) &&
#define RESOLVE_METHOD_RENAME(dllmethod, method) \
( m_##method##_ptr = (void*) & :: dllmethod ) &&
#define RESOLVE_METHOD_RENAME_FP(dllmethod, method) \
( method##_ptr = (void*) & :: dllmethod ) &&
#undef __DEF_SHARED_SO_METHOD_H__
#endif
#ifndef __DEF_SHARED_SO_METHOD_H__
#define __DEF_SHARED_SO_METHOD_H__
#undef DECLARE_DLL_WRAPPER
#undef XDECLARE_DLL_WRAPPER
#undef RESOLVE_METHOD
#undef RESOLVE_METHOD_FP
#undef RESOLVE_METHOD_RENAME
#undef RESOLVE_METHOD_RENAME_FP
#define DECLARE_DLL_WRAPPER(classname, dllname) \
XDECLARE_DLL_WRAPPER(classname,dllname)
#define XDECLARE_DLL_WRAPPER(classname, dllname) \
public: \
classname () : DllDynamic( dllname ) {}
#define RESOLVE_METHOD(method) \
m_dll->ResolveExport( #method , & m_##method##_ptr ) &&
#define RESOLVE_METHOD_FP(method) \
m_dll->ResolveExport( #method , & method##_ptr ) &&
#define RESOLVE_METHOD_RENAME(dllmethod, method) \
m_dll->ResolveExport( #dllmethod , & m_##method##_ptr ) &&
#define RESOLVE_METHOD_RENAME_FP(dllmethod, method) \
m_dll->ResolveExport( #dllmethod , & method##_ptr ) &&
#undef __DEF_STATIC_LIB_METHOD_H__
#endif
如何使用?
只需要在类定义之前包含def_static_lib_method.h,在之后再包含def_shared_so_method.h即可
静态链接的秘诀就在替换了RESOLVE_METHOD那几个宏,将函数调用替换成指针赋值
亮点在于,两个头文件,在末尾分别undef对方的头文件包含宏,这样就可以任意次在不同的头文件中
成对使用这两个头文件包含了