'Does cross-platform C++ require building separately on every single platform?

My question actually has two variants, but for some context, I have a C++ *.DLL that I use with Unity using P/Invoke. It's built on Windows 10 with MSBuild (platform toolset: ClangCL).

And now for my questions,

  1. Does the size of a particular type stay constant after the DLL has been built? Or does it need to be rebuilt again on the target platform (say, Linux or Mac)?

My code looks a bit like this:

typedef wchar_t wchar;
static_assert(sizeof(wchar) == 2, "WideChar size-test failed.");

After I have recompiled the source on Windows, if I build the Unity project for the Android platform, will the size of wchar remain the same on there as well? Or am I in for a nasty surprise when my string-handling code just stops working?

  1. Are some of the other language features maintained after the DLL is built, or do I need to change my workflow to account for something else?

In particular, let's look at something super-basic, like extern methods.

#define CALLING_CONVENTION __stdcall

#if _WIN32
#define DLLEXPORT(type) extern "C" __declspec(dllexport) type CALLING_CONVENTION
#else
#define DLLEXPORT(type) extern "C" type CALLING_CONVENTION
#endif

DLLEXPORT(void) DoSomething(const wchar* ManagedString);
// expands to
// extern "C" __declspec(dllexport) void __stdcall DoSomething(const wchar* ManagedString)
// on Windows

And for managed,

[DllImport("DllName", CharSet = CharSet.Unicode)]
public static extern void DoSomething([MarshalAs(UnmanagedType.LPWStr)] string input);

Will this maintain interoperability for other platforms as well? Or do I need to go out of my way to build the C++ DLL on Linux and then use that for an Android platform?



Solution 1:[1]

Each platform usually has a different ABI. For example, long on Windows is 32-bit (from memory), but long on Linux is 64-bit. In your example, wchar_t on Windows is 16-bit, but on Linux it is 32-bit. The way that C++ names are mangled is also platform-specific.

Both Windows and Linux have different syscalls (standard library functions like malloc usually end up calling platform-specific syscalls). But not only that; the way that each platform stores and loads executable code (and how it dynamically links to other executable code) is also different, and without some sort of translator in between (such as Wine), it's typically not possible to run executable code that was compiled for a different platform.

So in general, you will need to compile your code for each platform you intend to support. See also this post in the Unity forums.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Peter Mortensen