# Microsoft.DotNet.SharedFramework.Sdk

This package provides a common set of tools for authoring framework packs, shared frameworks, and packages and installers for packs and frameworks.

## Building Framework Packs

This SDK supports building framework packs based on the [official design](https://github.com/dotnet/designs/blob/master/accepted/2019/targeting-packs-and-runtime-packs.md) as well as additional extensions such as profiles and single-file support. To define a shared framework project, create a project with the `.sfxproj` suffix that references both the `Microsoft.NET.Sdk` and `Microsoft.DotNet.SharedFramework.Sdk` SDKs and defines the name in the `SharedFrameworkName` property and the pack type in the `PlatformPackageType` property.

An example project is included below:

```xml
<Project Sdk="Microsoft.NET.Sdk">
  <Sdk Name="Microsoft.DotNet.SharedFramework.Sdk" />
  <PropertyGroup>
     <!-- Required properties -->
    <TargetFramework>netcoreapp3.0</TargetFramework>
    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
    <SharedFrameworkName>Microsoft.Banana.App</SharedFrameworkName>
    <PlatformPackageType>RuntimePack</PlatformPackageType>
    <DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
  </PropertyGroup>
  
  <ItemGroup>
    <FrameworkReference Include="Microsoft.NETCore.App" RuntimeFrameworkVersion="3.0.0" />
    
    <ProjectReference Include="..\..\MyAssembly1\MyAssembly1.csproj" />
    <ProjectReference Include="..\..\MyAssembly2\MyAssembly2.csproj" />
    <PackageReference Include="Foo" Version="1.0.4" />
    
    <NativeRuntimeAsset Include="linux-x64/libmydep.so" Condition=" '$(RuntimeIdentifier)' == 'linux-x64' " />
  </ItemGroup>
  
</Project>
```

This example project shows some of the basic options provided by the SDK. The `SharedFrameworkName` property specifies the name of the shared framework. This is used to determine the NuGet package ID as well as appearing in various data files generated by the build. The `PlatformPackageType` property specifies the type of pack the project defines. There are four types of packs this SDK supports:

- `RuntimePack`: RID-specific runtime packages
- `TargetingPack`: Packs of reference assemblies
- `AppHostPack`: Pack containing the app hosts
- `ToolPack`: This pack option allows you to have completely custom scripting for what files are included where in your pack. It also enables creating installer-only projects with this SDK.

This SDK uses the standard mechanisms in the .NET SDK for referencing packages, projects, and other frameworks to resolve its dependencies and collect the files that are a part of the pack. To include native files, add them to the `NativeRuntimeAsset` item group.

If you need to resolve additional managed assemblies, you can add them to the `ReferenceCopyLocalPaths` item group for runtime packs or `ReferencePath` for targeting packs. XML documentation files can be added to the `DocFilesToPackage` item group. If you need to resolve your assemblies in a target, you can define your own target to resolve them. To enable these files to have ReadyToRun code generated for them for a runtime pack, update the `GetSharedFrameworkFilesForReadyToRunDependsOn` property to include your targets in a semicolon-delimited list. If you are adding additional files to a targeting pack, add `BeforeTargets="GetFilesToPackage"` to the target definition.

### Deps file generation

By default, the SDK will generate a .deps.json file for runtime packs named `$(SharedFrameworkName).deps.json`. You can set the `$(SharedFrameworkHostFileNameOverride)` property to instead generate the deps file with the name `$(SharedFrameworkHostFileNameOverride).deps.json`. The RID fallback graph can be included by setting `$(IncludeFallbacksInDepsFile)` to `true`.

### Runtimeconfig file generation

This SDK uses the built-in .NET SDK generation for .runtimeconfig.json files for runtime packs. By default, the output file will be named `$(SharedFrameworkName).runtimeconfig.json`. You can override it to be named `$(SharedFrameworkHostFileNameOverride).runtimeconfig.json`.

### Platform Manifest generation

Since platform manifest generation can be tricky at times when a shared framework has differing files per platform, this SDK provides two different mechanisms for generating a platform manifest, templating or harvesting.

Pros of harvesting:

- Simple declaration in the project file.
  - You define a property in the targeting pack project that points to the runtime pack project. The SDK will determine all of the files that the runtime pack project produces on RIDs that this build will produce.
- Less friction when adding files to the manifest.
  - Files will be automatically added by the harvesting process.

Cons of harvesting:

- Either all runtime pack RIDs must be buildable from a single invocation or one RID must have a superset of all files in the targeting pack.

Pros of templating:

- All files can be declared to be in the manifest without needing every file on disk.
  - As a result, this enables building a targeting pack for a runtime pack that has disjoint sets of files on different RIDs, such as Microsoft.NETCore.App, without needing to download any runtime pack builds.
- Targeting pack can be built independently of the runtime pack.
- Ensures that every file in a runtime pack is a known file in the manifest.

Cons of templating:

- Each file has to be declared with an MSBuild item.
- File and assembly fallback versions need to be declared for files that do not exist in the targeting pack.
- Any change in the list of files requires a new MSBuild item declaring the entry.

### Platform Manifest Harvesting

For platforms where all target platforms have the same files or where one platform has a superset of the files available on all platforms, we can generate a platform manifest from the present files in the runtime pack.

This is enabled by default or when `UseTemplatedPlatformManifest` is not set to `true`.

Set the `RuntimePackProjectPath` to the path to the runtime pack shared framework project.

If you only want to use one RID to generate the platform manifest, you can set the `RuntimePackPlatformForManifest` property to the RID you'd like to use. If the chosen RID doesn't have a superset of files for all shipping platforms, then you may have unexpected behavior when using the produced targeting pack.

### Templated Platform Manifest

For shared frameworks with differing sets of files on various platforms and with no single platform that contains all of the files, this SDK provides support for creating a platform manifest from a templated list of items.

Assumptions:

- All managed assemblies are either present in both the ref and runtime pack for the shared framework
    or have an easily calculatable assembly version and file version.
- All native files have an easily calculatable file version.

To use, set `UseTemplatedPlatformManifest` to true and define a set of `PlatformManifestFileEntry` items

`PlatformManifestFileEntry` metadata:

- `ItemSpec`/`Identity`
  - File name and extension of file in the shared framework.
- `IsNative`
  - true when the file is a native file
- `FallbackAssemblyVersion`
  - An assembly version for this file if it is not present in the ref-pack build.
- `FallbackFileVersion`
  - A file version for this file if it is not present in the ref-pack build.

Properties for these targets:

- `UseTemplatedPlatformManifest`: Set to true to enable the templated platform manifest generation
- `PlatformManifestFallbackAssemblyVersion`: Fallback asssembly version when one is needed and there is no fallback on the entry.
- `PlatformManifestFallbackFileVersion`: Fallback file version when one is needed and there is no fallback on the entry.

### RuntimeList/FrameworkList Generation

The FrameworkList/RuntimeList support in this SDK has some additions on the base design to support profile and single-file features.

If your shared framework has various profiles, you can use `<FrameworkListFileClass>` items to specify the profiles for each file in the shared framework. However, once you've specified one `FrameworkListFileClass` entry, you need to specify one for every file in the framework.

If your shared framework can drop some files from the single-file bundle, you can specify `<SingleFileHostIncludeFilename>` items that specify which files by name are **included** in the single file bundle. Once one `SingleFileHostIncludeFilename` item is specified, all files without corresponding `SingleFileHostIncludeFilename` elements will be marked as droppable from a single file build.

The name of the framework/runtime is specified in the `SharedFrameworkFriendlyName` property, which defaults to the value of `SharedFrameworkName`.

### Archives

By default, this SDK also generates an archive that can be extracted on top of an existing .NET SDK or Runtime layout. The name of this file is derived from the `SharedFrameworkArchiveName` property and the RID. By default, `SharedFrameworkArchiveName` is set to the value of `SharedFrameworkName`.

### Custom dumping to disk

This SDK provides a custom target named `PublishToDisk` that publishes the generated framework pack to disk as though the folder specified via the `OutputPath` is the root of a .NET SDK or Runtime layout. This target is provided for compatibilty with the `Microsoft.DotNet.Build.Tasks.Installers` and `Microsoft.DotNet.Build.Tasks.Archives` packages, but can also be used to implement custom dumping to disk to set up test harnesses with the shared framework. 

## Build Skip Support for Unsupported Platforms and Servicing

This SDK also supports automatically skipping builds on unsupported platforms or in servicing releases. If a project with a list of provided RIDs in `RuntimeIdentifiers` is built with the `RuntimeIdentifier` property set to a RID that is not in the `RuntimeIdentifiers` list, the build will be skipped. This enables cleanly skipping optional packs, installers, or bundles that only exist on specific platforms. 

Additionally, if a `ProjectServicingConfiguration` item is provided with the identity of the project name and the `PatchVersion` metadata on the item is not equal to the current `PatchVersion`, the build will be skipped. This support enables a repository to disable building targeting packs in servicing releases if that is desired.
