AutoSharedLibrary -- 基于模板元编程技术的跨平台C++动态链接加载库

基于模板元编程技术的跨平台C++动态链接加载库。通过模板技术,使用者仅需通过简单的宏,即可使编译器在编译期自动生成加载动态链接库导出符号的代码,无任何额外的运行时开销。

ASL_LIBRARY_BEGIN(TestLib)
    ASL_SYMBOL(Proc_test1, test1, false)
    ASL_SYMBOL(Proc_test2, test2, true)
ASL_LIBRARY_END() 

TestLib theLib;
try { theLib.Load("./1.so"); }
catch (ASL::LibraryNotFoundException& e)
{
    cout << e.what() << endl; // 输出./1.so
}
catch (ASL::SymbolNotFoundException& e)
{
    cout << e.what() << endl; // 输出 加载失败的符号名称
 }

theLib.test1(1); // assert(theLib.test1 != NULL)
theLib.test2("aa");
theLib.Unload();

假定有个一个名为1.so的动态链接库,并且该模块导出test1和test2两个接口。test1的接口类型为Proc_test1, test2的接口类型为Proc_test2。

ASL_SYMBOL宏的第三个参数表示,如果该符号加载失败(模块并没有导出该接口),是否抛出SymbolNotFoundException。 为false时,抛出异常,终止链接库加载流程,并且e.what()为加载失败的符号名称。为true时,忽略错误,仍然继续加载其他符号,客户端可以根据对应的接口是否为NULL来判断该符号是否加载成功。

/********************************************************************
	created:	2014/05/31
	file base:	AutoSharedLibrary
	file ext:	h
	author:		qiuhan ([email protected])

	purpose:	Cross platform classes and macros to make  dynamic link module
                easy to use by using c++ template meta programming technic.

                No need to make any changes to existing module code.

                Support both windows(*.dll) and linux(*.so) platforms (wchar_t & char).

                SPECIAL THANKS TO TRL (Template Relection Library)

    usage:
                Following codes are all in client side:

                ASL_LIBRARY_BEGIN(ClassName)
                    ASL_SYMBOL(Proc_func1, func1, true)
                    ASL_SYMBOL(Proc_func2, func2, false)
                ASL_LIBRARY_END()

                ClassName theLib;
                try {
                    theLib.Load("./1.so");
                }
                catch (ASL::LibraryNotFoundException& e) {
                }
                catch (ASL::SymbolNotFoundException& e) {
                }
                theLib.func1(1);
                theLib.func2("aa");
                theLib.Unload();

*********************************************************************/

#ifndef ASL_INCLUDE_H
#define  ASL_INCLUDE_H

#ifdef WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif

#include <cstdlib>
#include <exception>
#include <string>

namespace ASL {

    namespace Private {

        template <class Head_, class Tail_>
        struct TypeList
        {
            typedef Head_ Head;
            typedef Tail_ Tail;
        };

        class NullType {};

        template <int i_>
        struct Int2Type
        {
            enum { value = i_ };
        };

        template <int condition_, class T0_, class T1_>
        struct Select
        {
            typedef T0_ Result;
        };

        template <class T0_, class T1_>
        struct Select<false, T0_, T1_>
        {
            typedef T1_ Result;
        };

        template <int condition_, int v0_, int v1_>
        struct SelectInt
        {
            enum { value = v0_ };
        };

        template <int v0_, int v1_>
        struct SelectInt<false, v0_, v1_>
        {
            enum { value = v1_ };
        };

        template <class Type_, int Ignore_>
        struct MemberInfo
        {
            typedef Type_ Type;
            enum {
                ignore = Ignore_
            };
        };

        template <class TList_, int startLine_, int endLine_, class ConcreteClass_>
        struct CreateMemberIndicesImpl
        {
            typedef typename ConcreteClass_::template IsMemberPresent<endLine_> IsMemberPresent;
            enum { isMemberPresent = IsMemberPresent::value };

            typedef typename Select< isMemberPresent
                , TypeList<MemberInfo<Int2Type<IsMemberPresent::index>, IsMemberPresent::ignoreError >, TList_>
                , TList_ >::Result NewTList;

            typedef CreateMemberIndicesImpl<NewTList, startLine_, endLine_ - 1, ConcreteClass_> MemberIndicesImpl;
            typedef typename MemberIndicesImpl::Indices Indices;
        };

        template <class TList_, int startLine_, class ConcreteClass_>
        struct CreateMemberIndicesImpl<TList_, startLine_, startLine_, ConcreteClass_>
        {
            typedef TList_ Indices;
        };

        template <int startLine_, int endLine_, class ConcreteClass_>
        struct CreateMemberIndices
        {
            typedef CreateMemberIndicesImpl< NullType, startLine_
                , endLine_ - 1, ConcreteClass_ > MemberIndicesImpl;
            typedef typename MemberIndicesImpl::Indices Indices;
        };

        template <class ConcreteClass_, int startLine_, int currentLine_>
        struct GetMemberIndex
        {
            typedef typename ConcreteClass_::template IsMemberPresent<currentLine_> IsMemberPresent;

            enum {
                index = SelectInt< IsMemberPresent::value
                , IsMemberPresent::index
                , GetMemberIndex<ConcreteClass_, startLine_, currentLine_ - 1>::index >::value + 1
            };
        };

        template <class ConcreteClass_, int startLine_>
        struct GetMemberIndex<ConcreteClass_, startLine_, startLine_>
        {
            enum { index = -1 };
        };

    }

    class DefaultLibraryLoader
    {
    public:
        typedef void* LibHandle;

        DefaultLibraryLoader()
        {
            lib_handle = NULL;
        }

        template<class Char_>
        bool Load(const Char_* name)
        {
#if defined(WIN32)
            lib_handle = ::LoadLibrary(name);
#else
            lib_handle = dlopen(name, RTLD_LAZY);
#endif
            return lib_handle != NULL;
        }

        void Unload()
        {
            if (!lib_handle) {
                return;
            }

#if defined(WIN32)
            ::FreeLibrary((HMODULE)lib_handle);
#elif !defined(_ANDROID)
            dlclose(lib_handle);
#endif

            lib_handle = NULL;
        }

        template<class Char_>
        void* LoadSymbol(const Char_* fun_name)
        {
#if defined(WIN32)
            return (void *)::GetProcAddress((HMODULE)lib_handle, fun_name);
#elif !defined(_ANDROID)
            return dlsym(lib_handle, fun_name);
#endif
        }

    private:
        LibHandle lib_handle;
    };

    class LibraryNotFoundException : public std::exception
    {
    public:
        LibraryNotFoundException(const char* err)
        {
            _err = err;
        }

        LibraryNotFoundException(const wchar_t* err)
        {
            static const size_t CONVERT_LEN = 256;

            char mbsBuff[CONVERT_LEN + 1] = { 0 };
            std::wcstombs(mbsBuff, err, CONVERT_LEN);
            _err = mbsBuff;
        }

        ~LibraryNotFoundException() throw() {}

        virtual const char* what() const throw() {
            return _err.c_str();
        }
    private:
        std::string _err;
    };

    class SymbolNotFoundException : public std::exception
    {
    public:
        SymbolNotFoundException(const char* err)
        {
            _err = err;
        }

        SymbolNotFoundException(const wchar_t* err)
        {
            static const size_t CONVERT_LEN = 256;

            char mbsBuff[CONVERT_LEN + 1] = { 0 };
            std::wcstombs(mbsBuff, err, CONVERT_LEN);
            _err = mbsBuff;
        }

        ~SymbolNotFoundException() throw() { }

        virtual const char* what() const throw() {
            return _err.c_str();
        }

        std::string _err;
    };

    struct DefaultErrorHandler
    {
        template<class Char_>
        static void OnLoadLibrary(const Char_* libName)
        {
            throw LibraryNotFoundException(libName);
        }

        template<class Char_>
        static void OnLoadSymbol(const Char_* symbolName, const bool ignore)
        {
            if (!ignore) {
                throw SymbolNotFoundException(symbolName);
            }
        }
    };

    template < class ConcreteClass_,
                    class Loader_ = DefaultLibraryLoader,
                    class ErrorHandler_ = DefaultErrorHandler >
    class AutoSharedLibrary
    {
    public:
        AutoSharedLibrary()
        {
        }

        ~AutoSharedLibrary()
        {
            Unload();
        }

