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对方的头文件包含宏,这样就可以任意次在不同的头文件中

成对使用这两个头文件包含了

posted @ 2013-12-16 20:31  日月王  阅读(382)  评论(0编辑  收藏  举报