Skip to content

Fix generation of long-typed defines when on Linux#699

Draft
Exanite wants to merge 10 commits into
dotnet:mainfrom
Exanite:fix/long-defines
Draft

Fix generation of long-typed defines when on Linux#699
Exanite wants to merge 10 commits into
dotnet:mainfrom
Exanite:fix/long-defines

Conversation

@Exanite

@Exanite Exanite commented Jun 29, 2026

Copy link
Copy Markdown
Member

Summary

For context, C long is output as C# nint on Linux.

This causes an issue where a 64-bit ulong value can be used as the initializer for a const field of type nint, leading to 2 errors:

  1. There is a missing type cast from long to nint, causing a compile error.
  2. Because C# doesn't know the bit width of nint until run time, this errors with Constant initializer must be compile-time constant after fixing the first error. This is specified here: https://github.com/dotnet/csharplang/blob/main/proposals/csharp-9.0/native-integers.md

This PR fixes the issue by updating the generator to output the expected test output below, along with some additional test cases.

Current test outputs (matching main branch)

This is the current output of the new CLongDefinesTestUnix test case on Linux when ran against the main branch.

public static partial class Methods
{
    [NativeTypeName("#define SIZE_MAX (18446744073709551615UL)")]
    public const nuint SIZE_MAX = (18446744073709551615U);

    [NativeTypeName("#define CL_IMPORT_MEMORY_WHOLE_ALLOCATION_ARM SIZE_MAX")]
    public const nuint CL_IMPORT_MEMORY_WHOLE_ALLOCATION_ARM = (18446744073709551615U);

    [NativeTypeName("#define LONG_MAX __LONG_MAX__")]
    public const nint LONG_MAX = unchecked(9223372036854775807);

    [NativeTypeName("#define ULONG_MAX (__LONG_MAX__ *2UL+1UL)")]
    public const nuint ULONG_MAX = (9223372036854775807 * 2U + 1U);
}

The new CLongDefinesTestWindows test case already passes and is there to ensure that no unintended changes occur to the Windows behavior.

Expected test outputs

The expected test outputs are my proposal for roughly what the expected bindings output should look like.

Notably, we need to add a type cast and change the field to be a static readonly field instead of a const field.

public static partial class Methods
{
    [NativeTypeName(""#define SIZE_MAX (18446744073709551615UL)"")]
    public static readonly nuint SIZE_MAX = unchecked((nuint)(18446744073709551615U));

    [NativeTypeName(""#define CL_IMPORT_MEMORY_WHOLE_ALLOCATION_ARM SIZE_MAX"")]
    public static readonly nuint CL_IMPORT_MEMORY_WHOLE_ALLOCATION_ARM = unchecked((nuint)(18446744073709551615U));

    [NativeTypeName(""#define LONG_MAX __LONG_MAX__"")]
    public static readonly nint LONG_MAX = unchecked((nint)(9223372036854775807));

    [NativeTypeName(""#define ULONG_MAX (__LONG_MAX__ *2UL+1UL)"")]
    public static readonly nuint ULONG_MAX = unchecked((nuint)(9223372036854775807 * 2U + 1U));
}

Remaining Tasks

I'll handle these tasks before undrafting.

  • Add tests for the "similar" case in my comment below
  • Identify other test cases to add
  • Address the todo comments I left
  • Squash/cleanup the git history
  • Package this branch and test against Silk.NET 3.0 on both Windows and Linux

@Exanite

Exanite commented Jun 29, 2026

Copy link
Copy Markdown
Member Author

There is also a similar case with nint typed const fields:

Also from OpenCL:

#if INTPTR_MAX == INT32_MAX
#define CL_ICD2_TAG_KHR ((intptr_t)0x434C3331)
#else
#define CL_ICD2_TAG_KHR ((intptr_t)0x4F50454E434C3331)
#endif

This generates as the following on both Windows and Linux:

[NativeTypeName("#define CL_ICD2_TAG_KHR ((intptr_t)0x4F50454E434C3331)")]
public const nint CL_ICD2_TAG_KHR = unchecked((nint)(0x4F50454E434C3331));

In this case, the only change needed to make this compile would be to replace const with static readonly.

Exanite added 4 commits July 2, 2026 06:10
Will keep investigating the conditions a bit more since I'm not quite convinced this is optimal.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant