Skip to content

Commit

Permalink
Fix incorrect app host used in build when PublishSingleFile=true
Browse files Browse the repository at this point in the history
  • Loading branch information
elinor-fung committed Nov 23, 2023
1 parent eefaab2 commit 20d5788
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Copyright (c) .NET Foundation. All rights reserved.
</ItemDefinitionGroup>

<Target Name="_ComputeToolPackInputsToProcessFrameworkReferences" BeforeTargets="ProcessFrameworkReferences">
<!-- Keep this in sync with the warnings produced for RequiresILLinkPack in ProcessFrameworkReferences.cs.
<!-- Keep this in sync with the warnings produced for RequiresILLinkPack in ProcessFrameworkReferences.cs.
Must be set late enough to see the inferred value of EnableSingleFileAnalyzer. -->
<PropertyGroup>
<_RequiresILLinkPack Condition="'$(_RequiresILLinkPack)' == '' And (
Expand Down Expand Up @@ -101,7 +101,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<!-- Don't warn if the library multitargets and includes TFM that's supported by trimming/AOT and is supported by the min non-EOL TFM that supports trimming/AOT. -->
<_SilenceIsTrimmableUnsupportedWarning Condition="'$(_SilenceIsTrimmableUnsupportedWarning)' == '' And
@(_TargetFrameworkToSilenceIsTrimmableUnsupportedWarning->Count()) > 0">true</_SilenceIsTrimmableUnsupportedWarning>
<_SilenceIsAotCompatibleUnsupportedWarning Condition="'$(_SilenceIsAotCompatibleUnsupportedWarning)' == '' And
<_SilenceIsAotCompatibleUnsupportedWarning Condition="'$(_SilenceIsAotCompatibleUnsupportedWarning)' == '' And
@(_TargetFrameworkToSilenceIsAotCompatibleUnsupportedWarning->Count()) > 0">true</_SilenceIsAotCompatibleUnsupportedWarning>
<_SilenceEnableSingleFileAnalyzerUnsupportedWarning Condition="'$(_SilenceEnableSingleFileAnalyzerUnsupportedWarning)' == '' And
@(_TargetFrameworkToSilenceEnableSingleFileAnalyzerUnsupportedWarning->Count()) > 0">true</_SilenceEnableSingleFileAnalyzerUnsupportedWarning>
Expand Down Expand Up @@ -694,6 +694,40 @@ Copyright (c) .NET Foundation. All rights reserved.
</ItemGroup>
</Target>

<!--
============================================================
_CreateSingleFileHost
Create the single-file host for the publish scenario if app is being published as a self-contained single-file .net5+ app
============================================================
-->
<UsingTask TaskName="CreateAppHost" AssemblyFile="$(MicrosoftNETBuildTasksAssembly)" />
<Target Name="_CreateSingleFileHost"
Inputs="@(IntermediateAssembly);$(SingleFileHostSourcePath)"
Outputs="$(SingleFileHostIntermediatePath)"
DependsOnTargets="_GetAppHostPaths"
Condition="'$(PublishSingleFile)' == 'true' and
'$(SelfContained)' == 'true' and
'$(SingleFileHostSourcePath)' != '' and
'$(_TargetFrameworkVersionWithoutV)' >= '5.0' and
Exists('@(IntermediateAssembly)') and
Exists('$(SingleFileHostSourcePath)')">
<PropertyGroup>
<_UseWindowsGraphicalUserInterface Condition="($(RuntimeIdentifier.StartsWith('win')) or $(DefaultAppHostRuntimeIdentifier.StartsWith('win'))) and '$(OutputType)'=='WinExe'">true</_UseWindowsGraphicalUserInterface>
<_EnableMacOSCodeSign Condition="'$(_EnableMacOSCodeSign)' == '' and $([MSBuild]::IsOSPlatform(`OSX`)) and Exists('/usr/bin/codesign') and
($(RuntimeIdentifier.StartsWith('osx')) or $(AppHostRuntimeIdentifier.StartsWith('osx')))">true</_EnableMacOSCodeSign>
</PropertyGroup>

<CreateAppHost AppHostSourcePath="$(SingleFileHostSourcePath)"
AppHostDestinationPath="$(SingleFileHostIntermediatePath)"
AppBinaryName="$(AssemblyName)$(TargetExt)"
IntermediateAssembly="@(IntermediateAssembly->'%(FullPath)')"
WindowsGraphicalUserInterface="$(_UseWindowsGraphicalUserInterface)"
Retries="$(CopyRetryCount)"
RetryDelayMilliseconds="$(CopyRetryDelayMilliseconds)"
EnableMacOSCodeSign="$(_EnableMacOSCodeSign)"
/>
</Target>

