diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 8047c4f..d90b7c8 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -8,6 +8,7 @@ * Add `Argu.Samples.Introspect` sample [#298](https://github.com/fsprojects/Argu/pull/298) [@dimension-zero](https://github.com/dimension-zero) * Add `ArgumentParser.Parse(ParseConfig)` [#307](https://github.com/fsprojects/Argu/pull/307) [@dimension-zero](https://github.com/dimension-zero) * Add `ArgumentParser.PrintUsage(..., ?UsageStrings)` for localization support [#303](https://github.com/fsprojects/Argu/pull/303) [@dimension-zero](https://github.com/dimension-zero) +* Add AOT annotations on [#314](https://github.com/fsprojects/Argu/pull/314) [@dimension-zero](https://github.com/dimension-zero) * Obsolete `EqualsAssignmentAttribute`, `ColonAssignmentAttribute`, `CustomAssignmentAttribute`, `EqualsAssignmentOrSpacedAttribute`, `ColonAssignmentOrSpacedAttribute` and `CustomAssignmentOrSpacedAttribute` [#315](https://github.com/fsprojects/Argu/pull/315) [@dimension-zero](https://github.com/dimension-zero) * Obsolete `PostProcessResult`, `PostProcessResults`, `TryPostProcessResult` [#296](https://github.com/fsprojects/Argu/pull/296) [@dimension-zero](https://github.com/dimension-zero) diff --git a/src/Argu/Argu.fsproj b/src/Argu/Argu.fsproj index 45d8999..2e93b9d 100644 --- a/src/Argu/Argu.fsproj +++ b/src/Argu/Argu.fsproj @@ -5,8 +5,15 @@ true logo.png enable + + true + false + diff --git a/src/Argu/ArgumentParser.fs b/src/Argu/ArgumentParser.fs index ff2b194..9da0f5e 100644 --- a/src/Argu/ArgumentParser.fs +++ b/src/Argu/ArgumentParser.fs @@ -1,6 +1,8 @@ namespace Argu open FSharp.Quotations +open System.Diagnostics.CodeAnalysis + open Argu.UnionArgInfo /// Configuration record for . @@ -32,6 +34,14 @@ type ParseConfig = IgnoreUnrecognized = false RaiseOnUsage = true } +module internal TrimMessages = + [] + let aot = + "Argu reflects over the supplied F# discriminated union via MakeGenericType / Activator.CreateInstance to build its schema. This is not safe under publish-AOT; consider a hand-written parser for AOT scenarios." + [] + let trim = + "Argu walks the union schema via System.Reflection (FSharpType.GetUnionCases and friends). The trimmer cannot keep referenced union cases unless the consumer's root sees them; pin the template type with DynamicDependency or DynamicallyAccessedMembers attributes when trimming." + /// The Argu type generates an argument parser given a type argument /// that is an F# discriminated union. It can then be used to parse command line arguments /// or XML configuration. @@ -135,6 +145,8 @@ and [] /// Text width used when formatting the usage string. Defaults to 80 chars. /// The implementation of IExiter used for error handling. Exception is default. /// Indicate if the structure of the arguments discriminated union should be checked for errors. + [] + [] new (?programName : string, ?helpTextMessage : string, ?usageStringCharacterWidth : int, ?errorHandler : IExiter, ?checkStructure: bool) = let usageStringCharacterWidth = usageStringCharacterWidth |> Option.defaultWith getDefaultCharacterWidthSafeMin80 let programName = programName |> Option.defaultWith currentProgramName @@ -150,6 +162,8 @@ and [] member val ProgramName = _programName /// Force a check of the discriminated union structure. + [] + [] static member CheckStructure() = argInfoWithCheck.Value |> ignore @@ -313,6 +327,8 @@ type ArgumentParser with /// Text width used when formatting the usage string. Defaults to 80 chars. /// The implementation of IExiter used for error handling. Exception is default. /// Indicate if the structure of the arguments discriminated union should be checked for errors. + [] + [] static member Create<'Template when 'Template :> IArgParserTemplate>(?programName : string, ?helpTextMessage : string, ?usageStringCharacterWidth : int, ?errorHandler : IExiter, ?checkStructure: bool) = new ArgumentParser<'Template>(?programName = programName, ?helpTextMessage = helpTextMessage, ?errorHandler = errorHandler, ?usageStringCharacterWidth = usageStringCharacterWidth, ?checkStructure = checkStructure) @@ -327,9 +343,13 @@ module ArgumentParserUtils = r.CharacterWidth, r.ErrorHandler) /// converts a sequence of inputs to a ParseResults instance + [] + [] let toParseResults (inputs : seq<'Template>) : ParseResults<'Template> = ArgumentParser.Create<'Template>().ToParseResults(inputs) /// gets the F# union tag representation of given argument instance + [] + [] let tagOf (input : 'Template) : int = ArgumentParser.Create<'Template>().GetTag input diff --git a/src/Argu/TrimAnnotations.fs b/src/Argu/TrimAnnotations.fs new file mode 100644 index 0000000..a78464c --- /dev/null +++ b/src/Argu/TrimAnnotations.fs @@ -0,0 +1,40 @@ +// Polyfills for AOT/trim diagnostic attributes so that +// netstandard2.0 builds can carry the same metadata as .NET 7+ targets. +// The .NET trimmer / publish-AOT pipeline matches by full type name, +// not by assembly, so internal copies are picked up. +namespace System.Diagnostics.CodeAnalysis + +open System + +#if !NET7_0_OR_GREATER + +/// +/// Marker indicating that the annotated method requires dynamic-code +/// generation at runtime (e.g. MakeGenericType + +/// Activator.CreateInstance) and is therefore not safe under +/// publish-AOT. Callers that opt into AOT will see an IL3050 +/// warning when invoking the annotated member. +/// +[] +type internal RequiresDynamicCodeAttribute(message : string) = + inherit Attribute() + /// Reason the method requires dynamic code. + member _.Message = message + /// Optional URL pointing at extended documentation. + member val Url : string = null with get, set + +/// +/// Marker indicating that the annotated method uses reflection in a +/// way the trimmer cannot statically analyse (e.g. arbitrary type +/// reads via FSharpType.GetUnionCases). Callers that enable +/// trimming will see an IL2026 warning. +/// +[] +type internal RequiresUnreferencedCodeAttribute(message : string) = + inherit Attribute() + /// Reason the method holds unreferenced-code requirements. + member _.Message = message + /// Optional URL pointing at extended documentation. + member val Url : string = null with get, set + +#endif