Skip to content
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

Adding a differentiator between "LTS" (default) and "STS" (latest) codegen #426

Merged
merged 4 commits into from
Mar 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions ClangSharp.sln
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets
Directory.Packages.props = Directory.Packages.props
global.json = global.json
LICENSE.md = LICENSE.md
NOTICE.md = NOTICE.md
NuGet.config = NuGet.config
Expand Down
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ ClangSharp provides Clang bindings written in C#. It is self-hosted and auto-gen
A nuget package for the project is provided here: https://www.nuget.org/packages/clangsharp.
A .NET tool for the P/Invoke generator project is provided here: https://www.nuget.org/packages/ClangSharpPInvokeGenerator

**NOTE:** If you are running as a dotnet tool, you may need to manually copy the appropriate DLLs from NuGet due to limitations in the dotnet tool support.

A convenience package which provides the native libClang library for several platforms is provided here: https://www.nuget.org/packages/libclang

A helper package which exposes many Clang APIs missing from libClang is provided here: https://www.nuget.org/packages/libClangSharp

NOTE: libclang and libClangSharp are meta-packages which point to the platform-specific runtime packages ([e.g.](https://www.nuget.org/packages/libClangSharp.runtime.win-x64/15.0.0); see others owned by [tannergooding](https://www.nuget.org/profiles/tannergooding)). Several manual steps may be required to use them, see discussion in [#46](https://github.com/dotnet/ClangSharp/issues/46) and [#118](https://github.com/dotnet/ClangSharp/issues/118).
**NOTE:** libclang and libClangSharp are meta-packages which point to the platform-specific runtime packages ([e.g.](https://www.nuget.org/packages/libClangSharp.runtime.win-x64/15.0.0); see others owned by [tannergooding](https://www.nuget.org/profiles/tannergooding)). Several manual steps may be required to use them, see discussion in [#46](https://github.com/dotnet/ClangSharp/issues/46) and [#118](https://github.com/dotnet/ClangSharp/issues/118).

Nightly packages are available via the NuGet Feed URL: https://pkgs.clangsharp.dev/index.json

Expand Down Expand Up @@ -179,8 +181,9 @@ The available configuration options (visible with `-c help`) are:
Options:
?, h, help Show help and usage information for -c, --config
compatible-codegen Bindings should be generated with .NET Standard 2.0 compatibility. Setting this disables preview code generation.
latest-codegen Bindings should be generated for the latest stable version of .NET/C#. This is currently .NET 6/C# 10.
preview-codegen Bindings should be generated for the latest preview version of .NET/C#. This is currently .NET 7/C# 11.
default-codegen Bindings should be generated for the current LTS version of .NET/C#. This is currently .NET 6/C# 10.
latest-codegen Bindings should be generated for the current STS version of .NET/C#. This is currently .NET 7/C# 11.
preview-codegen Bindings should be generated for the preview version of .NET/C#. This is currently .NET 8/C# 12.
single-file Bindings should be generated to a single output file. This is the default.
multi-file Bindings should be generated so there is approximately one type per file.
unix-types Bindings should be generated assuming Unix defaults. This is the default on Unix platforms.
Expand Down
7 changes: 7 additions & 0 deletions global.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"sdk": {
"version": "7.0.100",
"allowPrerelease": false,
"rollForward": "latestFeature"
}
}
8 changes: 6 additions & 2 deletions sources/ClangSharp.Interop/Extensions/clang.ResolveLibrary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,12 @@ private static IntPtr OnDllImport(string libraryName, Assembly assembly, DllImpo

if (result == IntPtr.Zero)
{
Console.WriteLine("Failed to resolve libClang or libClangSharp.");
Console.WriteLine("If you are running as a dotnet tool, you may need to manually copy the appropriate DLLs from NuGet due to limitations in the dotnet tool support.");
Console.WriteLine();
Console.WriteLine("*****IMPORTANT*****");
Console.WriteLine($"Failed to resolve {libraryName}.");
Console.WriteLine("If you are running as a dotnet tool, you may need to manually copy the appropriate DLLs from NuGet due to limitations in the dotnet tool support. Please see https://github.com/dotnet/clangsharp for more details.");
Console.WriteLine("*****IMPORTANT*****");
Console.WriteLine();
}
return result;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -801,7 +801,7 @@ public void BeginStruct(in StructDesc desc)
Write(".Interface");
}

if ((desc.Uuid is not null) && _config.GenerateGuidMember && _config.GeneratePreviewCode)
if ((desc.Uuid is not null) && _config.GenerateGuidMember && _config.GenerateLatestCode)
{
Write(desc.HasVtbl ? ", " : " : ");
Write("INativeGuid");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -919,7 +919,7 @@ private void VisitIndirectFieldDecl(IndirectFieldDecl indirectFieldDecl)
ParentName = GetRemappedCursorName(parent),
Offset = null,
NeedsNewKeyword = false,
NeedsUnscopedRef = _config.GeneratePreviewCode && !fieldDecl.IsBitField,
NeedsUnscopedRef = _config.GenerateLatestCode && !fieldDecl.IsBitField,
Location = fieldDecl.Location,
HasBody = true,
WriteCustomAttrs = static context => {
Expand Down Expand Up @@ -2937,7 +2937,7 @@ void VisitConstantOrIncompleteArrayFieldDecl(RecordDecl recordDecl, FieldDecl co
}
else
{
_outputBuilder.BeginIndexer(AccessSpecifier.Public, isUnsafe: false, needsUnscopedRef: _config.GeneratePreviewCode);
_outputBuilder.BeginIndexer(AccessSpecifier.Public, isUnsafe: false, needsUnscopedRef: _config.GenerateLatestCode);
_outputBuilder.WriteIndexer($"ref {arrayTypeName}");
_outputBuilder.BeginIndexerParameters();
var param = new ParameterDesc {
Expand Down Expand Up @@ -2979,7 +2979,7 @@ void VisitConstantOrIncompleteArrayFieldDecl(RecordDecl recordDecl, FieldDecl co
ReturnType = $"Span<{arrayTypeName}>",
Location = constantOrIncompleteArray.Location,
HasBody = true,
NeedsUnscopedRef = _config.GeneratePreviewCode,
NeedsUnscopedRef = _config.GenerateLatestCode,
};

var isUnsafe = false;
Expand Down Expand Up @@ -3354,7 +3354,7 @@ private void VisitVarDecl(VarDecl varDecl)

case CX_CharacterKind.CX_CLK_UTF32:
{
if (_config.GeneratePreviewCode && flags.HasFlag(ValueFlags.Constant))
if (_config.GenerateLatestCode && flags.HasFlag(ValueFlags.Constant))
{
typeName = "ReadOnlySpan<uint>";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2472,7 +2472,7 @@ private void VisitStringLiteral(StringLiteral stringLiteral)
case CX_CharacterKind.CX_CLK_Ascii:
case CX_CharacterKind.CX_CLK_UTF8:
{
if (Config.GeneratePreviewCode)
if (Config.GenerateLatestCode)
{
outputBuilder.Write('"');
outputBuilder.Write(EscapeString(stringLiteral.String));
Expand Down
2 changes: 1 addition & 1 deletion sources/ClangSharp.PInvokeGenerator/PInvokeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ public void Close()

foreach (var entry in methodClassOutputBuilders)
{
var hasGuidMember = _config.GenerateGuidMember && _config.GeneratePreviewCode;
var hasGuidMember = _config.GenerateGuidMember && _config.GenerateLatestCode;
hasGuidMember &= _uuidsToGenerate.ContainsKey(entry.Value.Name) || _generatedUuids.Contains(entry.Value.Name);

CloseOutputBuilder(stream, entry.Value, isMethodClass: true, leaveStreamOpen, emitNamespaceDeclaration);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,21 @@ public PInvokeGeneratorConfiguration(string defaultNamespace, string outputLocat
{
throw new ArgumentOutOfRangeException(nameof(options));
}
else if (options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateCompatibleCode) && options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateLatestCode))
{
throw new ArgumentOutOfRangeException(nameof(options));
}
else if (options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateLatestCode) && options.HasFlag(PInvokeGeneratorConfigurationOptions.GeneratePreviewCode))
{
throw new ArgumentOutOfRangeException(nameof(options));
}

if (options.HasFlag(PInvokeGeneratorConfigurationOptions.GeneratePreviewCode))
{
// While users shouldn't have passed it in like this, we can simplify
// our own downstream checks be having preview also opt into "latest".
options |= PInvokeGeneratorConfigurationOptions.GenerateLatestCode;
}
_options = options;

if (!_options.HasFlag(PInvokeGeneratorConfigurationOptions.NoDefaultRemappings))
Expand Down Expand Up @@ -205,6 +220,8 @@ public IReadOnlyCollection<string> ExcludedNames

public bool GenerateHelperTypes => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateHelperTypes);

public bool GenerateLatestCode => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateLatestCode);

public bool GenerateMacroBindings => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateMacroBindings);

public bool GenerateMarkerInterfaces => _options.HasFlag(PInvokeGeneratorConfigurationOptions.GenerateMarkerInterfaces);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,6 @@ public enum PInvokeGeneratorConfigurationOptions : ulong
GenerateDocIncludes = 1UL << 32,

GenerateGuidMember = 1UL << 33,

GenerateLatestCode = 1UL << 34,
}
26 changes: 19 additions & 7 deletions sources/ClangSharpPInvokeGenerator/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,9 @@ public class Program
// Codegen Options

new TwoColumnHelpRow("compatible-codegen", "Bindings should be generated with .NET Standard 2.0 compatibility. Setting this disables preview code generation."),
new TwoColumnHelpRow("latest-codegen", "Bindings should be generated for the latest stable version of .NET/C#. This is currently .NET 6/C# 10."),
new TwoColumnHelpRow("preview-codegen", "Bindings should be generated for the latest preview version of .NET/C#. This is currently .NET 7/C# 11."),
new TwoColumnHelpRow("default-codegen", "Bindings should be generated for the current LTS version of .NET/C#. This is currently .NET 6/C# 10."),
new TwoColumnHelpRow("latest-codegen", "Bindings should be generated for the current STS version of .NET/C#. This is currently .NET 7/C# 11."),
new TwoColumnHelpRow("preview-codegen", "Bindings should be generated for the preview version of .NET/C#. This is currently .NET 8/C# 12."),

// File Options

Expand Down Expand Up @@ -209,13 +210,13 @@ static Program()
public static IEnumerable<HelpSectionDelegate> GetExtendedHelp(HelpContext context)
{
foreach (var sectionDelegate in HelpBuilder.Default.GetLayout())
{
yield return sectionDelegate;
}

yield return _ =>
{
Console.WriteLine(
@"Wildcards:
You can use * as catch-all rule for remapping procedures. For example if you want make all of your generated code internal you can use --with-access-specifier *=Internal.");
yield return _ => {
Console.WriteLine("Wildcards:");
Console.WriteLine("You can use * as catch-all rule for remapping procedures. For example if you want make all of your generated code internal you can use --with-access-specifier *=Internal.");
};
}

Expand Down Expand Up @@ -339,20 +340,31 @@ public static void Run(InvocationContext context)
case "compatible-codegen":
{
configOptions |= PInvokeGeneratorConfigurationOptions.GenerateCompatibleCode;
configOptions &= ~PInvokeGeneratorConfigurationOptions.GenerateLatestCode;
configOptions &= ~PInvokeGeneratorConfigurationOptions.GeneratePreviewCode;
break;
}

case "default-codegen":
{
configOptions &= ~PInvokeGeneratorConfigurationOptions.GenerateCompatibleCode;
configOptions &= ~PInvokeGeneratorConfigurationOptions.GenerateLatestCode;
configOptions &= ~PInvokeGeneratorConfigurationOptions.GeneratePreviewCode;
break;
}

case "latest-codegen":
{
configOptions &= ~PInvokeGeneratorConfigurationOptions.GenerateCompatibleCode;
configOptions |= PInvokeGeneratorConfigurationOptions.GenerateLatestCode;
configOptions &= ~PInvokeGeneratorConfigurationOptions.GeneratePreviewCode;
break;
}

case "preview-codegen":
{
configOptions &= ~PInvokeGeneratorConfigurationOptions.GenerateCompatibleCode;
configOptions &= ~PInvokeGeneratorConfigurationOptions.GenerateLatestCode;
configOptions |= PInvokeGeneratorConfigurationOptions.GeneratePreviewCode;
break;
}
Expand Down