Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PublishSingleFile breaks IProjectAnalyzer.Build() #224

Closed
chucker opened this issue Jan 24, 2023 · 17 comments
Closed

PublishSingleFile breaks IProjectAnalyzer.Build() #224

chucker opened this issue Jan 24, 2023 · 17 comments
Labels
⚠ Bug Something isn't working as expected

Comments

@chucker
Copy link

chucker commented Jan 24, 2023

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?

image

@phmonte phmonte added the ⚠ Bug Something isn't working as expected label Feb 18, 2024
@phmonte
Copy link
Owner

phmonte commented Feb 18, 2024

Hi @chucker , I'll look into it and get back to you.

@Karql
Copy link

Karql commented Apr 12, 2024

Hi 😉
Any update on this topic?
We also faced this issue.

@Corniel
Copy link
Contributor

Corniel commented Apr 12, 2024

If @phmonte does not have time today (nor tomorrow), I'll give it a go.

@phmonte
Copy link
Owner

phmonte commented Apr 13, 2024

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?

@Karql
Copy link

Karql commented Apr 13, 2024

@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.

image

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

@phmonte
Copy link
Owner

phmonte commented Apr 13, 2024

@Karql thanks, now it's possible to reproduce, I'm investigating.

@phmonte
Copy link
Owner

phmonte commented Apr 15, 2024

I believe I found the problem, it's here.
It uses the dll address to send to msbuild, I'm testing some alternatives.

@Karql
Copy link

Karql commented Apr 15, 2024

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: dotnet/runtime#43010

I hope you will find some alternatives 😉

Two ideas:

  1. Exclude logger dll from single file.
  2. Add possibility to specify path to logger similar like MSBUILD_EXE_PATH

@phmonte
Copy link
Owner

phmonte commented Apr 15, 2024

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.

@phmonte
Copy link
Owner

phmonte commented Apr 17, 2024

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).

@Karql
Copy link

Karql commented Apr 18, 2024

@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>
...

image

but there is a small improvement - the path to the logger is good 😉

Screen from dump looks similar:
image

@phmonte
Copy link
Owner

phmonte commented Apr 19, 2024

@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.

@Karql
Copy link

Karql commented Apr 22, 2024

@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

@phmonte
Copy link
Owner

phmonte commented Apr 23, 2024

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.

@Karql
Copy link

Karql commented Apr 23, 2024

btw. I really appreciate your help 😉

Have a great day!

@phmonte
Copy link
Owner

phmonte commented Jun 18, 2024

@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 phmonte closed this as completed Jun 18, 2024
@Karql
Copy link

Karql commented Jun 18, 2024

@phmonte 👌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
⚠ Bug Something isn't working as expected
Projects
None yet
Development

No branches or pull requests

4 participants