<!--
============================================================
_ComputeCopyToPublishDirectoryItems
Expand Down Expand Up @@ -736,6 +770,7 @@ Copyright (c) .NET Foundation. All rights reserved.
KeepDuplicateOutputs=" '$(MSBuildDisableGetCopyToPublishDirectoryItemsOptimization)' == '' "
DependsOnTargets="AssignTargetPaths;
DefaultCopyToPublishDirectoryMetadata;
_CreateSingleFileHost;
_SplitProjectReferencesByFileExistence;
_GetProjectReferenceTargetFrameworkProperties">

Expand Down Expand Up @@ -826,6 +861,15 @@ Copyright (c) .NET Foundation. All rights reserved.
Condition="'%(_NoneWithTargetPath.CopyToPublishDirectory)'=='PreserveNewest'"/>
</ItemGroup>

<ItemGroup Condition="'$(PublishSingleFile)' == 'true' and '$(SelfContained)' == 'true' and '$(_TargetFrameworkVersionWithoutV)' >= '5.0'">
<!-- Remove non-single-file apphost from items to publish -->
<_SourceItemsToCopyToPublishDirectoryAlways Remove="$(AppHostIntermediatePath)" />
<_SourceItemsToCopyToPublishDirectory Remove="$(AppHostIntermediatePath)" />

<!-- Add the single-file host created as part of publish -->
<_SourceItemsToCopyToPublishDirectoryAlways Include="$(SingleFileHostIntermediatePath)" CopyToOutputDirectory="Always" TargetPath="$(AssemblyName)$(_NativeExecutableExtension)" />
</ItemGroup>

<ItemGroup>
<AllPublishItemsFullPathWithTargetPath Include="@(_SourceItemsToCopyToPublishDirectoryAlways->'%(FullPath)');@(_SourceItemsToCopyToPublishDirectory->'%(FullPath)')"/>
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -700,7 +700,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<Target Name="_CreateAppHost"
Inputs="@(IntermediateAssembly);$(AppHostSourcePath)"
Outputs="$(AppHostIntermediatePath)"
DependsOnTargets="_ChooseAppHost;CoreCompile"
DependsOnTargets="_GetAppHostPaths;CoreCompile"
Condition="'$(ComputeNETCoreBuildOutputFiles)' == 'true' and
'$(AppHostSourcePath)' != '' and
Exists('@(IntermediateAssembly)') and
Expand All @@ -722,26 +722,6 @@ Copyright (c) .NET Foundation. All rights reserved.
/>
</Target>

<!--
============================================================
_ChooseAppHost
Choose the correct app-host for the build scenario:
* SingleFileHost if an app being published as a self-contained single-file .net5+ app
* AppHost otherwise
============================================================
-->
<Target Name="_ChooseAppHost"
DependsOnTargets="_GetAppHostPaths"
Condition="'$(UseAppHost)' == 'true' and '$(_IsExecutable)' == 'true'">
<PropertyGroup Condition="'$(PublishSingleFile)' == 'true' and
'$(SelfContained)' == 'true' and
'$(_TargetFrameworkVersionWithoutV)' >= '5.0' and
'$(SingleFileHostSourcePath)' != ''">
<AppHostSourcePath>$(SingleFileHostSourcePath)</AppHostSourcePath>
<AppHostIntermediatePath>$([System.IO.Path]::GetFullPath('$(IntermediateOutputPath)singlefilehost$(_NativeExecutableExtension)'))</AppHostIntermediatePath>
</PropertyGroup>
</Target>

<!--
============================================================
_GetAppHostPaths
Expand All @@ -763,6 +743,7 @@ Copyright (c) .NET Foundation. All rights reserved.
</PropertyGroup>
<PropertyGroup Condition="'$(UseAppHostFromAssetsFile)' == 'false' Or '@(_NativeRestoredAppHostNETCore)' != ''">
<AppHostIntermediatePath>$([System.IO.Path]::GetFullPath('$(IntermediateOutputPath)apphost$(_NativeExecutableExtension)'))</AppHostIntermediatePath>
<SingleFileHostIntermediatePath>$([System.IO.Path]::GetFullPath('$(IntermediateOutputPath)singlefilehost$(_NativeExecutableExtension)'))</SingleFileHostIntermediatePath>
</PropertyGroup>