        template<class Char_>
        void Load(ConcreteClass_& object, const Char_* p)
        {
            if (!_loader.Load(p)) {
                ErrorHandler_::OnLoadLibrary(p);
            }
            typedef typename ConcreteClass_::MemberIndices Indices;
            LoadSymbols(object, Indices());
        }

        void Unload()
        {
            _loader.Unload();
        }

    private:
        template <class Indices_>
        void LoadSymbols(ConcreteClass_& object, Indices_ indices)
        {
            typedef typename Indices_::Head SymInfo;
            typedef typename SymInfo::Type Index;

            bool ret = LoadSymbol(object.getLoadName(Index()),
                object.*ConcreteClass_::getMemberPtr(Index()));
            if (!ret) {
                ErrorHandler_::OnLoadSymbol(object.getLoadName(Index()), (bool)SymInfo::ignore);
            }
            LoadSymbols(object, typename Indices_::Tail());
        }

        void LoadSymbols(ConcreteClass_& object, Private::NullType indices)
        {
        }

        template <class FuncType_, class Char_>
        bool LoadSymbol(const Char_* funcName, FuncType_& func)
        {
            func = (FuncType_)_loader.LoadSymbol(funcName);
            return func != NULL;
        }

        Loader_ _loader;
    };

}

#define ASL_LIBRARY_BEGIN(ConcreteClass_)     ASL_LIBRARY_BEGIN_2(ConcreteClass_, ASL::DefaultLibraryLoader, ASL::DefaultErrorHandler)

#define ASL_LIBRARY_BEGIN_2(ConcreteClass_, LibraryLoader_, ErrorHandler_) class ConcreteClass_ {                                  private:                                                    typedef ConcreteClass_ ConcreteClass;               enum { startLine = __LINE__ };                              ASL::AutoSharedLibrary<ConcreteClass_, LibraryLoader_, ErrorHandler_> _libLoader;  public:                                                     ConcreteClass_() { }                                        ~ConcreteClass_() { Unload(); }                             template<class Char_> void Load(const Char_* p)     {                                                           _libLoader.Load(*this, p);                          }                                                           void Unload()                                       {                                                           _libLoader.Unload();                                }                                                           template <int lineNb_, class Dummy_ = ASL::Private::NullType> struct IsMemberPresent                                  {                                                    enum { value = false };                                 enum { index = 0 };                                     enum { ignoreError = false };                           };

#define ASL_SYMBOL_2(DataType, name, loadName, ignoreNotFound)          public:                                                     DataType name;                                      private:                                                    typedef DataType ConcreteClass::* MemberPtr##name;  public:                                                     template <class Dummy_>                             struct IsMemberPresent<__LINE__, Dummy_>                {                                                    enum { value = true };                                  enum { index = ASL::Private::GetMemberIndex<                ConcreteClass, startLine, __LINE__ - 1>::index }; enum { ignoreError = ignoreNotFound};           };                                                      static const char* getLoadName(                         ASL::Private::Int2Type<IsMemberPresent<__LINE__>::index >) { return #loadName; }                               static MemberPtr##name getMemberPtr(                ASL::Private::Int2Type< IsMemberPresent<__LINE__>::index >) { return &ConcreteClass::name; }

#define ASL_SYMBOL(DataType, name, ignoreNotFound) ASL_SYMBOL_2(DataType, name, name, ignoreNotFound)

#define ASL_LIBRARY_END()                               private:                                                enum { endLine = __LINE__ };                            public:                                                     typedef ASL::Private::CreateMemberIndices<startLine, endLine, ConcreteClass>     ::Indices MemberIndices;                            };

#endif

AutoSharedLibrary -- 基于模板元编程技术的跨平台C++动态链接加载库,布布扣,bubuko.com

时间: 2024-10-11 01:15:40

AutoSharedLibrary -- 基于模板元编程技术的跨平台C++动态链接加载库的相关文章

AutoSharedLibrary -- 基于模板元编程技术的跨平台C++动态链接载入库

基于模板元编程技术的跨平台C++动态链接载入库.通过模板技术,使用者仅需通过简单的宏,就可以使编译器在编译期自己主动生成载入动态链接库导出符号的代码,无不论什么额外的执行时开销. extern "C" { typedef int(*Proc_fnTestDll)(); typedef const char* (*Proc_fnTestDll2)(const char*); } ASL_LIBRARY_BEGIN(Test) // 强制载入名为fnTestDll的接口,假设没有该接口.则

