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

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

  •  
  •   zhiqiang · 2018-10-18 20:07:43 +08:00 · 4390 次点击
    这是一个创建于 2205 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我要做的事情很简单,这个单例是 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
    justou
        1
    justou  
       2018-10-18 20:30:31 +08:00
    get_logger 需要导出, 这样声明:

    extern "C" _declspec(dllexport) Logger* get_logger();
    icedx
        2
    icedx  
       2018-10-18 20:44:24 +08:00
    如果用 mingw 编译大概可以
    zhiqiang
        3
    zhiqiang  
    OP
       2018-10-18 21:14:18 +08:00
    @justou 我加了一些 dllexport dllimport 还是不行。
    justou
        4
    justou  
       2018-10-18 21:36:14 +08:00   ❤️ 1
    不清楚你具体怎么操作的, 我建了个测试工程, 你可以试下

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

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

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

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

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

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

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

    Linux 系统上我上面的示例代码就可以做到 。关键在于 Linux 可以在运行时进行函数链接。
    zhiqiang
        18
    zhiqiang  
    OP
       2018-10-23 08:36:11 +08:00
    @wutiantong 不是这个~~~
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4897 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 40ms · UTC 05:38 · PVG 13:38 · LAX 22:38 · JFK 01:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.