Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the recommended place to put make_public pragmas

In a complex solution I have a mix of native C++ library, C++/CLI wrappers and C# assemblies. In the wrappers I often have to use native types so I have to make them public using #pragma make_public. The problem with those pragmas however is that you often get linker error LNK2022 as discussed here and here (and many other places).

The usual solution is to collect all pragmas in one place to avoid the duplicate type error. So far the only reliable place I found was to put the list in my stdafx.h header file. This is however annoying as it causes my entire project to recompile as soon as I have to add a new native type there (it's my precompiled header).

I'd like to extract that list to a separate header or, even better, cpp file. But my attempts so far have not worked. The types where not made public. It also seems I have to put the #pragma make_public calls in a header file. I'd prefer a cpp however.

So, what other possibilties exist? Where do others place their #pragma make_public calls?

like image 905
Mike Lischke Avatar asked Nov 21 '25 18:11

Mike Lischke


1 Answers

I put the pragma directly after including the .h file that brought in the type:

#include "native_type.h"
#pragma make_public(Native_Struct_1)

I only use the pragma in the case where the type is not one I control. If the type is one that I control, then I just mark the type as public by using the following preprocessor helper (to allow it to be compiled by either cli enabled code or non cli enabled code):

#ifdef __cplusplus_cli
#define CLR_ASSEMBLY_ACCESS_SPECIFIER__Public public
#else
#define CLR_ASSEMBLY_ACCESS_SPECIFIER__Public 
#endif

Usage:

CLR_ASSEMBLY_ACCESS_SPECIFIER__Public 
class NativeClass
{
}; 

Edit:

Example 1:

Native only library A.dll has header a.h which includes the following class declaration:

CLR_ASSEMBLY_ACCESS_SPECIFIER__Public 
class TypeA
{
};

When compiled in library A.dll, the CLR_ASSEMBLY_ACCESS_SPECIFIER__Public compiles to nothing. And there is no concept of managed visibility from the native dll.

When that class is used within a c++/cli assembly B.dll, and the header a.h within a /clr compiled source file, the CLR_ASSEMBLY_ACCESS_SPECIFIER__Public compiles to public and TypeA becomes public from B.dll. The equivalent would occur by using make_public within B.dll's source instead of using CLR_ASSEMBLY_ACCESS_SPECIFIER__Public.

Example 2: Now, let's say that A.h did not use CLR_ASSEMBLY_ACCESS_SPECIFIER__Public. And, let's say that in B.dll, we include A.h but we do not use make_public. Also, let's say we expose a managed method that includes TypeA:

public ref class ManagedTypeB
{
     public: void Foo(TypeA * pA);
};

Now, consider a managed assembly C.dll that references B.dll. It cannot call ManagedTypeB::Foo (even though it is public) because TypeA is private in B.dll. Furthermore, there is no way to fix this from the source code of C.dll. I.e., C.dll's source cannot used make_public to make TypeA public from B.dll. In this situation, the source of B.dll must be changed in order to make Foo callable.

like image 187
Matt Smith Avatar answered Nov 24 '25 07:11

Matt Smith



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!