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

来源:互联网 发布:java定时器 任务超时 编辑:程序博客网 时间:2024/04/30 14:41

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


[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. extern "C"  
  2. {  
  3.     typedef int(*Proc_fnTestDll)();  
  4.     typedef const char* (*Proc_fnTestDll2)(const char*);  
  5. }  
  6.   
  7.   
  8. ASL_LIBRARY_BEGIN(Test)  
  9.     // 强制加载名为fnTestDll的接口,如果没有该接口,则抛SymbolNotFound异常  
  10.     ASL_SYMBOL_EXPLICIT(Proc_fnTestDll, fnTestDll)  
  11.  // 加载名为<span style="font-family: Arial, Helvetica, sans-serif;">fnTestDll2的接口,如果没有该接口,则为NULL</span>  
  12. ASL_SYMBOL_OPTIONAL(Proc_fnTestDll2, fnTestDll2)  
  13. // 加载名为shouldFail的接口,如果没有该接口,则为NULL</span>  
  14. ASL_SYMBOL_OPTIONAL(Proc_fnTestDll2, shouldFail) // non-exists  
  15.     // 加载名为testFunc的接口,接口函数的类型由调用时的实参类型决定  
  16.     ASL_SYMBOL_EXPLICIT_T(testFunc) // Enabled only when ' #define  ASL_USE_CPP11 1 ' and compliler supports c++ 11  
  17. ASL_LIBRARY_END()  
  18.   
  19. int _tmain(int argc, _TCHAR* argv[])  
  20. {  
  21.     using namespace std;  
  22.   
  23.     Test test;  
  24.   
  25.     try {  
  26.         test.Load(_T("testDll.dll"));  
  27.     }  
  28.     catch (const ASL::LibraryNotFoundException& e)  
  29.     {  
  30.         cout << "Lib not found " <<  e.what() << endl;  
  31.     }  
  32.     catch (const ASL::SymbolNotFoundException& e) {  
  33.         cout << "Sym not found " <<  e.what() << endl;  
  34.     }  
  35.   
  36.     assert(test.shouldFail == NULL);  
  37.     cout << test.fnTestDll() << endl;  
  38.     cout << test.fnTestDll2("hELLO, WORLD") << endl;  
  39.  // testFunc函数的签名由此处的实参类型推导出来,int为其返回值类型,  
  40.     // 这种调用方式并不安全,慎用!  
  41.    cout << test.testFunc<int>(ASL_ARGS_T((int)1, (int)2.f)) << endl;  
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. test.Unload();  
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. getchar();  
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. return 0;  
[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. }  

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

[cpp] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. /******************************************************************** 
  2.     created:    2014/05/31 
  3.     file base:  AutoSharedLibrary 
  4.     file ext:   h 
  5.     author:     qiuhan (hanzz2007@hotmail.com) 
  6.  
  7.     purpose:    Cross platform classes and macros to make dynamic loaded module 
  8.     easy to use by using c++ template meta-programming technic. 
  9.  
  10.     No need to make any changes to existing module code. 
  11.  
  12.     Support both windows(*.dll) and linux(*.so) platforms (wchar_t & char). 
  13.  
  14.     SPECIAL THANKS TO TRL (Template Relection Library) 
  15.  
  16.     usage: 
  17.     Following codes are all in client side: 
  18.  
  19.     ASL_LIBRARY_BEGIN(ClassName) 
  20.         ASL_SYMBOL_OPTIONAL(Func1Type, func1) 
  21.         ASL_SYMBOL_EXPLICIT(Func2Type, func2) 
  22.         // Enabled only when ' #define  ASL_USE_CPP11 1 ' and compliler supports c++ 11 
  23.         ASL_SYMBOL_EXPLICIT_T(func4) // only need to declare the name 
  24.     ASL_LIBRARY_END() 
  25.  
  26.     ClassName theLib; 
  27.     try { 
  28.     theLib.Load("./1.so"); 
  29.     } 
  30.     catch (LibraryNotFoundException& e) { 
  31.     } 
  32.     catch (SymbolNotFoundException& e) { 
  33.     } 
  34.     theLib.func1(1); 
  35.     theLib.func2("aa"); 
  36.  
  37.     // The function type is deduced with the args 
  38.     // retType => int, args => const char* AND float 
  39.     // So this calling is UNSAFE! 
  40.     // You'd better explicitly specifiy the type of args like this 
  41.     theLib.func4<int>(ASL_ARGS_T((const char*)"test", (float)2.3)); 
  42.  
  43.     theLib.Unload(); 
  44.  
  45.  
  46. *********************************************************************/  
  47.   
  48. #ifndef ASL_INCLUDE_H  
  49. #define  ASL_INCLUDE_H  
  50.   
  51. #ifdef WIN32  
  52. #include <windows.h>  
  53. #else  
  54. #include <dlfcn.h>  
  55. #endif  
  56.   
  57.   
  58. #include <cstdlib>  
  59. #include <exception>  
  60. #include <string>  
  61.   
  62. #if ASL_USE_CPP11  
  63. #include <functional>  
  64. #include <tuple>  
  65. #endif  
  66.   
  67.   
  68. namespace ASL {  
  69.   
  70.     namespace Private {  
  71.   
  72.         template <class Head_, class Tail_>  
  73.         struct TypeList  
  74.         {  
  75.             typedef Head_ Head;  
  76.             typedef Tail_ Tail;  
  77.         };  
  78.   
  79.         class NullType {};  
  80.   
  81.         template <int i_>  
  82.         struct Int2Type  
  83.         {  
  84.             enum { value = i_ };  
  85.         };  
  86.   
  87.         template <int condition_, class T0_, class T1_>  
  88.         struct Select  
  89.         {  
  90.             typedef T0_ Result;  
  91.         };  
  92.   
  93.         template <class T0_, class T1_>  
  94.         struct Select<false, T0_, T1_>  
  95.         {  
  96.             typedef T1_ Result;  
  97.         };  
  98.   
  99.         template <int condition_, int v0_, int v1_>  
  100.         struct SelectInt  
  101.         {  
  102.             enum { value = v0_ };  
  103.         };  
  104.   
  105.         template <int v0_, int v1_>  
  106.         struct SelectInt<false, v0_, v1_>  
  107.         {  
  108.             enum { value = v1_ };  
  109.         };  
  110.   
  111.         template <class Type_, int Ignore_>  
  112.         struct MemberInfo  
  113.         {  
  114.             typedef Type_ Type;  
  115.             enum {  
  116.                 ignore = Ignore_  
  117.             };  
  118.         };  
  119.   
  120.   
  121.         template <class TList_, int startLine_, int endLine_, class ConcreteClass_>  
  122.         struct CreateMemberIndicesImpl  
  123.         {  
  124.             typedef typename ConcreteClass_::template IsMemberPresent<endLine_> IsMemberPresent;  
  125.             enum { isMemberPresent = IsMemberPresent::value };  
  126.   
  127.             typedef typename Select< isMemberPresent  
  128.                 , TypeList<MemberInfo<Int2Type<IsMemberPresent::index>, IsMemberPresent::ignoreError >, TList_>  
  129.                 , TList_ >::Result NewTList;  
  130.   
  131.             typedef CreateMemberIndicesImpl<NewTList, startLine_, endLine_ - 1, ConcreteClass_> MemberIndicesImpl;  
  132.             typedef typename MemberIndicesImpl::Indices Indices;  
  133.         };  
  134.   
  135.   
  136.         template <class TList_, int startLine_, class ConcreteClass_>  
  137.         struct CreateMemberIndicesImpl<TList_, startLine_, startLine_, ConcreteClass_>  
  138.         {  
  139.             typedef TList_ Indices;  
  140.         };  
  141.   
  142.   
  143.         template <int startLine_, int endLine_, class ConcreteClass_>  
  144.         struct CreateMemberIndices  
  145.         {  
  146.             typedef CreateMemberIndicesImpl< NullType, startLine_  
  147.                 , endLine_ - 1, ConcreteClass_ > MemberIndicesImpl;  
  148.             typedef typename MemberIndicesImpl::Indices Indices;  
  149.         };  
  150.   
  151.   
  152.         template <class ConcreteClass_, int startLine_, int currentLine_>  
  153.         struct GetMemberIndex  
  154.         {  
  155.             typedef typename ConcreteClass_::template IsMemberPresent<currentLine_> IsMemberPresent;  
  156.   
  157.             enum {  
  158.                 index = SelectInt< IsMemberPresent::value  
  159.                 , IsMemberPresent::index  
  160.                 , GetMemberIndex<ConcreteClass_, startLine_, currentLine_ - 1>::index >::value + 1  
  161.             };  
  162.         };  
  163.   
  164.         template <class ConcreteClass_, int startLine_>  
  165.         struct GetMemberIndex<ConcreteClass_, startLine_, startLine_>  
  166.         {  
  167.             enum { index = -1 };  
  168.         };  
  169.   
  170.   
  171. #if ASL_USE_CPP11  
  172.         typedef void* FuncType;  
  173.   
  174.         // Pack of numbers.  
  175.         // Nice idea, found at http://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer  
  176.         template<int ...> struct Seq {};  
  177.   
  178.         // Metaprogramming Expansion  
  179.         template<int N, int ...S> struct GenList : GenList < N - 1, N - 1, S... > {};  
  180.         template<int ...S> struct GenList < 0, S... >  
  181.         {  
  182.             typedef Seq<S...> Result;  
  183.         };  
  184.   
  185.             // Function that performs the actual call  
  186.             template<typename Ret_, int ...S_, typename...Args_>  
  187.             Ret_ ActualCall(Seq<S_...>, std::tuple<Args_...> tpl, const std::function<Ret_(Args_...)>& func)  
  188.             {  
  189.                 // It calls the function while expanding the std::tuple to it's arguments via std::get<S>  
  190.                 return func(std::get<S_>(tpl) ...);  
  191.             }  
  192. #endif  
  193.     }  
  194.   
  195.     class DefaultLibraryLoader  
  196.     {  
  197.     public:  
  198.         typedef void* LibHandle;  
  199.   
  200.         DefaultLibraryLoader()  
  201.         {  
  202.             lib_handle = NULL;  
  203.         }  
  204.   
  205.         template<class Char_>  
  206.         bool Load(const Char_* name)  
  207.         {  
  208. #if defined(WIN32)  
  209.             lib_handle = LoadLibrary(name);  
  210. #else  
  211.             lib_handle = dlopen(name, RTLD_LAZY);  
  212. #endif  
  213.             return lib_handle != NULL;  
  214.         }  
  215.   
  216.         void Unload()  
  217.         {  
  218.             if (!IsLoaded()) {  
  219.                 return;  
  220.             }  
  221.   
  222. #if defined(WIN32)  
  223.             FreeLibrary((HMODULE)lib_handle);  
  224. #elif !defined(_ANDROID)  
  225.             dlclose(lib_handle);  
  226. #endif  
  227.   
  228.             lib_handle = NULL;  
  229.         }  
  230.   
  231.         template<class Char_>  
  232.         void* LoadSymbol(const Char_* fun_name)  
  233.         {  
  234. #if defined(WIN32)  
  235.             return (void *)GetProcAddress((HMODULE)lib_handle, fun_name);  
  236. #elif !defined(_ANDROID)  
  237.             return dlsym(lib_handle, fun_name);  
  238. #endif  
  239.         }  
  240.   
  241.         bool IsLoaded() const  
  242.         {  
  243.             return lib_handle != NULL;  
  244.         }  
  245.   
  246.     private:  
  247.         LibHandle lib_handle;  
  248.     };  
  249.   
  250.     class LibraryNotFoundException : public std::exception  
  251.     {  
  252.     public:  
  253.         LibraryNotFoundException(const char* err)  
  254.         {  
  255.             _err = err;  
  256.         }  
  257.   
  258.         LibraryNotFoundException(const wchar_t* err)  
  259.         {  
  260.             static const size_t CONVERT_LEN = 256;  
  261. #if _MSC_VER  
  262. #pragma warning(push)  
  263. #pragma warning(disable: 4996)  
  264. #endif  
  265.             char mbsBuff[CONVERT_LEN + 1] = { 0 };  
  266.             std::wcstombs(mbsBuff, err, CONVERT_LEN);  
  267.             _err = mbsBuff;  
  268. #if _MSC_VER  
  269. #pragma warning(pop)  
  270. #endif  
  271.         }  
  272.   
  273.         ~LibraryNotFoundException() throw() {}  
  274.   
  275.         virtual const char* what() const throw() {  
  276.             return _err.c_str();  
  277.         }  
  278.     private:  
  279.         std::string _err;  
  280.     };  
  281.   
  282.     class SymbolNotFoundException : public std::exception  
  283.     {  
  284.     public:  
  285.         SymbolNotFoundException(const char* err)  
  286.         {  
  287.             _err = err;  
  288.         }  
  289.   
  290.         SymbolNotFoundException(const wchar_t* err)  
  291.         {  
  292.             static const size_t CONVERT_LEN = 256;  
  293. #if _MSC_VER  
  294. #pragma warning(push)  
  295. #pragma warning(disable: 4996)  
  296. #endif  
  297.             char mbsBuff[CONVERT_LEN + 1] = { 0 };  
  298.             std::wcstombs(mbsBuff, err, CONVERT_LEN);  
  299.             _err = mbsBuff;  
  300. #if _MSC_VER  
  301. #pragma warning(pop)  
  302. #endif  
  303.         }  
  304.   
  305.         ~SymbolNotFoundException() throw() { }  
  306.   
  307.         virtual const char* what() const throw() {  
  308.             return _err.c_str();  
  309.         }  
  310.   
  311.     private:  
  312.         std::string _err;  
  313.     };  
  314.   
  315.     struct DefaultErrorHandler  
  316.     {  
  317.         template<class Char_>  
  318.         static void OnLoadLibrary(const Char_* libName)  
  319.         {  
  320.             throw LibraryNotFoundException(libName);  
  321.         }  
  322.   
  323.         template<class Char_>  
  324.         static void OnLoadSymbol(const Char_* symbolName, const bool ignore)  
  325.         {  
  326.             if (!ignore) {  
  327.                 throw SymbolNotFoundException(symbolName);  
  328.             }  
  329.         }  
  330.     };  
  331.   
  332.     template < class ConcreteClass_,  
  333.                 class Loader_ = DefaultLibraryLoader,  
  334.                 class ErrorHandler_ = DefaultErrorHandler >  
  335.     class AutoSharedLibrary  
  336.     {  
  337.     public:  
  338.         AutoSharedLibrary()  
  339.         {  
  340.         }  
  341.   
  342.         ~AutoSharedLibrary()  
  343.         {  
  344.             Unload();  
  345.         }  
  346.   
  347.         template<class Char_>  
  348.         void Load(ConcreteClass_& object, const Char_* p)  
  349.         {  
  350.             if (!_loader.Load(p)) {  
  351.                 ErrorHandler_::OnLoadLibrary(p);  
  352.             }  
  353.             typedef typename ConcreteClass_::MemberIndices Indices;  
  354.             LoadSymbols(object, Indices());  
  355.         }  
  356.   
  357.         void Unload()  
  358.         {  
  359.             _loader.Unload();  
  360.         }  
  361.   
  362.     private:  
  363.         template <class Indices_>  
  364.         void LoadSymbols(ConcreteClass_& object, Indices_ indices)  
  365.         {  
  366.             typedef typename Indices_::Head SymInfo;  
  367.             typedef typename SymInfo::Type Index;  
  368.   
  369.             bool ret = LoadSymbol(ConcreteClass_::getLoadName(Index()),  
  370.                 object.*ConcreteClass_::getMemberPtr(Index()));  
  371.             if (!ret) {  
  372.                 ErrorHandler_::OnLoadSymbol(ConcreteClass_::getLoadName(Index()), (bool)SymInfo::ignore);  
  373.             }  
  374.             LoadSymbols(object, typename Indices_::Tail());  
  375.         }  
  376.   
  377.         void LoadSymbols(ConcreteClass_& object, Private::NullType indices)  
  378.         {  
  379.         }  
  380.   
  381.         template <class FuncType_, class Char_>  
  382.         bool LoadSymbol(const Char_* funcName, FuncType_& func)  
  383.         {  
  384.             func = (FuncType_)_loader.LoadSymbol(funcName);  
  385.             return func != NULL;  
  386.         }  
  387.   
  388.         Loader_ _loader;  
  389.     };  
  390.   
  391. }  
  392.   
  393. #define ASL_LIBRARY_BEGIN(ConcreteClass_) \  
  394.     ASL_LIBRARY_BEGIN_2(ConcreteClass_, ASL::DefaultLibraryLoader, ASL::DefaultErrorHandler)  
  395.   
  396. #define ASL_LIBRARY_BEGIN_2(ConcreteClass_, LibraryLoader_, ErrorHandler_) \  
  397. class ConcreteClass_ {                                  \  
  398. private:                                                \  
  399.     typedef ConcreteClass_ ConcreteClass;               \  
  400. enum { startLine = __LINE__ };                          \  
  401.     ASL::AutoSharedLibrary<ConcreteClass_, LibraryLoader_, ErrorHandler_> _libLoader;  \  
  402. public:                                                 \  
  403.     ConcreteClass_() { }                                \  
  404.     \  
  405.     ~ConcreteClass_() { Unload(); }                     \  
  406.     \  
  407.     template<class Char_> void Load(const Char_* p)     \  
  408. {                                                       \  
  409.     _libLoader.Load(*this, p);                          \  
  410. }                                                       \  
  411.     void Unload()                                       \  
  412. {                                                       \  
  413.     _libLoader.Unload();                                \  
  414. }                                                       \  
  415.     template <int lineNb_, class Dummy_ = ASL::Private::NullType> \  
  416. struct IsMemberPresent                                  \  
  417. {                                                    \  
  418. enum { value = false };                                 \  
  419. enum { index = 0 };                                     \  
  420. enum { ignoreError = false };                           \  
  421. };  
  422.   
  423. #define ASL_SYMBOL(DataType, name, loadName, ignoreNotFound)          \  
  424. public:                                                 \  
  425.     DataType name;                                      \  
  426. private:                                                \  
  427.     typedef DataType ConcreteClass::* MemberPtr##name;  \  
  428. public:                                                 \  
  429.     template <class Dummy_>                             \  
  430. struct IsMemberPresent<__LINE__, Dummy_>                \  
  431. {                                                    \  
  432. enum { value = true };                                  \  
  433. enum { index = ASL::Private::GetMemberIndex<            \  
  434.     ConcreteClass, startLine, __LINE__ - 1>::index }; \  
  435. enum { ignoreError = ignoreNotFound};           \  
  436. };                                                  \  
  437.     static const char* getLoadName(                     \  
  438.     ASL::Private::Int2Type<IsMemberPresent<__LINE__>::index >) \  
  439. return #loadName; }                           \  
  440.     static MemberPtr##name getMemberPtr(            \  
  441.     ASL::Private::Int2Type< IsMemberPresent<__LINE__>::index >) \  
  442. return &ConcreteClass::name; }  
  443.   
  444. #if ASL_USE_CPP11  
  445.   
  446. #define ASL_SYMBOL_T(name, loadName, ignoreNotFound)                    \  
  447.         ASL_SYMBOL(ASL::Private::FuncType, name##_private_, loadName, ignoreNotFound)   \  
  448.         template<class Ret_, class... Args_> Ret_ name (std::tuple<Args_...> args)      \  
  449.         { \  
  450.             typedef Ret_(*FuncPointer)(Args_...); \  
  451.             std::function<Ret_(Args_...)> func = reinterpret_cast<FuncPointer>(name##_private_);  \  
  452.             return ASL::Private::ActualCall(typename ASL::Private::GenList<sizeof...(Args_)>::Result(), args, func); \  
  453.         }  
  454.   
  455. #define ASL_SYMBOL_EXPLICIT_T(name) \  
  456.         ASL_SYMBOL_T(name, name, false)  
  457.   
  458. #define ASL_ARGS_T(...) (std::make_tuple<>(__VA_ARGS__))  
  459.   
  460. #endif  
  461.   
  462. #define ASL_SYMBOL_DEFAULT(DataType, name, ignoreNotFound) \  
  463.         ASL_SYMBOL(DataType, name, name, ignoreNotFound)  
  464.   
  465. #define ASL_SYMBOL_OPTIONAL(DataType, name) \  
  466.         ASL_SYMBOL_DEFAULT(DataType, name, true)  
  467.   
  468. #define ASL_SYMBOL_EXPLICIT(DataType, name) \  
  469.         ASL_SYMBOL_DEFAULT(DataType, name, false)  
  470.   
  471.   
  472. #define ASL_LIBRARY_END()                               \  
  473. private:                                                \  
  474. enum { endLine = __LINE__ };                            \  
  475. public:                                                 \  
  476.     typedef ASL::Private::CreateMemberIndices<startLine, endLine, ConcreteClass> \  
  477.     ::Indices MemberIndices;                            \  
  478. };  
  479.   
  480. #endif  
0 0
原创粉丝点击