Overview
Cosmos.Patcher.Build wires the Cosmos.Patcher tool into the MSBuild pipeline. Cosmos.Patcher rewrites IL in candidate assemblies by applying CosmosOS-style plugs so that the .NET Core framework can run on NativeAOT targets. Static analysis is provided by Cosmos.Patcher.Analyzer, which reports plug errors during C# compilation before any IL is rewritten.
.NET Assembly Structure
A .NET assembly (.dll or .exe) is a portable executable containing metadata and IL code. The patcher manipulates these structures using Mono.Cecil.
┌─────────────────────────────────────────────────────────────────────┐
│ AssemblyDefinition │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ Name: "MyAssembly" │ │
│ │ Version: 1.0.0.0 │ │
│ │ CustomAttributes: [AssemblyInfo, ...] │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ ModuleDefinition[0] │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ Name: "MyAssembly.dll" │ │ │
│ │ │ AssemblyReferences: [mscorlib, System.Runtime, ...] │ │ │
│ │ │ TypeReferences: [external type tokens] │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────────────────┐ │ │
│ │ │ TypeDefinition[0] │ │ │
│ │ │ ┌───────────────────────────────────────────────────┐ │ │ │
│ │ │ │ FullName: "MyNamespace.MyClass" │ │ │ │
│ │ │ │ BaseType: System.Object │ │ │ │
│ │ │ │ Interfaces: [IDisposable, ...] │ │ │ │
│ │ │ │ CustomAttributes: [Plug, Serializable, ...] │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ ┌─────────────────────────────────────────────┐ │ │ │ │
│ │ │ │ │ FieldDefinition[0] │ │ │ │ │
│ │ │ │ │ Name, FieldType, Attributes, Constant │ │ │ │ │
│ │ │ │ ├─────────────────────────────────────────────┤ │ │ │ │
│ │ │ │ │ FieldDefinition[n] │ │ │ │ │
│ │ │ │ └─────────────────────────────────────────────┘ │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ ┌─────────────────────────────────────────────┐ │ │ │ │
│ │ │ │ │ PropertyDefinition[0] │ │ │ │ │
│ │ │ │ │ Name, PropertyType, GetMethod, SetMethod │ │ │ │ │
│ │ │ │ ├─────────────────────────────────────────────┤ │ │ │ │
│ │ │ │ │ PropertyDefinition[n] │ │ │ │ │
│ │ │ │ └─────────────────────────────────────────────┘ │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ ┌─────────────────────────────────────────────┐ │ │ │ │
│ │ │ │ │ MethodDefinition[0] │ │ │ │ │
│ │ │ │ │ Name, ReturnType, Parameters, Attributes │ │ │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ │ │ ┌───────────────────────────────────────┐ │ │ │ │ │
│ │ │ │ │ │ MethodBody │ │ │ │ │ │
│ │ │ │ │ │ Variables: [local0, local1, ...] │ │ │ │ │ │
│ │ │ │ │ │ MaxStackSize: 8 │ │ │ │ │ │
│ │ │ │ │ │ InitLocals: true │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ │ │ │ │ Instructions: │ │ │ │ │ │
│ │ │ │ │ │ IL_0000: ldarg.0 │ │ │ │ │ │
│ │ │ │ │ │ IL_0001: call .ctor │ │ │ │ │ │
│ │ │ │ │ │ IL_0006: ldstr "Hello" │ │ │ │ │ │
│ │ │ │ │ │ IL_000B: call Console.WriteLine │ │ │ │ │ │
│ │ │ │ │ │ IL_0010: ret │ │ │ │ │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ │ │ │ │ ExceptionHandlers: │ │ │ │ │ │
│ │ │ │ │ │ [try/catch/finally blocks] │ │ │ │ │ │
│ │ │ │ │ └───────────────────────────────────────┘ │ │ │ │ │
│ │ │ │ ├─────────────────────────────────────────────┤ │ │ │ │
│ │ │ │ │ MethodDefinition[n] │ │ │ │ │
│ │ │ │ └─────────────────────────────────────────────┘ │ │ │ │
│ │ │ └───────────────────────────────────────────────────┘ │ │ │
│ │ ├─────────────────────────────────────────────────────────┤ │ │
│ │ │ TypeDefinition[n] │ │ │
│ │ └─────────────────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ ModuleDefinition[n] │ │
│ └───────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
Flow chart
flowchart TD
A[SetupPatcher] --> B[FindPluggedAssembliesTask]
B --> C{AssembliesToPatch}
C -->|for each| D[PatcherTask]
D --> E[Program patch]
E --> F[PatchCommand.Execute]
F --> G[PlugScanner.LoadPlugs]
G --> H[PlugPatcher.PatchAssembly]
H --> I[ProcessPlugMembers]
I --> J[MethodResolver.ResolveMethod]
J --> K[MethodPatcher.PatchMethod]
K --> L[ILCloner.CloneInstructions]
L --> M[TypeImporter.SafeImport*]
I --> N[PropertyPatcher.PatchProperty]
I --> O[FieldPatcher.PatchField]
K --> P[Patched assemblies]
N --> P
O --> P
A --> X[CleanPatcher]
Parameters
| Name | Description | Default |
|---|---|---|
EnablePatching |
Enables or disables patching. | true |
CosmosPatcherExe |
Path to the Cosmos.Patcher executable. |
%USERPROFILE%\.dotnet\tools\cosmos.patcher.exe on Windows, cosmos.patcher on Unix |
PatcherOutputPath |
Directory where patched assemblies are written. | $(IntermediateOutputPath)/cosmos/ref/ |
PlugReference |
Names of plug assemblies to include. | none |
Tasks
| Task | Description | Depends On |
|---|---|---|
SetupPatcher |
Collects candidate assemblies, resolves plug references, and prepares output directories. | Build, ResolveIlcPath |
RunPatcher |
Executes Cosmos.Patcher for each entry in AssembliesToPatch. |
SetupPatcher |
CleanPatcher |
Removes files generated by the patcher. | Clean |
FindPluggedAssembliesTask |
Filters candidate assemblies to only those containing target types. | SetupPatcher |
PatcherTask |
MSBuild wrapper around Cosmos.Patcher for custom scenarios. |
none |
Detailed workflow
SetupPatcher gathers output and reference assemblies, resolves plug references, and stores them in
$(IntermediateOutputPath)/cosmos.FindPluggedAssembliesTask uses
PlugScanner.FindPluggedAssembliesto cross-reference plug targets against the candidate assemblies and producesAssembliesToPatch.RunPatcher iterates over
AssembliesToPatchand, for each assembly, thePatcherTasklaunches theCosmos.PatcherCLI (Program→PatchCommand.Execute). InsideExecute:- The target assembly and the plug assemblies are read through
PatcherAssemblyLoaderwith aPatcherAssemblyResolverthat searches the directories of the target, the plugs and the output, plus the onesRunPatcherpasses with--search(cosmos/refand the directory of every candidate assembly). Writing a patched assembly back resolves the types its constants are typed with: aconstfield or a default parameter typed as an enum from another Cosmos assembly needs that assembly found, and Mono.Cecil's default resolver looks only in the current directory and the host runtime. PlugScanner.LoadPlugsdiscovers plug types in those assemblies.PlugPatcher.PatchAssemblygroups plugs by their[Plug]target and patches each target type using:MethodResolvermatches plug signatures (including constructors andaThisparameters) by name and parameter types.PlugPatcher.Methodswaps or clones IL and strips P/Invoke metadata.ILClonerclones instructions, remaps parameters, and fixes branch targets.TypeImportersafely imports type/method/field references, fixing self-references that would cause invalid IL metadata.PlugPatcher.Propertywires getters and setters to plug implementations.PlugPatcher.Fieldcopies constant values and redirects field accesses.
- The patched assembly is written to
PatcherOutputPath.
- The target assembly and the plug assemblies are read through
CleanPatcher deletes the patched output when the project is cleaned.
Cosmos.Patcher.Analyzervalidates plug rules during compilation to catch errors before patching.
Outputs
- Patched app assembly:
$(IntermediateOutputPath)/cosmos/$(AssemblyName)_patched.dll, the main project output after plug application. - Reference assemblies for ILC:
$(IntermediateOutputPath)/cosmos/ref/*.dll, patched where plugs apply; otherwise copied unmodified for resolution. - Intermediate directories are created on demand under
$(IntermediateOutputPath)/cosmos/.
Notes:
RunPatcheronly runs whenEnablePatchingistrueand afterSetupPatchercomputes@(AssembliesToPatch)and destinations.