How to make Shared Library in linux OS with C++

How to make Shared Library in linux OS with C++

ابتدا باید در برنامه ای که قصد دارید آن را به کتابخانه عمومی تبدیل کنید، یک رابط مناسب Factory Method برای لینک در زمان اجرا بسازید.

نکته!

توجه داشته باشید که می توانید با استفاده از پلی مورفیسم یک اشاره گر از یک رابط که به صورت مجرد تعریف شده است را در Factory Method کتابخانه خود انتقال دهید.

تابع سازنده رابط کتابخانه را به شکل زیر در Main برنامه کتابخانه تعریف کنید...!

#ifndef __PLUGIN_H__
#define __PLUGIN_H__
 
#include <sstream>
#include <string.h>
  
typedef char* Bytes;
typedef unsigned int size_t;
typedef const char* cBytes;
  
#define DELOBJ(obj)         {if(obj!=NULL){delete obj;obj=NULL;}}
  
enum encryptAloglType {
    BASE64, HASH , MD4 ,MD5 ,OPENSSL
};
  
enum ioType {
    CPP_STREAM , C_LOWLEVEL
};
 
class Encryptor_Interface
{
public:
    virtual ~Encryptor_Interface() {}
  
    virtual void getEncBuffer(Bytes & buffer, cBytes fileName) const = 0;
    virtual void getDecBuffer(std::istringstream** sstream, cBytes fileName) const = 0;
    virtual void setIoType(ioType =C_LOWLEVEL) = 0;
    virtual void setAlgolType(encryptAloglType) = 0;
    virtual void dispose(int) =0;
    virtual size_t getReadedSize() =0;
  
};
  
typedef Plugin_Interface* PluginEnctyptorPtr;
  
#endif // __PLUGIN_H__

در این مرحله بعد از پیاده سازی الگوریتم های متدهای کلاس مجرد ساخته شده باید سورس کتابخانه خود را در لینوکس کامپایل کنید.اگر توزیع لینوکس شما از bash script استفاده میکند می توانید به روش زیر کامپایل را انجام دهید...

gcc -ggdb3 -shared -fPIC libdep.c -o libEncryptor.so

اکنون در این مرحله کافی است که از رابط زیر که من به صورت template نوشته ام به صورتی که اشاره خواهم کرد استفاده نمایید. در این کلاس کافی است که شما رابط مجرد کتابخانه را به صورت اشاره گر ویا در صورتی که متدهای شما در کتابخانه به آرگومانهایی نیاز دارند به همراه آرگومانهای کلاس را به سازنده این کلاس ارسال نمایید.

در این کلاس با استفاده از تکنیک استراتژی شما می توانید انوع رابط های کتابخانه ها را به راحتی استفاده نمایید فقط کافی است که یک کلاس Wrapper بنویسید که کلاس مجرد Solver را به ارث برده باشد و در متد solve این کلاس نحوه پیاده سازی کتابخانه خود را بنویسید.

زمانی که شما در پروژه های خیلی بزرگ کار میکنید که از چند ده کتابخانه مختلف استفاده میکنند به راحتی می توانید از این کلاس ژنریک استفاده نمایید تا هم اتصالات سخت را از بین برده باشید و هم کلاس های سبک رابطی را تهیه کرده اید که اصل Single Responsibility را هم به خوبی راعایت کرده باشید وهم کسانی که از رابط شما استفاده میکنند درگیر جزییات پیاده سازی نخواهند شد.

/*
 * Library_Loader.h
 *
 *  Created on: Jan 1, 2019
 *      Author: f.shiri
 */
  
#ifndef PLUGINLOADER_H_
#define PLUGINLOADER_H_
  
#include "Encryptor_interface.h"
#include <stdexcept>
#include <memory>
#include <dlfcn.h>
  
#define LibEncryptorName "./libEncryptor.so"
#define LibFactoryMethod "create_plugin"
#define LibDestyoryMethod "destroy_plugin"
 
#define LogicFileName    "logic.ini"
#define __CleanupLibClose __attribute__((cleanup(closedl)))
  
#ifdef SCL_EQUIPPED
#include "SCLVoter_Interface.h"
#include "initsclvoter.h"
extern ISCLVoterManager* pSCLVoterManager;
#endif
  
typedef Encryptor_Interface* encAbstractPtr;
//typedef ISCLVoterManager*    pISCLVoter;
/* load shared library or static library and dynamic
 * declare library virtual function.
 * template arg1 : interface class library pointer.
 * */
template<class InterfacePtr>
class PluginLoader {
private:
  