【C/C++学院】0816-引用包装器/仿函数/转义字符 R”()”/using别名/模板元编程 比递归优化/智能指针/多线程/静态断言以及调试技能的要求 assert

引用包装器  std::ref(变量) #include<iostream> template<class T> void com(T arg)//模板函数,引用无效,引用包装器 { std::cout <<"com ="<< &arg << "\n"; arg++; } void main() { int count = 10; int & rcount = count; com(coun

读书笔记 effective c++ Item 48 了解模板元编程

1. TMP是什么? 模板元编程(template metaprogramming TMP)是实现基于模板的C++程序的过程,它能够在编译期执行.你可以想一想:一个模板元程序是用C++实现的并且可以在C++编译器内部运行的一个程序,它的输出——从模板中实例化出来的C++源码片段——会像往常一样被编译. 2. 使用TMP的优势 如果这没有冲击到你,是因为你没有足够尽力去想. C++不是为了模板元编程而设计的,但是自从TMP早在1990年被发现之后,它就被证明是非常有用的,为了使TMP的使用更加容易

Item 48:了解模板元编程

Item 48: Be aware of template metaprogramming. 模板元编程(Template Metaprogramming,TMP)就是利用模板来编写那些在编译时运行的C++程序. 模板元程序(Template Metaprogram)是由C++写成的,运行在编译器中的程序.当程序运行结束后,它的输出仍然会正常地编译. C++并不是为模板元编程设计的,但自90年代以来,模板元编程的用处逐渐地被世人所发现. 模板编程提供的很多便利在面向对象编程中很难实现: 程序的工

C++模板元编程 - 3 逻辑结构,递归,一点列表的零碎,一点SFINAE

本来想把scanr,foldr什么的都写了的,一想太麻烦了,就算了,模板元编程差不多也该结束了,离开学还有10天,之前几天部门还要纳新什么的,写不了几天代码了,所以赶紧把这个结束掉,明天继续抄轮子叔的Win32库去. 逻辑结构和递归说白了就是做了一个If,一个For_N,If就和Excel里的If一样,For_N是把一个模板结构迭代N遍,为了所谓的方便,把If做成了宏,写起来还挺有意思的 1 template<typename TTest, typename TTrue, typename TF

C++模板元编程 - 2 模仿haskell的列表以及相关操作

这是昨天和今天写的东西,利用C++的可变模板参数包以及包展开,模式匹配的一些东西做的,感觉用typename...比轮子叔那个List<A,List<B, List<C, D>>>的设计要好看不少. List有一个很巧妙的继承,只有那么做才能使用类似于List<>::Rest的写法,直接定义成template<typename T, typename... TArgs>List是不行的. Change这里可以给一个args...换另一个包装,这里

C++拾遗--模板元编程

C++拾遗--模板元编程 前言 模板元是用于递归加速的,把运行期的函数调用变到编译期进行代码展开,类似于内联函数.下面看一个实例:斐波那契数列第n项求解. 模板元编程 #include <iostream> #include <ctime> using namespace std; //递归法 int fib(int n) { if (n < 0) return 0; if (n == 1 || n == 2) return 1; return fib(n - 1) + fi

模板元编程

//模板元把运行时消耗的时间,在编译期间优化 //递归极其消耗时间 1 #include <iostream> 2 3 //模板元把运行时消耗的时间,在编译期间优化 4 //递归极其消耗时间 5 6 template <int N> 7 struct data 8 { 9 enum { res = data<N - 1>::res + data<N - 2>::res }; 10 }; 11 12 template <> 13 struct da

初识C++模板元编程(Template Mega Programming)

前言:毕设时在开源库上做的程序,但是源码看得很晕(当时导师告诉我这是模板元编程,可以不用太在乎),最近自己造轮子时想学习STL的源码,但也是一样的感觉,大致了解他这么做要干什么,但是不知道里面的机制.于是开始学习<C++模板元编程>,看完第二章对一些东西豁然开朗. PS:该书也有点老了,C++11标准还没出来,主要用的Boost库. Traits(特征) 说正题,在STL中经常可以见到后缀为traits的名字,比如经常用到的std::string,本质是类模板basic_string的第一个参