放置 make_public pragma 的推荐位置是啥
Posted
技术标签:
【中文标题】放置 make_public pragma 的推荐位置是啥【英文标题】:What's the recommended place to put make_public pragmas放置 make_public pragma 的推荐位置是什么 【发布时间】:2014-02-07 10:03:29 【问题描述】:在一个复杂的解决方案中,我混合了原生 C++ 库、C++/CLI 包装器和 C# 程序集。在包装器中,我经常必须使用本机类型,所以我必须使用 #pragma make_public
将它们公开。然而,这些 pragma 的问题在于,您经常会遇到链接器错误 LNK2022,正如 here 和 here(以及许多其他地方)所讨论的那样。
通常的解决方案是将所有 pragma 收集到一个地方以避免重复类型错误。到目前为止,我发现的唯一可靠的地方是将列表放在我的 stdafx.h
头文件中。然而,这很烦人,因为它会导致我的整个项目在我必须在那里添加新的本机类型时重新编译(这是我的预编译头文件)。
我想将该列表提取到单独的标题,或者更好的是,cpp 文件。但到目前为止我的尝试都没有奏效。未公开的类型。看来我还必须将 #pragma make_public
调用放在头文件中。不过我更喜欢cpp。
那么,还有哪些其他可能性?其他人在哪里拨打#pragma make_public
电话?
【问题讨论】:
这听起来不太好。 wrapper 的重点是包装而不是 使原生类型可见。 嗯,包装器不是链中的最后一个环节。有一些消费者库在更高级别的结构中使用包装的类。他们获取原生对象并为它们构造包装器,这需要让原生类对它们可见。 【参考方案1】:我在包含引入类型的 .h 文件后直接放了 pragma:
#include "native_type.h"
#pragma make_public(Native_Struct_1)
我只在类型不是我控制的类型的情况下使用编译指示。如果类型是我控制的类型,那么我只需使用以下预处理器帮助程序将类型标记为公共(以允许它由启用 cli 的代码或非启用 cli 的代码编译):
#ifdef __cplusplus_cli
#define CLR_ASSEMBLY_ACCESS_SPECIFIER__Public public
#else
#define CLR_ASSEMBLY_ACCESS_SPECIFIER__Public
#endif
用法:
CLR_ASSEMBLY_ACCESS_SPECIFIER__Public
class NativeClass
;
编辑:
示例 1:
仅本机库 A.dll 的头文件 a.h 包含以下类声明:
CLR_ASSEMBLY_ACCESS_SPECIFIER__Public
class TypeA
;
在库 A.dll 中编译时,CLR_ASSEMBLY_ACCESS_SPECIFIER__Public
编译为空。并且本地 dll 中没有托管可见性的概念。
当在 c++/cli 程序集 B.dll 中使用该类,并且在 /clr 编译的源文件中使用头文件 a.h 时,CLR_ASSEMBLY_ACCESS_SPECIFIER__Public
编译为 public
和 TypeA
从 B.dll 变为公共。通过在 B.dll 的源代码中使用 make_public
而不是使用 CLR_ASSEMBLY_ACCESS_SPECIFIER__Public
来实现等效。
示例 2:
现在,假设 A.h 没有使用CLR_ASSEMBLY_ACCESS_SPECIFIER__Public
。而且,假设在 B.dll 中,我们包含 A.h 但我们不使用 make_public
。另外,假设我们公开了一个包含 TypeA 的托管方法:
public ref class ManagedTypeB
public: void Foo(TypeA * pA);
;
现在,考虑一个引用 B.dll 的托管程序集 C.dll。它不能调用ManagedTypeB::Foo
(即使它是公共的),因为TypeA 在B.dll 中是私有的。此外,没有办法从 C.dll 的源代码中修复此问题。即,C.dll 的源代码不能使用make_public
从 B.dll 公开 TypeA。在这种情况下,必须更改 B.dll 的源才能使Foo
可调用。
【讨论】:
但是,使用 public 关键字只能在托管库中使用,对吧?如果本机类型在本机 DLL 中,则始终必须使用 make_public。当您阅读有关 make_public 时,几乎没有提到这一事实。 使用 make_public (also) 仅适用于托管库。 make_public 更改程序集的本机类型的可见性。它不能用于更改 另一个 引用程序集中的类型的可见性(请参阅***.com/questions/9198363/…)。 @MikeLischke 使用 make_public 仅适用于您使用无法/不应修改的标头(即标准库标头、Windows 标头等)的情况 @MikeLischke 但是,如果本机类型在本机 dll 中,并且您在项目中使用标头,那么您可以在 your 程序集中将该本机类型公开(您只是不能在本机 dll 中公开它)。即使在这种情况下,如果您可以控制本机 dll 的源,我会使用第二种方法而不是 make_public。使用这种方法,如果使用 /clr 编译,则不需要使用 make_public,如果不使用 /clr 编译,就好像没有 public 关键字。 所以你说,我可以将本机 DLL(本机,而不是程序集)中的本机类型在另一个(这次是托管)DLL 中公开,而无需使用 make_public? make_public 的一个有趣点是,当您可以控制本机类型的源代码时,您甚至需要它。那是因为您不能在本机类型中将其公开(在托管意义上,从纯 C++ 的角度来看,它是公开/导出的)。在任何情况下,您必须在托管库中公开它。我的问题是这样做,尤其是您在回答中建议的方式,通常会导致 LNK2022 错误。以上是关于放置 make_public pragma 的推荐位置是啥的主要内容,如果未能解决你的问题,请参考以下文章
库导入:#pragma 注释 VS Visual Studio 项目输入
#pragma 标记的意义是啥?为啥我们需要#pragma 标记?