    /*clean up macro function calling by compiler, delete the pointer
     when the pointer's life cycle is end */
    static inline int closedl(void* handle) {
        int tmp = -1;
        if (handle)
            tmp = dlclose(handle);
        handle = NULL;
        return tmp;
    }
   struct {
        /* union data type contained
         * dynamic link library objects.
         * */
        union {
            void* dlsym;
            InterfacePtr (*factoryMethod)();
        } factoryObject;
  
        union {
            void* dlsym;
            bool (*destoryMethod)(InterfacePtr);
        } destroyObject;
  
        /* shared library handler */
   } libraryObject;
  
    void* m_handle;
  
public:
    explicit PluginLoader() {
    }
    ;
    ~PluginLoader() {
    }
    ;
  
    // Dynamic load, encryption function from shared library.
    /*
     * arg1 : shared library name.
     * arg2 : reference factory method name in shared library.
     * arg3 : reference declarative interface class pointer.
     * arg4 : own request for the symbol in library or main executable.
    // arg5 : reference destroy method name in shared library.
     * return type : reference interface pointer.
     */
    template<class CInterfacePtr>
    inline void operator()(cBytes libName, cBytes factoryFuncName,
             CInterfacePtr** pClassInterface,cBytes destroyFuncName =NULL) {
  
        dlerror();
        /*
         * The RTLD_DEEPBIND attribute specifies that when resolving a symbol in a shared library,
         * the symbols in the shared library are put ahead of the global symbol scope.
         * example-> When you load the ???.so, it has it's own request for the symbol.
         * Because you use RTLD_DEEPBIND this definition is looked up in the dependencies of this library first,
         * before looking in the main executable.
         */
        __CleanupLibClose void* m_handle = dlopen(libName, RTLD_DEEPBIND | RTLD_NOW | RTLD_LOCAL);
  
  
        if (!m_handle) {
            throw std::runtime_error(dlerror());
        }
  
        if(factoryFuncName!=NULL){
            if (!(libraryObject.factoryObject.dlsym = dlsym(m_handle, factoryFuncName))) {
                throw std::runtime_error(dlerror());
            }
        }
  
        if(destroyFuncName!=NULL){
            if (!(libraryObject.destroyObject.dlsym = dlsym(m_handle, destroyFuncName))) {
                throw std::runtime_error(dlerror());
            }
        }
  
        *pClassInterface =(*libraryObject.factoryObject.factoryMethod)();
  
    }
  
    template<class CInterfacePtr>
    bool destroy(CInterfacePtr** pClassInterface) {
        return libraryObject.destroyObject.destoryMethod(*pClassI  nterface);
    }
  
private:
    PluginLoader(const PluginLoader&);
    PluginLoader& operator=(const PluginLoader&);
  
};
  
/* this class is invoke strategy shared library wrapper
 * template arg1: reference interface class
 */
template<class InterfacePtr>
class Solver {
public:
    Solver(){};
    Solver(cBytes cLibName, cBytes cFactoryFuncName
            ,cBytes cDestroyFuncName=NULL) :m_interfacePtr(NULL){
        m_pluginLoader(cLibName, cFactoryFuncName,
                &m_interfacePtr ,cDestroyFuncName);
    }
    virtual ~Solver(){
        m_pluginLoader.destroy(&m_interfacePtr);
        DELOBJ(m_interfacePtr);
    }
    // important: this pure virtual method must be implemented in derived class.
    virtual void solve() =0;
  
protected:
    template<class CInterfacePtr>
    inline void getInterface(CInterfacePtr& inputInterFace){
        if(m_interfacePtr!=NULL){
            inputInterFace = m_interfacePtr;
        }
    }
private:
    //shared library interface class member.
    InterfacePtr m_interfacePtr;
    //instance of plugin loader class.
    PluginLoader<InterfacePtr> m_pluginLoader;
};
  
  
  
/*proxy class shared library. this class is immutable type
 * class type: pointer type of shared library interface class.
 * template arg1 : encrypt interface class pointer
 * template arg2 : string stream reference pointer
 * */
