Buildalyzer
Buildalyzer copied to clipboard
`PublishSingleFile` breaks `IProjectAnalyzer.Build()`
If I publish a .NET 6 app with PublishSingleFile
enabled (PublishReadyToRun
and PublishTrimmed
don't seem to be related to the issue), it hangs as soon as I call Build()
.
For example, make a fresh class library (its code doesn't matter), and a console app with the following Program.cs
:
using Buildalyzer;
var manager = new AnalyzerManager();
var analyzer = manager.GetProject(@"path\to\ClassLibrary1\ClassLibrary1.csproj");
Console.WriteLine("1");
_ = analyzer.Build();
Console.WriteLine("2");
If you build and run it, you get both console outputs within a few seconds.
But if you then create a publish profile with PublishSingleFile
enabled, e.g.:
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>publish\</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<_TargetId>Folder</_TargetId>
<TargetFramework>net6.0</TargetFramework>
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
<SelfContained>true</SelfContained>
<PublishSingleFile>true</PublishSingleFile>
</PropertyGroup>
</Project>
and run that, it seems to hang after the first output.
My first hunch was that code trimming removed something crucial, but that seems to be inactive.
I tried to profile it, and it looks like some kind of deadlock?

Hi @chucker , I'll look into it and get back to you.
Hi 😉 Any update on this topic? We also faced this issue.
If @phmonte does not have time today (nor tomorrow), I'll give it a go.
Hello @Karql and @chucker
I tried to simulate the problem, but all attempts worked without errors.
I created a unit test to simulate the problem and a project in my personal git, could you assess whether the configuration is correct?
What version of Buildalyzer are you using?
@phmonte
The problem occurs when you publish code that uses Buildalyzer
in PublishSingleFile=true
mode.
Not when you analyze a project with a such profile 😉
I don't know how to simulate it in unit tests but your sample project is good for replicate this behavior.
I have change one line
from: var analyzer = manager.GetProject(@"../../../../ClassLibrary1/ClassLibrary1.csproj");
to: var analyzer = manager.GetProject(@"../ClassLibrary1/ClassLibrary1.csproj");
and start console in ConsoleApp1
folder.
As you can see for normal build everything works as expected
but when published as single file: dotnet publish -p PublishSingleFile=true ConsoleApp1.csproj
and runs bin/Debug/net6.0/win-x64/publish/ConsoleApp1.exe
its hangs (i have cancelled it after half minute).
It hangs somewhere in AnonymousPipeLoggerServer
starting from this line: https://github.com/phmonte/Buildalyzer/blob/main/src/Buildalyzer/ProjectAnalyzer.cs#L182
Best regards, Mateusz
@Karql thanks, now it's possible to reproduce, I'm investigating.
I believe I found the problem, it's here. It uses the dll address to send to msbuild, I'm testing some alternatives.
Nice catch 👌
https://learn.microsoft.com/en-us/dotnet/core/deploying/single-file/overview?tabs=cli#api-incompatibility
This could be a problem... As I understand correctly, that dll needs to exists on the disk in order to pass its path to msbuild
.
For a moment, I wondered if it might be possible to get extract path from DOTNET_BUNDLE_EXTRACT_BASE_DIR
https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-environment-variables#dotnet_bundle_extract_base_dir
but from .NET5.0
only native dlls are extracted: https://github.com/dotnet/runtime/issues/43010
I hope you will find some alternatives 😉
Two ideas:
- Exclude logger dll from single file.
- Add possibility to specify path to logger similar like
MSBUILD_EXE_PATH
The msbuild result is captured through the log, there is a custom log that does all this work, removing it will be a bit complex, I'm thinking about other alternatives keeping the dll.
Hi @Karql , I did some tests in the last few days, from extracting a dll to manipulating the assembly, unfortunately I was not successful. I believe the healthiest solution would be to remove the Buildalyzer.Logger package from the publish single file. There are some alternatives in this issue.
If you are really going to remove the dll from the publish single file and you are unsuccessful with the alternatives, let us know and we can think of an alternative (search in the current directory or by parameter).
@phmonte
I have seen the issue you mentioned 😉 Did you manage to use this solution?
For me after use it its still hangs.
ConsoleApp1.Program.cs:
using Buildalyzer;
using Buildalyzer.Logger;
string loggerPath = typeof(BuildalyzerLogger).Assembly.Location;
Console.WriteLine($"Logger path: {loggerPath}");
var manager = new AnalyzerManager();
var analyzer = manager.GetProject(@"../ClassLibrary1/ClassLibrary1.csproj");
Console.WriteLine("1");
_ = analyzer.Build();
Console.WriteLine("2");
ConsoleApp1.csproj
...
<Target Name="ExplicitRemoveFromFilesToBundle" BeforeTargets="GenerateSingleFileBundle" DependsOnTargets="PrepareForBundle">
<ItemGroup>
<FilesToRemoveFromBundle Include="@(FilesToBundle)" Condition="$([System.String]::new('%(Filename)').ToLower().Contains('buildalyzer.logger'))" />
</ItemGroup>
<Message Text="FilesToRemoveFromBundle '@(FilesToRemoveFromBundle)'" Importance="high" />
<ItemGroup>
<FilesToBundle Remove="@(FilesToRemoveFromBundle)" />
</ItemGroup>
</Target>
<Target Name="CopyFilesToRemoveFromBundle" AfterTargets="Publish">
<Copy SourceFiles="@(FilesToRemoveFromBundle)" DestinationFolder="$(PublishDir)" />
<Message Text="Copied files to remove from bundle to '$(PublishDir)'" Importance="high" />
</Target>
...
but there is a small improvement - the path to the logger is good 😉
Screen from dump looks similar:
@Karql I ended up forgetting to mention it.
There are 2 dlls, could you test by removing them? -MsBuildPipeLogger.Logger.dll -Buildalyzer.logger.dll
I really believe it will solve your problem.
@phmonte
I can confirm that after excluding those two dlls application works as expected 😉
I wonder if adding some fallbacks would be a nice addition (somthing like searching msbuild
here: https://github.com/dotnet/msbuild/blob/main/src/Shared/BuildEnvironmentHelper.cs#L77).
I have three in my mind:
- Env like
BUILDALYZER_LOGGER_DLL_PATH
- Searching next to application
- Searching next to
msbuild
Thanks for confirming, I believe it's not the best solution, but it's the only one that enables PublishSingleFile due to current restrictions.
I will make some of your suggestions.
btw. I really appreciate your help 😉
Have a great day!
@Karql an environment variable was added for publish single file cases in version 7.0.2. Environment variable name: LoggerPathDll
I'll close the issue, any problems open a new one.
@phmonte 👌