/*---------------------------------------------------------------------------------------------
* Copyright (c) Unity Technologies.
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
using System;
using System.IO;
using System.Text;
using UnityEditor.Compilation;
using UnityEngine;
namespace Microsoft.Unity.VisualStudio.Editor
{
internal class SdkStyleProjectGeneration : ProjectGeneration
{
internal override string StyleName => "SDK";
internal class SdkStyleAssemblyNameProvider : AssemblyNameProvider
{
// disable PlayerGeneration with SdkStyle projects
internal override ProjectGenerationFlag ProjectGenerationFlagImpl => base.ProjectGenerationFlagImpl & ~ProjectGenerationFlag.PlayerAssemblies;
}
public SdkStyleProjectGeneration() : base(
Directory.GetParent(Application.dataPath)?.FullName,
new SdkStyleAssemblyNameProvider(),
new FileIOProvider(),
new GUIDProvider())
{
}
internal static readonly string[] SupportedCapabilities = new string[]
{
"Unity",
};
internal static readonly string[] UnsupportedCapabilities = new string[]
{
"LaunchProfiles",
"SharedProjectReferences",
"ReferenceManagerSharedProjects",
"ProjectReferences",
"ReferenceManagerProjects",
"COMReferences",
"ReferenceManagerCOM",
"AssemblyReferences",
"ReferenceManagerAssemblies",
};
internal override void GetProjectHeader(ProjectProperties properties, out StringBuilder headerBuilder)
{
headerBuilder = new StringBuilder();
headerBuilder.Append(@"").Append(k_WindowsNewline);
headerBuilder.Append(@" ").Append(k_WindowsNewline);
// Prevent circular dependency issues see https://github.com/microsoft/vscode-dotnettools/issues/401
// We need a dedicated subfolder for each project in obj, else depending on the build order, nuget cache files could be overwritten
// We need to do this before common.props, else we'll have a MSB3539 The value of the property "BaseIntermediateOutputPath" was modified after it was used by MSBuild
headerBuilder.Append(@" ").Append(k_WindowsNewline);
headerBuilder.Append($" {@"Temp\obj\$(Configuration)\$(MSBuildProjectName)".NormalizePathSeparators()}").Append(k_WindowsNewline);
headerBuilder.Append(@" $(BaseIntermediateOutputPath)").Append(k_WindowsNewline);
headerBuilder.Append(@" ").Append(k_WindowsNewline);
// Supported capabilities
GetCapabilityBlock(headerBuilder, "Sdk.props", "Include", SupportedCapabilities);
headerBuilder.Append(@" ").Append(k_WindowsNewline);
headerBuilder.Append(@" false").Append(k_WindowsNewline);
headerBuilder.Append(@" false").Append(k_WindowsNewline);
headerBuilder.Append(@" false").Append(k_WindowsNewline);
headerBuilder.Append(@" ").Append(properties.LangVersion).Append(@"").Append(k_WindowsNewline);
headerBuilder.Append(@" Debug;Release").Append(k_WindowsNewline);
headerBuilder.Append(@" Debug").Append(k_WindowsNewline);
headerBuilder.Append(@" AnyCPU").Append(k_WindowsNewline);
headerBuilder.Append(@" ").Append(properties.RootNamespace).Append(@"").Append(k_WindowsNewline);
headerBuilder.Append(@" Library").Append(k_WindowsNewline);
headerBuilder.Append(@" Properties").Append(k_WindowsNewline);
headerBuilder.Append(@" ").Append(properties.AssemblyName).Append(@"").Append(k_WindowsNewline);
// In the end, given we use NoConfig/NoStdLib (see below), hardcoding the target framework version will have no impact, even when targeting netstandard/net48 from Unity.
// But with SDK style we use netstandard2.1 (net471 for legacy), so 3rd party tools will not fail to work when .NETFW reference assemblies are not installed.
// Unity already selected proper API surface through referenced DLLs for us.
headerBuilder.Append(@" netstandard2.1").Append(k_WindowsNewline);
headerBuilder.Append(@" .").Append(k_WindowsNewline);
headerBuilder.Append(@" ").Append(k_WindowsNewline);
GetProjectHeaderConfigurations(properties, headerBuilder);
// Explicit references
headerBuilder.Append(@" ").Append(k_WindowsNewline);
headerBuilder.Append(@" true").Append(k_WindowsNewline);
headerBuilder.Append(@" true").Append(k_WindowsNewline);
headerBuilder.Append(@" true").Append(k_WindowsNewline);
headerBuilder.Append(@" true").Append(k_WindowsNewline);
headerBuilder.Append(@" MSB3277").Append(k_WindowsNewline);
headerBuilder.Append(@" ").Append(k_WindowsNewline);
GetProjectHeaderVstuFlavoring(properties, headerBuilder, false);
GetProjectHeaderAnalyzers(properties, headerBuilder);
}
internal override void AppendProjectReference(Assembly assembly, Assembly reference, StringBuilder projectBuilder)
{
// If the current assembly is a Player project, we want to project-reference the corresponding Player project
var referenceName = m_AssemblyNameProvider.GetAssemblyName(assembly.outputPath, reference.name);
projectBuilder.Append(@" ").Append(k_WindowsNewline);
}
internal override void GetProjectFooter(StringBuilder footerBuilder)
{
// Unsupported capabilities
GetCapabilityBlock(footerBuilder, "Sdk.targets", "Remove", UnsupportedCapabilities);
footerBuilder.Append("").Append(k_WindowsNewline);
}
internal static void GetCapabilityBlock(StringBuilder footerBuilder, string import, string attribute, string[] capabilities)
{
footerBuilder.Append($@" ").Append(k_WindowsNewline);
footerBuilder.Append(@" ").Append(k_WindowsNewline);
foreach (var capability in capabilities)
{
footerBuilder.Append($@" ").Append(k_WindowsNewline);
}
footerBuilder.Append(@" ").Append(k_WindowsNewline);
}
}
}