template<class InterfacePtr ,typename InputType>
class EncryptLibraryLoader : public Solver<InterfacePtr>{
  
protected:
  
public:
    // arg1 : shared library name.
    // arg2 : reference factory method name in shared library.
    // arg3 : reference destroy method name in shared library.
    // arg4 : output string stream
    EncryptLibraryLoader(InputType outStream ,cBytes cLibName, cBytes cFactoryFuncName
            ,cBytes cDestroyFuncName=NULL) : Solver<InterfacePtr>(cLibName,cFactoryFuncName,cDe  stroyFuncName)
             , m_outStream(outStream) {
        /* important: must be call getInterface in super class and get
         *            interface class reference and copy in member pointer in this class.
         */
        getInterface(m_interfacePtr);
    }
    virtual ~EncryptLibraryLoader() {
        //clean up member pointer
        DELOBJ(m_interfacePtr);
        DELOBJ(m_outStream);
    }
    /* get the byte stream from encrypt logic.ini file.
     * arg1 : reference bytes stream.
     * return type : reference stream pointer
     *
     * important: must be call getInterface in super class and get
     *            interface class reference and copy in member pointer in this class.
     * */
    inline void solve(){
        if(m_outStream!=NULL){
            try {
                if (m_interfacePtr!=NULL) {
                    m_interfacePtr->setIoType(C_LOWLEVEL);
                    m_interfacePtr->getDecBuffer(m_outStream,const_cast<char*> (LogicFileName));
                }
                //important : if interfacePtr is loaded.
                //            this method dispossess member static pointer in memory section of library.
                m_interfacePtr->dispose(0);
            } catch (std::runtime_error& e) {
                printf("%s \n", e.what());
            }
        }
    }
  
private:
    //EncryptLibraryLoader();
    EncryptLibraryLoader(const EncryptLibraryLoader&);
    EncryptLibraryLoader& operator=(const EncryptLibraryLoader&);
  
    //shared library interface class member.
    InterfacePtr m_interfacePtr;
    InputType m_outStream;
};
  
#endif /* PLUGINLOADER_H_ */

و در این مرحله به استفاده از آبجکت های زیر از کتابخانه های خود استفاده نمایید.

std::istringstream* file=NULL ;
{
    Solver<encAbstractPtr> *loader = new    EncryptLibraryLoader<encAbstractPtr,std::istringst  ream**> (
            &file ,LibEncryptorName, LibFactoryMethod , LibDestyoryMethod);
    // initial encryption library.
    loader->solve();
    loader=NULL;
    
}

موفق باشید

I want the real one. Love books. Pretty. :)

Like
Reply

جناب شما منبعی به فارسی برای numpy هم دارید؟ جای محاسبات عددی با پایتون در محاسبات عددی خیلی خالی هست

مثل همیشه بسیار عالی بود آقای شیری ، واقعا مطالبتون خوب و کاربردی هستند 👌👌👌

To view or add a comment, sign in

More articles by Farhad Shiri

  • مقدمه ای از دی اسمبل کردن و مقایسه با دی کامپایلرها

    یک دی کامپایلر فایلهای باینری اجرایی را به صورت قابل خواندن نشان می دهد. به عبارت دقیق تر ، کد دودویی را به متن تبدیل…

  • معماری پردازشگرها کوانتومی

    زبان برنامه نویسی نوعی زبان دستور مدار می باشد که برای رایانه قابل فهم است. زبان برنامه نویسی مکانیزمی ساخت یافته برای…

  • Introduction to TPL Dataflow

    Introductory Examples One of the most common ways into TPL Dataflow is the ActionBlock<TInput> class. This class can be…

  • POSIX IPC-Message Queue in Linux

    یکی از تکنیکهایی که در دنیا برنامه نویسی از اهمیت زیادی برخوردار می باشد، مبحث ارتباطات بین پردازشی در هسته سیستم عامل…

    9 Comments
  • Optimizing and Safety Programming in C ++

    با توجه به اهمیت امنیت نرم افزار، شرکت های بزرگ دنیا به ارائه راهکارهایی چون طراحی زبانها و محیط های برنامه نویسی و…

    5 Comments
  • Device console management in Linux(TTY)

    همانطور که مستحضر هستید، یکی از بلاک دیوایس ها پر کاربرد در لینوکس ترمینال هست یا به تعبیری کنسول هایی که برای اجرای…

    2 Comments
  • Use reflection to dynamic Content Values When using SQLite

    من همیشه با اینکه یک کار تکراری انجام بدم و یک Map Content Values درست کنم برای عملیاتهای Insert / Update برای جداول تو…

  • How To use Fork Join Task Algorithm in Java

    از پرکابردترین الگوریتم های برنامه نویسی چند نخی و عملیاتهای همزمانی الگوریتم تقسیم وغلبه می باشد، به همین علت کتابخانه…

  • Inline Assembly code VS Compiler Assembly code

    با سلام قبلا یک مقدمه کوتاهی درباره نوشتن کدهای بهینه با استفاده از بلاک کدهای اسمبلی در زبان سی پلاس پلاس در لینک زیر…

    3 Comments
  • Programmer Tools For Windows

    معمولا هر برنامه نویسی فارغ از اینکه در چه سطحی برنامه نویسی میکنه، به ابزارهایی نیاز داره که با کمک این ابزار نرم…

    1 Comment

Others also viewed

Explore content categories