</Target>
Expand Down Expand Up @@ -878,12 +859,12 @@ Copyright (c) .NET Foundation. All rights reserved.
============================================================
-->
<Target Name="_ComputeNETCoreBuildOutputFiles"
DependsOnTargets="_ChooseAppHost;_GetComHostPaths;_GetIjwHostPaths"
DependsOnTargets="_GetAppHostPaths;_GetComHostPaths;_GetIjwHostPaths"
BeforeTargets="AssignTargetPaths"
Condition="'$(ComputeNETCoreBuildOutputFiles)' == 'true'">

<!-- Fallback to renaming the dotnet host if there is no apphost for self-contained builds. -->
<PropertyGroup Condition="'$(AppHostIntermediatePath)' == '' and '$(SelfContained)' == 'true'">
<PropertyGroup Condition="'$(AppHostIntermediatePath)' == '' and '$(SelfContained)' == 'true' and '$(_TargetFrameworkVersionWithoutV)' < '2.0'">
<_CopyAndRenameDotnetHost Condition="'$(_CopyAndRenameDotnetHost)' == ''">true</_CopyAndRenameDotnetHost>
</PropertyGroup>
<ItemGroup Condition="'$(_CopyAndRenameDotnetHost)' == 'true'">
Expand All @@ -895,8 +876,7 @@ Copyright (c) .NET Foundation. All rights reserved.
</None>
</ItemGroup>


<ItemGroup Condition="'$(AppHostIntermediatePath)' != '' or '$(_CopyAndRenameDotnetHost)' == 'true'">
<ItemGroup Condition="'$(AppHostIntermediatePath)' != ''">
<!--
If not copying local lock file assemblies, copy the host policy and host fxr libraries for self-contained builds.
This is required to allow the host to activate in self-contained mode.
Expand All @@ -909,8 +889,6 @@ Copyright (c) .NET Foundation. All rights reserved.
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
<ItemGroup Condition="'$(AppHostIntermediatePath)' != ''">
<None Include="$(AppHostIntermediatePath)">
<Link>$(AssemblyName)$(_NativeExecutableExtension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,55 @@ public void It_does_not_build_SelfContained_due_to_PublishSelfContained_being_tr
.Pass();

var outputDirectory = buildCommand.GetOutputDirectory(targetFramework);
outputDirectory.Should().NotHaveFile("hostfxr.dll"); // This file will only appear if SelfContained.
outputDirectory.Should().NotHaveFile($"hostfxr{FileNameSuffixes.CurrentPlatform.DynamicLib}"); // This file will only appear if SelfContained.
}

[Fact]
public void It_builds_using_regular_apphost_with_PublishSingleFile()
{
var tfm = ToolsetInfo.CurrentTargetFramework;
var project = new TestProject()
{
IsExe = true,
TargetFrameworks = tfm,
AdditionalProperties = {
{ "PublishSingleFile", "true"},
{ "SelfContained", "true" } }
};
var asset = _testAssetsManager.CreateTestProject(project);

// Validate apphost is used, not singlefilehost
var command = new GetValuesCommand(Log,
Path.Combine(asset.Path, project.Name),
project.TargetFrameworks,
"AllItemsFullPathWithTargetPath",
GetValuesCommand.ValueType.Item);
command.DependsOnTargets = "GetCopyToOutputDirectoryItems";
command.MetadataNames.Add("TargetPath");
command.Execute().Should().Pass();

var itemsWithTargetPaths = command.GetValuesWithMetadata();
itemsWithTargetPaths.Should().NotContain((i) => i.value.EndsWith($"singlefilehost{Constants.ExeSuffix}"));
itemsWithTargetPaths.Should().Contain((i) =>
i.value.EndsWith($"apphost{Constants.ExeSuffix}")
&& i.metadata["TargetPath"] == $"{project.Name}{Constants.ExeSuffix}");

// Validate it builds and runs
var buildCommand = new BuildCommand(asset);
buildCommand
.Execute()
.Should()
.Pass();

string exePath = Path.Combine(
buildCommand.GetOutputDirectory(tfm, runtimeIdentifier: EnvironmentInfo.GetCompatibleRid(tfm)).FullName,
$"{project.Name}{Constants.ExeSuffix}");
new RunExeCommand(Log, exePath)
.Execute()
.Should()
.Pass()
.And
.HaveStdOutContaining("Hello World!");
}

[Theory]
Expand Down

0 comments on commit 20d5788

Please sign in to comment.