-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add platform native long support to runtime #4844
Comments
Duplicate of #4233? This is a good point that has not been brought up before in that discussion. However, I would like to also point out that on Windows libraries can be compiled with gcc (LP) in addition to msvc (LLP), so native long on Windows doesn't depend on the fact that the OS is Windows, but rather on which compiler was used for the native library. The problem of "natural floats" discussed in #4233 is pretty much the same problem. The need for it is only indirectly tied to the processor size. In the use case in that issue, the need for So, I think an important criteria for a solution here is that any "native" types (other than the already exiting The CLR runtime doesn't have a way to know what compiler was used to compile a "native" library and it doesn't seem like it should. One solution I have thought of is to use the "bait and switch" trick that is used with PCLs. It would work something like this... You define all of your Another possible solution is to use #if LP64
using nlong = System.Int64;
#elif LLP64 || ILP32
using nlong = System.Int32;
#else
#error Must specify native library compiler type.
#endif |
The difference between this issue and #4233 is that LP and LLP are system wide. They are the standard for the platform as a whole. The
The purpose of |
One of the points that I was trying to make is that LP64 and LLP64 are not necessarily system wide. For example, Cygwin uses LP64 on Windows. So, if you say |
For the intent and purpose of this issue, they are always system wide. "foreign environments" will inherit the behaviour of the native environment: if a developer is using a LP64 environment on a native LLP64 system, they will be responsible for accommodating it just as is required for C/C++ without the presence of CoreCLR. CoreCLR is, as the name suggests, minimal. It has a greater need for interop than the previous "full frameworks". Now that LP64 systems (mac/linux) are officially supported targets, a mechanism is needed support interop on them. There are many native libraries that compile natively (sans Cygwin) for windows, linux and mac. If the public APIs of such libraries exposes The heart of this issue is that there is currently no way to express a |
I'm not sure there is anything here for CoreCLR to do, the support for a pointer-size type already exists in MSIL as "native int", and in C# as IntPtr. This deferred resolution of size at runtime or architecture-specific compile time is all that is needed for you to implement native interop where the size of a parameter/return type is dependent on the size of the pointer. long/longlong and abstract data model issues exist outside the realm of the runtime. Taking the example of C++, what happens when two different compilers compiling two different translation units where "long" is used need to interact. Is it 32-bit, or 64-bit? Portable C++/native code should define their data type size concretely as X bytes, or if it is dependent on architecture pick whatever data type represents that, for MSVC++ that is SIZE_T. The real issue here (it seems) is that the same "source code" can be compiled differently by different compilers on the same (or different) platforms and long/longlong may only be one specific instance of this difference. So you have a couple of options, you can either make the native code more portable by being explicit about your data type sizes or rely on pointer-size widths if that suits your purpose (and is of course semantically correct, etc.), and both of these are supported by the runtime. |
Rewriting every existing library on mac and linux to use explicit sizes is not a realistic solution. The converse argument is that Microsoft should just rewrite Windows to be a LP64 platform like everyone else. Both are unrealistic premises. Additionally, I was explicit about "why
Knowing the size of
Copy/paste the code that provides This is not about supporting every possible combination of compiler. There is absolutely no need to consider anything other than supported platforms and supported compilers. Cygwin and different translation units with different compilers are simply red herrings. The issue is that there is no way to express that despite IntPtr.Size = 8 on all 64bit platforms, NativeLong.Size=4 on windows and NativeLong.Size=8 on Mac and Linux. Assuming a 64bit environement, the following illustrates the problem to solve: C code: C# code to call it on Windows: C# code to call it on non Windows: The following works on Mac/Linux, but not Windows:
The desired solution (using the platform provided compiler and toolchains) is: C# code to call it on ALL platforms and ALL architectures: [Edit] |
I buy the argument that we can ignore the fact Cygwin is LP64 on Windows and just say that Windows is LLP64. It actually makes sense that if you want to run coreclr in Cygwin that you would use a binary version of coreclr that targets Cygwin that is more like the current Linux version of coreclr rather than using a Windows version of the coreclr. I also second the argument that the "fixing" the code of every library we pinvoke is quite unrealistic. The most common use case for pinvoke by far is system libraries and other well-know widely-used libraries that are not going to change because it would break everybody everywhere. I'm on board with what @OtherCrashOverride is suggesting here other than I might prefer to call it |
IntPtr.Size is not always 8 "on 64-bit platforms" (if by platform you mean processor architecture). If you compile to x86 specifically (as opposed to AnyCpu), Windows process will be forced to 32-bit, and so IntPtr.Size will be 4. Can this be used to address the "native long" issue? i.e. you would build two dlls with forced 32-bit and forced 64-bit, and then select the appropriate one depending on LP/LLP? |
Yes, running a 32bit process on a 64bit platform is the same as a 32bit platform and the 32bit rules apply.
There are various ways to "work around" it including #if and platform specific assemblies. Without first class support in the runtime, the typical "work around is" to simply not support a platform (typically Windows) since all the interop APIs using "long" where this matters are non-Widows libraries. The impact to developers is the same as if IntPtr did not exist in the choices they must make. |
I do not think that C# should add all "no sense" types of C / C++ long that is 32 or 64 bit "at random", long long (how a thing could be more "long" than "long"), if not we will need soon "native char" (UTF-8 or UTF-16 based on the platform?). Why this mess cannot solved using marshalling attributes? Without adding types that make no sense in the clean C# type system? |
There is nothing "random" about it. It is a real world issue faced by real developers.
An attribute can not solve the issue anymore than it could solve the issue for IntPtr. Its need is exactly the same as IntPtr. Windows is the only platform where an IntPtr can not be used to express "native long". |
Maybe something more generic can be implemented, which would work for other type variations as well: class NativeLongFieldTypeAttribute : ConditionalFieldTypeAttribute {
public override Type GetFieldType () {
if (windows) {
return typeof (int);
} else {
return IntPtr.Size == 8 ? typeof (long) : typeof (int);
}
}
}
struct nlong {
[NativeLongFieldType]
ValueType value;
} And at runtime the JIT calls |
Could not be done simply in this way: extern void func([MarshalAs(UnmanagedType.NativeLong)] long a); on Windwows32 / Windows64 'a' will be the same thing of System.Int32 on Linux32 it will be System.Int32 while on Linux64 it will be System.Int64! There is the precedent of SysInt/ SysUInt so SysLong / SysULong will be the more correct name: |
The attribute would need to apply to structures in addition to p/invoke signatures. The proposal would need to be tested in real-world scenarios, but its better than nothing. |
For structs, adding a MarshalAs that can change the size of the marshaled type could change a struct from blittable to non-blittable, making marshaling much slower on 64 bit linux (and similar LP systems). |
Duplicate of #27530 |
Nice idea - You know I have ported from Java Native Access to C# but not complete implements for C#. Thank you for trick with Type GetFieldType() with int and long. But what is about Pointer and PointerType for C# under Dotnet. Thanks Update Good luck! |
Currently, C#
long
maps toSystem.Int64
in the runtime. However, thenative long
may be 32bit or 64bit depending on platform. We need a new type that transitions from 32bit to 64bit as appropriate for the platform in much the same way asIntPtr
does. This issue is present when you compile a C/C++ project on 64bit platforms and need to perform interop.Windows is a LLP platform.
Windows 32bit: native long = 32bits
Windows 64bit: native long = 32bits
Linux is a LP platform.
Linux 32bit: native long = 32bits;
Linux 64bit: native long = 64bits;
For clarity,
IntPtr
is ALWAYS 32bit on 32bit platforms and ALWAYS 64bit on 64bit platforms. Thenative long
may be 32bit or 64bit depending on the 64bit platform in use. This is related to #4216. The goal is to make the p/invoke signature match without rewriting the import for each target platform (windows/linux).I have searched the issues and did not find this as a duplicate. However, if it is, please feel free to mark it as such and close it.
The text was updated successfully, but these errors were encountered: