From 318ca354b824513afe22793470b563c073c09a1c Mon Sep 17 00:00:00 2001 From: David Pine Date: Mon, 12 Jun 2023 08:38:55 -0500 Subject: [PATCH 1/2] Add details about .NET 8 IsAotCompatible prop --- docs/core/deploying/native-aot/index.md | 46 ++++++++++---- .../prepare-libraries-for-trimming.md | 63 ++++++++++--------- 2 files changed, 66 insertions(+), 43 deletions(-) diff --git a/docs/core/deploying/native-aot/index.md b/docs/core/deploying/native-aot/index.md index 92f5d4bc3ad03..1c2299a4d5cbd 100644 --- a/docs/core/deploying/native-aot/index.md +++ b/docs/core/deploying/native-aot/index.md @@ -3,15 +3,16 @@ title: Native AOT deployment overview description: Learn what native AOT deployments are and why you should consider using it as part of the publishing your app with .NET 7 and later. author: lakshanf ms.author: lakshanf -ms.date: 05/05/2023 +ms.date: 06/12/2023 --- + # Native AOT deployment Publishing your app as *native AOT* produces an app that's [self-contained](../index.md#publish-self-contained) and that has been ahead-of-time (AOT) compiled to native code. Native AOT apps have faster startup time and smaller memory footprints. These apps can run on machines that don't have the .NET runtime installed. The benefit of native AOT is most significant for workloads with a high number of deployed instances, such as cloud infrastructure and hyper-scale services. Native AOT deployment is currently in [preview for ASP.NET Core 8.0](/aspnet/core/fundamentals/native-aot/?view=aspnetcore-8.0&preserve-view=true). -The native AOT deployment model uses an ahead-of-time compiler to compile IL to native code at the time of publish. Native AOT apps don't use a just-in-time (JIT) compiler when the application runs. Native AOT apps can run in restricted environments where a JIT is not allowed. Native AOT applications target a specific runtime environment, such as Linux x64 or Windows x64, just like publishing a [self-contained app](../index.md#publish-self-contained). +The native AOT deployment model uses an ahead-of-time compiler to compile IL to native code at the time of publish. Native AOT apps don't use a just-in-time (JIT) compiler when the application runs. Native AOT apps can run in restricted environments where a JIT isn't allowed. Native AOT applications target a specific runtime environment, such as Linux x64 or Windows x64, just like publishing a [self-contained app](../index.md#publish-self-contained). There are some limitations in the .NET native AOT deployment model, with the main one being that run-time code generation isn't possible. For more information, see [Limitations of Native AOT deployment](#limitations-of-native-aot-deployment). The support in the .NET 7 release is targeted towards console-type applications. @@ -42,7 +43,7 @@ On macOS, install the latest [Command Line Tools for XCode](https://developer.ap ## Publish native AOT using the CLI -01. Add `true` to your project file. +1. Add `true` to your project file. This property enables native AOT compilation during publish. It also enables dynamic code-usage analysis during build and editing. It's preferable to put this setting in the project file rather than passing it on the command line, since it controls behaviors outside publish. @@ -52,25 +53,44 @@ On macOS, install the latest [Command Line Tools for XCode](https://developer.ap ``` -02. Publish the app for a specific runtime identifier using `dotnet publish -r `. +1. Publish the app for a specific runtime identifier using `dotnet publish -r `. The following example publishes the app for Windows as a native AOT application on a machine with the required prerequisites installed. `dotnet publish -r win-x64 -c Release` - The following example publishes the app for Linux as a native AOT application. A native AOT binary produced on Linux machine is only going to work on same or newer Linux version. For example, native AOT binary produced on Ubuntu 20.04 is going to run on Ubuntu 20.04 and later, but it is not going to run on Ubuntu 18.04. + The following example publishes the app for Linux as a native AOT application. A native AOT binary produced on Linux machine is only going to work on same or newer Linux version. For example, native AOT binary produced on Ubuntu 20.04 is going to run on Ubuntu 20.04 and later, but it isn't going to run on Ubuntu 18.04. `dotnet publish -r linux-arm64 -c Release` -The app will be available in the publish directory and will contain all the code needed to run in it, including a stripped-down version of the coreclr runtime. +The app is available in the publish directory and contains all the code needed to run in it, including a stripped-down version of the coreclr runtime. Check out the [native AOT samples](https://github.com/dotnet/samples/tree/main/core/nativeaot) available in the dotnet/samples repository on GitHub. The samples include [Linux](https://github.com/dotnet/samples/blob/main/core/nativeaot/HelloWorld/Dockerfile) and [Windows](https://github.com/dotnet/samples/blob/main/core/nativeaot/HelloWorld/Dockerfile.windowsservercore-x64) Dockerfiles that demonstrate how to automate installation of prerequisites and publish .NET projects with native AOT using containers. +## AOT-compatibility analyzers + +Starting with .NET 8.0, library authors use the `IsAotCompatible` property to indicate whether a library is compatible with native AOT. Consider when a library sets the `IsAotCompatible` property to `true`, for example: + +```xml + + true + +``` + +The preceding configuration would assign a default of `true` the following properties: + +- `IsTrimmable` +- `EnableTrimAnalyzer` +- `EnableSingleFileAnalyzer` +- `EnableAotAnalyzer` + +These analyzers help to ensure that a library is compatible with native AOT. + ## Native debug information ### [.NET 7](#tab/net7) -Native AOT publishing follows platform conventions for native toolchains. The default behavior of native toolchains on Windows is to produce debug information in a separate *.pdb* file. The default behavior of native toolchains on Linux is to include the debug information in the native binary, which makes the native binary significantly larger. +Native AOT publishing follows platform conventions for native toolchains. The default behavior of native toolchains on Windows is to produce debug information in a separate *.pdb* file. The default behavior of native toolchains on Linux is to include the debug information in the native binary, which makes the native binary larger. Set the `StripSymbols` property to `true` to produce the debug information in a separate *.dbg* file and exclude it from the native binary on Linux. (This property has no effect on Windows.) @@ -82,7 +102,7 @@ Set the `StripSymbols` property to `true` to produce the debug information in a ### [.NET 8+](#tab/net8plus) -By default, native AOT publishing produces debug information in a separate file on all supported platforms (*.dbg* on Linux, *.pdb* on Windows, and *.dwarf* on macOS). This file is necessary for running the app under the debugger or inspecting crash dumps. On Unix-like platforms, you can set the `StripSymbols` property to `false` to include the debug information in the native binary. (Including the debug information makes the native binary significantly larger.) +By default, native AOT publishing produces debug information in a separate file on all supported platforms (*.dbg* on Linux, *.pdb* on Windows, and *.dwarf* on macOS). This file is necessary for running the app under the debugger or inspecting crash dumps. On Unix-like platforms, you can set the `StripSymbols` property to `false` to include the debug information in the native binary. (Including the debug information makes the native binary larger.) ```xml @@ -103,14 +123,14 @@ Native AOT applications come with a few fundamental limitations and compatibilit - Requires trimming, which has [limitations](../trimming/incompatibilities.md). - Implies compilation into a single file, which has known [incompatibilities](../single-file/overview.md#api-incompatibility). - Apps include required runtime libraries (just like [self-contained apps](../index.md#publish-self-contained), increasing their size as compared to framework-dependent apps). -- always use interpreted form, that is much slower than run-time generated compiled code. +- always use their interpreted form, which is slower than run-time generated compiled code. -The publish process analyzes the entire project and its dependencies and produces warnings whenever the limitations could potentially be hit by the published application at run time. +The publish process analyzes the entire project and its dependencies and produces warnings whenever the limitations of the published application might be encountered at run time. -The first release of native AOT in .NET 7 has these additional limitations: +The first release of native AOT in .NET 7 has some more limitations: - Should be targeted for console type applications (not ASP.NET Core). -- Not all the runtime libraries are fully annotated to be native AOT compatible (that is, some warnings in the runtime libraries are not actionable by end developers). +- Not all the runtime libraries are fully annotated to be native AOT compatible (that is, some warnings in the runtime libraries aren't actionable by end developers). - Limited diagnostic support (debugging and profiling). ## Build native libraries @@ -124,7 +144,7 @@ Publishing a class library as native AOT creates a native library that exposes m The following table shows supported compilation targets. | Platform | Supported architecture | -| -------- | ---------------------- | +|----------|------------------------| | Windows | x64, Arm64 | | Linux | x64, Arm64 | | macOS* | x64, Arm64 | diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md index dce0378b2974e..1cc53690e9409 100644 --- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md +++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md @@ -3,7 +3,7 @@ title: Prepare .NET libraries for trimming description: Learn how to prepare .NET libraries for trimming. author: sbomer ms.author: svbomer -ms.date: 04/16/2021 +ms.date: 06/12/2023 --- # Prepare .NET libraries for trimming @@ -20,35 +20,37 @@ There are two ways to find trim warnings in your library: 1. Enable project-specific trimming using the `IsTrimmable` property. 2. Add your library as a reference to a sample app, and trim the sample app. -Consider doing both. Project-specific trimming is convenient and shows trim warnings for one project, but relies on the references being marked trim-compatible in order to see all warnings. Trimming a sample app is more work, but will always show all warnings. +Consider doing both. Project-specific trimming is convenient and shows trim warnings for one project, but relies on the references being marked trim-compatible to see all warnings. Trimming a sample app is more work, but will always show all warnings. ### Enable project-specific trimming > [!TIP] -> To get the latest version of the analyzer with the most coverage, use the [.NET 7 SDK](https://dotnet.microsoft.com/en-us/download/dotnet). Note this will only update the tooling used to build your app and doesn't require you to target the .NET 7 runtime. +> To get the latest version of the analyzer with the most coverage, use the [.NET 7 SDK](https://dotnet.microsoft.com/download/dotnet). Note this will only update the tooling used to build your app and doesn't require you to target the .NET 7 runtime. -Set `true` in a `` tag in your library project file. This will mark your assembly as "trimmable" and enable trim warnings for that project. Being "trimmable" means your library is considered compatible with trimming and should have no trim warnings when building the library. When used in a trimmed application, the assembly will have its unused members trimmed in the final output. +Set `true` in a `` tag in your library project file. This marks your assembly as "trimmable" and enable trim warnings for that project. Being "trimmable" means your library is considered compatible with trimming and should have no trim warnings when building the library. When used in a trimmed application, the assembly has its unused members trimmed in the final output. + +The `IsTrimmable` property defaults to `true` when configuring a library as AOT-compatible (`true`). For more information, see [AOT-compatibility analyzers](../native-aot/index.md#aot-compatibility-analyzers). If you want to see trim warnings, but don't want to mark your library as trim-compatible, you can add `true` instead. ### Show all warnings with sample application -To show all analysis warnings for your library, including warnings about dependencies, you need the trimmer to analyze the implementation of your library and the implementations of dependencies your library uses. When building and publishing a library, the implementations of the dependencies are not available, and the reference assemblies that are available do not have enough information for the trimmer to determine if they are compatible with trimming. Because of this, you'll need to create and publish a self-contained sample application which produces an executable that includes your library and the dependencies it relies on. This executable includes all the information the trimmer requires to warn you about all trim incompatibilities in your library code, as well as the code that your library references from its dependencies. +To show all analysis warnings for your library, including warnings about dependencies, you need the trimmer to analyze the implementation of your library and the implementations of dependencies your library uses. When building and publishing a library, the implementations of the dependencies aren't available, and the available reference assemblies don't have enough information for the trimmer to determine if they're compatible with trimming. Because of this, you need to create and publish a self-contained sample application, which produces an executable that includes your library and the dependencies it relies on. This executable includes all the information the trimmer requires to warn you about all trim incompatibilities in your library code, and the code that your library references from its dependencies. > [!NOTE] > If your library has significantly different behavior or uses different APIs depending on the target framework of the consumer (for example, using `#if NET7_0`) which might impact trimming, you will need to create a new sample app for each of the target frameworks you want to support trimming for. -To create your sample app, first create a separate console application project with `dotnet new console` and modify the project file to look like the following. No changes to the source code are necessary. You'll need to do the following in your project file: +To create your sample app, first create a separate console application project with `dotnet new console` and modify the project file to look like the following. No changes to the source code are necessary. You need to do the following in your project file: - Set the PublishTrimmed property to `true` with `true` in a `` tag. - Add a reference to your library project with `` inside of an `` tag. - Specify your library as a trimmer root assembly with `` in an `` tag. - - This ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root" which means the trimmer will analyze the assembly as if everything will be used, and traverses all possible code paths that originate from that assembly. This is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`, which would otherwise let trimming remove the unused library without analyzing it. -- If your app targets .Net 6, set the TrimmerDefaultAction property to `link` with `link` in a `` tag. -- If your app targets .Net 7, [the new default behavior](../../../core/compatibility/deployment/7.0/trim-all-assemblies.md) is what you want, but you can enforce the behavior by adding `full` in a `` tag. - - This ensures that the trimmer only analyzes the parts of the library's dependencies that are used. It tells the trimmer that any code that is not part of a "root" can be trimmed if it is unused. Without this option, you would see warnings originating from _any_ part of a dependency that doesn't set `[AssemblyMetadata("IsTrimmable", "True")]`, including parts that are unused by your library. + - This ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root" that means the trimmer analyzes the assembly as if everything were used, and traverses all possible code paths that originate from that assembly. This is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`, which would otherwise let trimming remove the unused library without analyzing it. +- If your app targets .NET 6, set the TrimmerDefaultAction property to `link` with `link` in a `` tag. +- If your app targets .NET 7, [the new default behavior](../../../core/compatibility/deployment/7.0/trim-all-assemblies.md) is what you want, but you can enforce the behavior by adding `full` in a `` tag. + - This ensures that the trimmer only analyzes the parts of the library's dependencies that are used. It tells the trimmer that any code that isn't part of a "root" can be trimmed if it's unused. Without this option, you would see warnings originating from _any_ part of a dependency that doesn't set `[AssemblyMetadata("IsTrimmable", "True")]`, including parts that are unused by your library. -##### .Net 6 .csproj +##### .NET 6 .csproj ```xml @@ -71,7 +73,7 @@ To create your sample app, first create a separate console application project w ``` -##### .Net 7 .csproj +##### .NET 7 .csproj ```xml @@ -97,14 +99,14 @@ Once your project file is updated, run `dotnet publish` with the [runtime identi dotnet publish -c Release -r ``` -You can also follow the same pattern for multiple libraries. To see trim analysis warnings for more than one library at a time, add them all to the same project as `ProjectReference` and `TrimmerRootAssembly` items. This will warn about dependencies if _any_ of the root libraries use a trim-unfriendly API in a dependency. To see warnings that have to do with only a particular library, reference that library only. +You can also follow the same pattern for multiple libraries. To see trim analysis warnings for more than one library at a time, add them all to the same project as `ProjectReference` and `TrimmerRootAssembly` items. This warns about dependencies if _any_ of the root libraries use a trim-unfriendly API in a dependency. To see warnings that have to do with only a particular library, reference that library only. > [!NOTE] > The analysis results depend on the implementation details of your dependencies. If you update to a new version of a dependency, this may introduce analysis warnings if the new version added non-understood reflection patterns, even if there were no API changes. In other words, introducing trim analysis warnings to a library is a breaking change when the library is used with `PublishTrimmed`. ## Resolve trim warnings -The above steps will produce warnings about code that may cause problems when used in a trimmed app. Here are a few examples of the most common kinds of warnings you may encounter, with recommendations for fixing them. +The above steps produce warnings about code that may cause problems when used in a trimmed app. Here are a few examples of the most common kinds of warnings you may encounter, with recommendations for fixing them. ### RequiresUnreferencedCode @@ -121,7 +123,8 @@ public class MyLibrary DynamicBehavior(); } - [RequiresUnreferencedCode("DynamicBehavior is incompatible with trimming.")] + [RequiresUnreferencedCode( + "DynamicBehavior is incompatible with trimming.")] static void DynamicBehavior() { } @@ -139,7 +142,7 @@ public static void Method() } ``` -Once you have "bubbled up" the attribute all the way to public APIs (so that these warnings are produced only for public methods, if at all), you are done. Apps that call your library will now get warnings if they call those public APIs, but these will no longer produce warnings like `IL2104: Assembly 'MyLibrary' produced trim warnings`. +Once you have "bubbled up" the attribute all the way to public APIs (so that these warnings are produced only for public methods, if at all), you're done. Apps that call your library will now get warnings if they call those public APIs, but these will no longer produce warnings like `IL2104: Assembly 'MyLibrary' produced trim warnings`. ### DynamicallyAccessedMembers @@ -173,9 +176,9 @@ static void UseMethods( } ``` -Now any calls to `UseMethods` will produce warnings if they pass in values that don't satisfy the `PublicMethods` requirement. Like with `RequiresUnreferencedCode`, once you have bubbled up such warnings to public APIs, you are done. +Now any calls to `UseMethods` produce warnings if they pass in values that don't satisfy the `PublicMethods` requirement. Like with `RequiresUnreferencedCode`, once you have bubbled up such warnings to public APIs, you're done. -Here is another example where an unknown `Type` flows into the annotated method parameter, this time from a field: +Here's another example where an unknown `Type` flows into the annotated method parameter, this time from a field: ```csharp static Type type; @@ -189,7 +192,7 @@ static void UseMethodsHelper() } ``` -Similarly, here the problem is that the field `type` is passed into a parameter with these requirements. You can fix it by adding `DynamicallyAccessedMembers` to the field. This will warn about code that assigns incompatible values to the field instead. Sometimes this process will continue until a public API is annotated, and other times it will end when a concrete type flows into a location with these requirements. For example: +Similarly, here the problem is that the field `type` is passed into a parameter with these requirements. You can fix it by adding `DynamicallyAccessedMembers` to the field. This warns about code that assigns incompatible values to the field instead. Sometimes this process continues until a public API is annotated, and other times it ends when a concrete type flows into a location with these requirements. For example: ```csharp [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] @@ -201,21 +204,21 @@ static void InitializeTypeField() } ``` -In this case the trim analysis will simply keep public methods of `System.Tuple`, and will not produce further warnings. +In this case, the trim analysis keeps public methods of , and produces further warnings. ## Recommendations -In general, try to avoid reflection if possible. When using reflection, limit it in scope so that it is reachable only from a small part of the library. +In general, try to avoid reflection if possible. When using reflection, limit it in scope so that it's reachable only from a small part of the library. -- Avoid using non-understood patterns in places like static constructors that will result in the warning propagating to all members of the class. +- Avoid using non-understood patterns in places like static constructors that result in the warning propagating to all members of the class. - Avoid annotating virtual methods or interface methods, which will require all overrides to have matching annotations. -- In some cases, you will be able to mechanically propagate warnings through your code without issues. Sometimes this will result in much of your public API being annotated with `RequiresUnreferencedCode`, which is the right thing to do if the library indeed behaves in ways that can't be understood statically by the trim analysis. +- In some cases, you're able to mechanically propagate warnings through your code without issues. Sometimes this results in much of your public API being annotated with `RequiresUnreferencedCode`, which is the right thing to do if the library indeed behaves in ways that can't be understood statically by the trim analysis. - In other cases, you might discover that your code uses patterns that can't be expressed in terms of the `DynamicallyAccessedMembers` attributes, even if it only uses reflection to operate on statically known types. In these cases, you may need to reorganize some of your code to make it follow an analyzable pattern. -- Sometimes the existing design of an API will render it mostly trim-incompatible, and you may need to find other ways to accomplish what it is doing. A common example is reflection-based serializers. In these cases, consider adopting other technology like source generators to produce code that is more easily statically analyzed. +- Sometimes the existing design of an API renders it mostly trim-incompatible, and you may need to find other ways to accomplish what it's doing. A common example is reflection-based serializers. In these cases, consider adopting other technology like source generators to produce code that is more easily statically analyzed. ## Resolve warnings for non-analyzable patterns -It's better to resolve warnings by expressing the intent of your code using `RequiresUnreferencedCode` and `DynamicallyAccessedMembers` when possible. However, in some cases you may be interested in enabling trimming of a library that uses patterns that can't be expressed with those attributes, or without refactoring existing code. This section describes some advanced ways to resolve trim analysis warnings. +It's better to resolve warnings by expressing the intent of your code using `RequiresUnreferencedCode` and `DynamicallyAccessedMembers` when possible. However, in some cases, you may be interested in enabling trimming of a library that uses patterns that can't be expressed with those attributes, or without refactoring existing code. This section describes some advanced ways to resolve trim analysis warnings. > [!WARNING] > These techniques might break your code if used incorrectly. @@ -263,7 +266,7 @@ class TypeWithConstructor Here, the indexer property has been annotated so that the returned `Type` meets the requirements of `CreateInstance`. This already ensures that the `TypeWithConstructor` constructor is kept, and that the call to `CreateInstance` doesn't warn. Furthermore, the indexer setter annotation ensures that any types stored in the `Type[]` have a constructor. However, the analysis isn't able to see this, and still produces a warning for the getter, because it doesn't know that the returned type has its constructor preserved. -If you are sure that the requirements are met, you can silence this warning by adding `UnconditionalSuppressMessage` to the getter: +If you're sure that the requirements are met, you can silence this warning by adding `UnconditionalSuppressMessage` to the getter: ```csharp [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] @@ -276,7 +279,7 @@ public Type this[int i] } ``` -It is important to underline that it is only valid to suppress a warning if there are annotations or code that ensure the reflected-on members are visible targets of reflection. It is not sufficient that the member was simply a target of a call, field or property access. It may appear to be the case sometimes but such code is bound to break eventually as more trimming optimizations are added. Properties, fields, and methods that are not visible targets of reflection could be inlined, have their names removed, get moved to different types, or otherwise optimized in ways that will break reflecting on them. When suppressing a warning, it's only permissible to reflect on targets that were visible targets of reflection to the trimming analyzer elsewhere. +It's important to underline that it's only valid to suppress a warning if there are annotations or code that ensure the reflected-on members are visible targets of reflection. It isn't sufficient that the member was simply a target of a call, field or property access. It may appear to be the case sometimes but such code is bound to break eventually as more trimming optimizations are added. Properties, fields, and methods that aren't visible targets of reflection could be inlined, have their names removed, get moved to different types, or otherwise optimized in ways that break reflecting on them. When suppressing a warning, it's only permissible to reflect on targets that were visible targets of reflection to the trimming analyzer elsewhere. ```csharp [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2063", @@ -299,7 +302,7 @@ public string Serialize(object o) ### DynamicDependency -This attribute can be used to indicate that a member has a dynamic dependency on other members. This results in the referenced members being kept whenever the member with the attribute is kept, but doesn't silence warnings on its own. Unlike the other attributes which teach the trim analysis about the reflection behavior of your code, `DynamicDependency` only keeps additional members. This can be used together with `UnconditionalSuppressMessageAttribute` to fix some analysis warnings. +This attribute can be used to indicate that a member has a dynamic dependency on other members. This results in the referenced members being kept whenever the member with the attribute is kept, but doesn't silence warnings on its own. Unlike the other attributes that teach the trim analysis about the reflection behavior of your code, `DynamicDependency` only keeps other members. This can be used together with `UnconditionalSuppressMessageAttribute` to fix some analysis warnings. > [!WARNING] > Use `DynamicDependencyAttribute` only as a last resort when the other approaches aren't viable. It is preferable to express the reflection behavior of your code using `RequiresUnreferencedCodeAttribute` or `DynamicallyAccessedMembersAttribute`. @@ -317,7 +320,7 @@ Without `DynamicDependency`, trimming might remove `Helper` from `MyAssembly` or The attribute specifies the members to keep via a `string` or via `DynamicallyAccessedMemberTypes`. The type and assembly are either implicit in the attribute context, or explicitly specified in the attribute (by `Type`, or by `string`s for the type and assembly name). -The type and member strings use a variation of the C# documentation comment ID string [format](/dotnet/csharp/language-reference/language-specification/documentation-comments#id-string-format), without the member prefix. The member string should not include the name of the declaring type, and may omit parameters to keep all members of the specified name. Some examples of the format follow: +The type and member strings use a variation of the C# documentation comment ID string [format](/dotnet/csharp/language-reference/language-specification/documentation-comments#id-string-format), without the member prefix. The member string shouldn't include the name of the declaring type, and may omit parameters to keep all members of the specified name. Some examples of the format follow: ```csharp [DynamicDependency("Method()")] @@ -334,4 +337,4 @@ The type and member strings use a variation of the C# documentation comment ID s [DynamicDependency("MethodOnGenericType(`0)", typeof(GenericType<>))] ``` -This attribute is designed to be used in cases where a method contains reflection patterns that can not be analyzed even with the help of `DynamicallyAccessedMembersAttribute`. +This attribute is designed to be used in cases where a method contains reflection patterns that can't be analyzed even with the help of `DynamicallyAccessedMembersAttribute`. From 44fa537c2ea5644d1c4a31ce9e8ae559f0183714 Mon Sep 17 00:00:00 2001 From: David Pine Date: Mon, 12 Jun 2023 14:34:34 -0500 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Tom Dykstra --- docs/core/deploying/native-aot/index.md | 2 +- .../deploying/trimming/prepare-libraries-for-trimming.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/core/deploying/native-aot/index.md b/docs/core/deploying/native-aot/index.md index 1c2299a4d5cbd..be4a989519a83 100644 --- a/docs/core/deploying/native-aot/index.md +++ b/docs/core/deploying/native-aot/index.md @@ -77,7 +77,7 @@ Starting with .NET 8.0, library authors use the `IsAotCompatible` property to in ``` -The preceding configuration would assign a default of `true` the following properties: +The preceding configuration assigns a default of `true` to the following properties: - `IsTrimmable` - `EnableTrimAnalyzer` diff --git a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md index 1cc53690e9409..4a1e16a83311d 100644 --- a/docs/core/deploying/trimming/prepare-libraries-for-trimming.md +++ b/docs/core/deploying/trimming/prepare-libraries-for-trimming.md @@ -45,8 +45,8 @@ To create your sample app, first create a separate console application project w - Set the PublishTrimmed property to `true` with `true` in a `` tag. - Add a reference to your library project with `` inside of an `` tag. - Specify your library as a trimmer root assembly with `` in an `` tag. - - This ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root" that means the trimmer analyzes the assembly as if everything were used, and traverses all possible code paths that originate from that assembly. This is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`, which would otherwise let trimming remove the unused library without analyzing it. -- If your app targets .NET 6, set the TrimmerDefaultAction property to `link` with `link` in a `` tag. + - This ensures that every part of the library is analyzed. It tells the trimmer that this assembly is a "root," which means the trimmer analyzes the assembly as if everything were used, and traverses all possible code paths that originate from that assembly. This is necessary in case the library has `[AssemblyMetadata("IsTrimmable", "True")]`, which would otherwise let trimming remove the unused library without analyzing it. +- If your app targets .NET 6, set the `TrimmerDefaultAction` property to `link` with `link` in a `` element. - If your app targets .NET 7, [the new default behavior](../../../core/compatibility/deployment/7.0/trim-all-assemblies.md) is what you want, but you can enforce the behavior by adding `full` in a `` tag. - This ensures that the trimmer only analyzes the parts of the library's dependencies that are used. It tells the trimmer that any code that isn't part of a "root" can be trimmed if it's unused. Without this option, you would see warnings originating from _any_ part of a dependency that doesn't set `[AssemblyMetadata("IsTrimmable", "True")]`, including parts that are unused by your library. @@ -302,7 +302,7 @@ public string Serialize(object o) ### DynamicDependency -This attribute can be used to indicate that a member has a dynamic dependency on other members. This results in the referenced members being kept whenever the member with the attribute is kept, but doesn't silence warnings on its own. Unlike the other attributes that teach the trim analysis about the reflection behavior of your code, `DynamicDependency` only keeps other members. This can be used together with `UnconditionalSuppressMessageAttribute` to fix some analysis warnings. +This attribute can be used to indicate that a member has a dynamic dependency on other members. This results in the referenced members being kept whenever the member with the attribute is kept, but doesn't silence warnings on its own. Unlike the other attributes, which inform the trim analysis about the reflection behavior of your code, `DynamicDependency` only keeps other members. This can be used together with `UnconditionalSuppressMessageAttribute` to fix some analysis warnings. > [!WARNING] > Use `DynamicDependencyAttribute` only as a last resort when the other approaches aren't viable. It is preferable to express the reflection behavior of your code using `RequiresUnreferencedCodeAttribute` or `DynamicallyAccessedMembersAttribute`.