首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  C/C++/Obj-C

windows 下 C++如何生成跨 DLL/SO 文件的单例?

  •  
  •   zhiqiang · 217 天前 · 1219 次点击
    这是一个创建于 217 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我要做的事情很简单,这个单例是 Log 示例,用来写 Log。用简单的单例方法:

    // log.h
    class Log {
        Log* instance() {
            static Log log;
            return &log;
        }
    }
    

    这样做会在每个 DLL 文件里会生成各自的 DLL 实例,不能直接这么写。

    在 Linux 下我是这个做可以生成一个跨 DLL 的单例:

    // in log.h
    extern C {
        Log* get_logger() 
    }
    class Log {
        Log* instance() {
            return get_logger();
        }
    }
    
    #ifndef _USRDLL
    extern C {
        Log* get_logger() {
        	static Log instance;
            return &instance;
        }
    }
    #endif
    

    这种方法在 linux/gcc 下有效。但在 windows/vc2015 编译时,提示连接不到get_logger函数。

    18 回复  |  直到 2018-10-23 08:36:11 +08:00
        1
    justou   217 天前
    get_logger 需要导出, 这样声明:

    extern "C" _declspec(dllexport) Logger* get_logger();
        2
    icedx   217 天前
    如果用 mingw 编译大概可以
        3
    zhiqiang   217 天前
    @justou 我加了一些 dllexport dllimport 还是不行。
        4
    justou   217 天前   ♥ 1
    不清楚你具体怎么操作的, 我建了个测试工程, 你可以试下

    链接: https://pan.baidu.com/s/1Qd4FXpYwqEAcRTrRjKxq6g 提取码: 4tfu

    编译时动态链接的时候除了头文件也需要一个导出符号表, 比如 some.dll(可执行代码)有个对应的 some.lib(符号表)

    如果用 windows api 的 LoadLibrary 函数则不需要那个 some.lib, 这样需要自己手动找符号对应的地址.
        5
    justou   217 天前
        6
    owt5008137   217 天前 via Android
    elf 里的堆是共享的,但是 pe 里 dll 的堆是独立的。所以唯一的方法是 dll 里导出一个函数,然后只由这个 dll 分配对象。不能写到.h 里,相应的.cpp 也不要链接进 exe 或者其他 dll
        7
    wutiantong   217 天前
    @zhiqiang 哎?是不是 fit@thu 的 zhiqiang ?
        8
    arzterk   217 天前
    windows 头文件导出类需要用宏区分 dllimport、dllexport 的,不然编译不是库编不过就是链接代码出问题
        9
    z4none   214 天前
    感觉你需要的是 #pragma data_seg
        10
    zhiqiang   213 天前
    @wutiantong haha,你也在这里混啊。现在在哪呢
        11
    zhiqiang   213 天前
    @justou 谢谢。

    不过我的需求是在 exe 里定义 get_logger() 函数。所有的 dll 从 exe 里去取这个函数的实现(因为我有很多个地位平等的 dll,这些 dll 是按需加载的)。跟你给的例子恰好相反。
        12
    zhiqiang   213 天前
    @justou 你这种方案需要把 log 库做成一个 dll,这样 log 库就不能直接 header only 了。
        13
    zhiqiang   213 天前
    @owt5008137 你说的是需要把 log 库做成一个 dll,这样 log 库就不能直接 header only 了。

    但在 linux 下是能实现我所需要的,同样的实现在 windows 下就不行。有些跨平台开源 log 库也是 header only 的,我还没细看他们怎么写的。
        14
    zhiqiang   213 天前
    @z4none 我去学习了一下 #pragma data_seg,这个是多个进程调用同一个 dll 文件时,共享该 dll 里面的某个变量。

    这跟我说的不一样。我说的是程序同时调用多个不同的 dll 文件时,这些 dll 里的 log 对象需要引用到同一个 log 变量。
        15
    noli   213 天前 via iPhone
    你的需求是说,不管有多少个 dll 被加载,只要这些 dll 使用了你的 logger 那么他们所引用的 logger 必然是内存中的同一个?

    要做到这一点的话必须要使用文件系统或者内核来保证。据我所知没有任何语言基本设施足以保证这一点。
        16
    wutiantong   213 天前 via iPhone
    @zhiqiang 我在扇贝啊
    你这个问题我也搜了一下,你看看是不是这个:
    https://stackoverflow.com/questions/362830/circular-dependencies-between-dlls-with-visual-studio/387380#387380
        17
    zhiqiang   213 天前
    @noli 加一个限制条件:dll 是运行在同一个进程里的。

    Linux 系统上我上面的示例代码就可以做到 。关键在于 Linux 可以在运行时进行函数链接。
        18
    zhiqiang   213 天前
    @wutiantong 不是这个~~~
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   3924 人在线   最高记录 5043   ·  
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 20ms · UTC 03:45 · PVG 11:45 · LAX 20:45 · JFK 23:45
    ♥ Do have faith in what you're doing.
    沪ICP备16043287号-1