跨 DLL / 共享库使用命名空间

Posted

技术标签:

【中文标题】跨 DLL / 共享库使用命名空间【英文标题】:using a namespace accross DLLs / shared library 【发布时间】:2013-05-20 19:16:53 【问题描述】:

我正在编写一个带有辅助函数的共享库/DLL。所以我声明命名空间在未来不会发生名称冲突。对于类,这很好用,但我有一些全局函数,我也想放在命名空间中,但这不起作用。尝试寻址命名空间时出现链接器错误。看起来好像无法从 DLL 中导出命名空间。

我用谷歌搜索并在这里找到了这个帖子Where should I put my DECLSPEC for a namespace?,但我不太明白答案。命名空间的重点是分隔名称并使它们唯一可识别,所以我想知道为什么它是一个公认的答案,即不需要导出命名空间。但是,也许我在这里遗漏了一些东西。我可以看到它自己的命名空间无法导出,但里面的函数应该仍然属于命名空间,这似乎是不可能的。但是,我在命名空间中拥有的类按预期工作,所以我有点困惑为什么这不应该适用于其他符号。

我现在通过创建一个虚拟类包装器并将我的函数声明为静态来结束。它不是 100% 像命名空间,但对于我的目的来说已经足够相似了。

在 DLL 中:

class EXPORT_DECL Base64

   public:
       static std::string encode(unsigned char const *bytes_to_encode, unsigned int in_len);
       static std::string decode(std::string const &oBase64Encoded);
;

在 main 中,我可以像在命名空间中一样处理它们。

Base64::encode(...);

我想知道,如果我在这里遗漏了什么,是否可以使用命名空间而不是使用此解决方法。共享库是否也有这个限制,或者这只是来自 DLL 的东西?

更新

共享库 foo.h:

namespace mytest

     int mytestfkt(int a);
     EXPORT_DECL int decltest(int a);

共享库 foo.cpp.

 int mytestfkt(int a)
 
     return 0;
 

int decltest(int a)

    return 0;

或者这个:

namespace mytest

 int mytestfkt(int a)
 
     return 0;
 

 EXPORT_DECL int decltest(int a)

    return 0;


或者这个:

int mytest::mytestfkt(int a)

 return 0;


EXPORT_DECL int mytest::decltest(int a)

return 0;

main.cpp:

int x = mytest::mytestfkt(1);
x = mytest::decltest(1);

结果:

undefined reference to `mytest::mytestfkt(int)'
undefined reference to `mytest::decltest(int)'

【问题讨论】:

呃,这都是windows-y!但我相信答案是你不想尝试导出整个命名空间。导出您想要的函数(恰好位于命名空间内)。像 namespace N int foo(); 这样的东西在修改后变成像 int N_foo(); 这样的东西,然后这个名字被导出。命名空间是源代码中的一个概念,而不是编译后的 DLL。 我认为使用具有静态方法的实用程序类没有任何问题。由于您正在使用 C++ 而不是 C,因此这是我建议的方法。从代码质量的角度来看,在其他命名空间中拥有相同的功能无论如何都是不好的,因为这可能会故意隐藏其他命名空间中的功能(非),使代码难以理解并且更容易出错 @BoBTFish,我的意思是这行不通。当我使用命名空间时,我尝试调用的函数出现未定义符号的链接器错误。 @Samuel,你说的很有道理,这就是我想出这个解决方法的原因。我仍然不明白为什么这个限制只适用于符号。它也不适用于变量,因为您不能将它们全部设为静态,因为这是一个完全不同的概念。好吧,如果我需要变量,我可能会使用类对象,所以这不是一个严重的问题。 “这不起作用” --- 确实如此。看看那个小std:: 前缀。它适用于独立功能吗?认为这样。你做错了什么。我不能确切地说出是什么,因为你没有展示你在做什么。展示你的代码,也许我们可以一起解决。 【参考方案1】:

EXPORT_DECL 是什么?如果您在库和用户代码中包含相同的头文件(在您的 q 中显示的那个),那么 EXPORT_DECL 必须根据上下文进行不同的扩展。

在库中它必须映射到__declspec(dllexport),在用户代码中它必须扩展为__declspec(dllimport)。否则,您是在告诉编译器从库代码和用户代码中导出相同的符号。由于用户中没有EXPORT_DECL-tagged 符号的定义(正确,因为您想从库中导入它),您会收到链接时错误。

通常这是通过对EXPORT_DECL 进行条件定义来完成的

#ifdef EXPORTING
#define EXPORT_DECL __declspec(dllexport)
#else
#define EXPORT_DECL __declspec(dllimport)
#endif

然后使用-DEXPORTING=1 编译您的库,使用-DEXPORTING=0 编译用户代码

【讨论】:

以上是关于跨 DLL / 共享库使用命名空间的主要内容,如果未能解决你的问题,请参考以下文章

跨命名空间共享秘密

第二十一章 命名空间和程序集

如何跨命名空间和平台伪造库(GDI 到 Xamarin.Forms),例如重用 Color 结构

如何跨 Namespace 同步 Secret 和 ConfigMap?

如何跨 Namespace 同步 Secret 和 ConfigMap?

Clojure 中的命名空间之间共享函数