linux c++動態鏈接庫so編寫

Linux下的動態鏈接庫是.so文件,即:Shared Object,下面是一個簡單的例子說明如何寫.so以及程序如何動態載入.so中的函數和對象。

testso.h:

#ifndef _TESTSO_H
#define _TESTSO_H
extern "C" {
    int myadd(int a, int b);
    typedef int myadd_t(int, int); // myadd function type
}
#endif // _TESTSO_H

testso.cpp:

#include "testso.h"

extern "C"
int myadd(int a, int  b)
{
    return a + b;
}

編譯so:

g++  -shared  -fPIC  -o testso.so testso.cpp

注意,-shared參數和-fPIC參數非常重要:
-shared 告訴gcc要生成的是動態鏈接庫;
-fPIC 告訴gcc生成的生成的代碼是非位置依賴的,方面的用於動態鏈接。

在主程序裏調用這個動態鏈接庫:
main.cpp:

#include 
#include
 // for dynamic library函數

#include "testso.h"

void print_usage(void)
{
    printf("Usage: main SO_PATH/n");
}

int main(int argc, char *argv[])
{
    if (2 != argc) {
        print_usage();
        exit(0);
    }

    const char *soname = argv[1];

    void *so_handle = dlopen(soname, RTLD_LAZY); // 載入.so文件
    if (!so_handle) {
        fprintf(stderr, "Error: load so `%s' failed./n", soname);
        exit(-1);
    }

    dlerror(); // 清空錯誤信息
    myadd_t *fn = (myadd_t*)dlsym(so_handle, "myadd"); // 載入函數
    char *err = dlerror();
    if (NULL != err) {
        fprintf(stderr, "%s/n", err);
        exit(-1);
    }

    printf("myadd 57 + 3 = %d/n", fn(57, 3)); // 調用函數

    dlclose(so_handle); // 關閉so句柄
    return 0;
}

編譯主程序:
g++ main.cpp -o main -ldl

注意:要加上-ldl

好了,上面就是如何寫和調用動態庫中的C函數。
對於C++中的類,不能直接導出,需要通過繼承的方式才能從動態鏈接庫中導出:

=====================

testso.h:

#ifndef _TESTSO_H
#define _TESTSO_H

// 只能通過基類調用,因此需要先定義一個基類,然後在create中生成真正需要生成的對象。
class Base
{
public:
    int a, b;

    virtual int add(void)
    {
        return -1;
    }
};

class A : public Base
{
public:
    int add(void);
};

extern "C" {
        Base* create(void);
        void destroy(Base *p);

        typedef Base* create_t(void);  // create factory
        typedef void destory_t(Base*); // destory
}

#endif // _TESTSO_H

testso.cpp:

#include "testso.h"

int A::add(void)
{
    return a + b;
}

extern "C"
{
    Base* create(void) // 注意:create函數必須返回Base的對象,不能直接返回A的
                       //      對象,否則後面調用A::add()的時候會提示錯誤。
    {
        return new A;
    }

    void destory(Base *p)
    {
        if (p) delete p;
    }
}

main.cpp: // 這裏需要注意

#include

#include 
#include 
#include "testso.h"

void print_usage(void)
{
    printf("Usage: myso SO_PATH/n");
}

int main(int argc, char *argv[])
{
    if (2 != argc) {
        print_usage();
        exit(0);
    }

    const char *soname = argv[1];

    void *so_handle = dlopen(soname, RTLD_LAZY);
    if (!so_handle) {
        fprintf(stderr, "Error: load so `%s' failed./n", soname);
        exit(-1);
    }

    dlerror();
    create_t *create = (create_t*) dlsym(so_handle, "create");
    if (NULL != err) {
        fprintf(stderr, "%s/n", err);
        exit(-1);
    }
    Base *pa = create();

    pa->a = 57;
    pa->b = 3;
    printf("A.add(57, 3)=%d/n", pa->add()); // 注意,這裏通過虛函數實現了
                                            // 對A::add()的調用。

    destory_t *destory = (destory_t*) dlsym(so_handle, "destory");
    if (NULL != err) {
        fprintf(stderr, "%s/n", err);
        exit(-1);
    }
    destory(pa);
    pa = NULL;

    dlclose(so_handle);

    printf("DONE!/n");
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章