dotnet cli passing -target:Restore to MSBuild instead of -restore
jonathanpeppers opened this issue · 15 comments
As seen in: dotnet/maui-samples#52
We have a multi-targeted project with:
<TargetFrameworks>net6.0-android;net6.0-ios</TargetFrameworks>
To deploy to an Android device/emulator (and not iOS), you can run:
> dotnet build -t:Run -p:TargetFramework=net6.0-android
With .NET 6.0.100-alpha.1.21064.27, this command fails with:
error MSB4057: The target "Run" does not exist in the project.
The MSBuild arguments the dotnet cli is passing seem odd:
-target:Restore -t:Run
With .NET 6.0.100-alpha.1.20562.2, it used to pass:
-restore -t:Run
In fact, you can workaround the problem by doing:
> dotnet build -t:Run -p:TargetFramework=net6.0-android --no-restore
I tried creating other, simpler projects to reproduce this issue, but a console app with TargetFrameworks=net5.0;net6.0
works fine. I always see -restore
being passed.
I think it is something to with .NET workloads and multi-targeting at the same time?
- Example broken log: broken.zip
- Example working log: works.zip
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.
@sfoslund Can you take a look?
@jonathanpeppers can you give some more information on how to repro this? The binlogs you provided are on two different platforms, does this only repro on windows or mac?
@sfoslund I think it happens on all platforms. My Mac has the older 6.0.100-alpha.1.20562.2 installed, so that is where I could grab the working .binlog
the easiest.
You can compare main
here:
https://github.com/xamarin/net6-samples
vs the branch on my PR:
There are installation instructions on the README.md
, but ping me on Teams if I can help further, thanks!
Okay I think I understand this issue now but I want to verify my understanding of the history with @dsplaisted.
The basic issue is with RestoringCommand, which has logic to decide if we can restore with -restore
included in the msbuild arguments or if we need to use a separate command to restore. The deciding factor is if the target framework is specified on the command line (by either -f
, --framework
, or -p:TargetFramework=...
). If it is, then we can't use -restore
, for the reasons explained in this comment.
It looks like before the System.CommandLine change there was a bug and we were using -restore
when the target framework was specified on the command line (see the command line args in your working binlog: -restore -consoleloggerparameters:Summary HelloForms -p:TargetFramework=net6.0-android...
). This was working because there weren't any dependent projects with different target frameworks, but if there had been then the command line target framework would have overridden the dependency projects' tfm's and restore would have failed.
So theoretically I think switching to system.commandline "fixed" this bug in that now we try to use a separate restore command when the target framework is specified on the command line. However, this has created a bug here such that we pass the -t:run
option to the separate restore command and it fails because we didn't specify a target framework.
@dsplaisted does this make sense to you? Do you know of any changes in the -restore
behavior in regards to target frameworks since Nick's comment (which is from 2017).
After discussing with @dsplaisted, we do want the -target:restore
behavior instead of -restore
when the target framework is specified on the command line.
@jonathanpeppers is there a reason you need to specify the run target while building? dotnet run -f net6.0-android
should be logically the same as it includes an implicit restore/build.
I still get this error with dotnet run
:
> cd HelloForms
> dotnet run -f net6.0-android
Microsoft (R) Build Engine version 16.9.0-preview-21063-04+27981f15c for .NET
Copyright (C) Microsoft Corporation. All rights reserved.
Determining projects to restore...
All projects are up-to-date for restore.
C:\src\net6-samples\HelloForms\HelloForms.csproj : error MSB4057: The target "Run" does not exist in the project.
I also tried adding --no-restore
to the dotnet run
command, but I'm not sure if that actually does anything.
These commands both work for me:
> dotnet build -t:Run -f net6.0-android --no-restore
> dotnet build -t:Run -p:TargetFramework=net6.0-android --no-restore
Yes, I'm seeing that error with 6.0.100-alpha.1.20562.2 (the version you're currently using which doesn't have the system.commandLine change). It's odd because in the binlog I can see the run target from Microsoft.NET.Sdk.targets is being imported and overriding the MSBuild target. I'm not able to repro this issue with simpler projects, do you have any custom logic for running?
I just updated to 6.0.100-preview.1.21081.5
and seeing the same thing there, too.
One thing, is we completely replace the Run
target with our own:
We also set $(RunCommand)
and $(RunArguments)
:
Maybe we need to specify the arguments here in a better way?
If I comment out where we set $(RunCommand)
and $(RunArguments)
, it tries to run the app locally, which is not what we want:
> dotnet run -f net6.0-android
System.ComponentModel.Win32Exception (2): The system cannot find the file specified.
at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start()
at Microsoft.DotNet.Cli.Utils.Command.Execute(Action`1 processStarted)
at Microsoft.DotNet.Cli.Utils.Command.Execute()
at Microsoft.DotNet.Tools.Run.RunCommand.Execute()
at Microsoft.DotNet.Tools.Run.RunCommand.Run(String[] args)
at Microsoft.DotNet.Cli.Program.ProcessArgs(String[] args, ITelemetry telemetryClient)
at Microsoft.DotNet.Cli.Program.Main(String[] args)
Huh, it seems like something with the MSBuild logic then. In the binlog I'm seeing that file imported and
Huh, it seems like something with the MSBuild logic then. In the binlog I'm seeing that file imported and
$(RunCommand) and $ (RunArguments) being reset but the run target is not being overridden, possibly because Microsoft.NET.Sdk.targets is being imported after your custom file, so the run target there overwrites yours. I would dig into the binlog and ensure that the logic is behaving as you expect.
Ah, it sounds like the reordering of the workload targets (from #14393) impacted this then.
Targets that need to override targets from the .NET SDK should be refactored into a separate .targets file, which should be added to the AfterMicrosoftNETSdkTargets
property in order to have them imported in the correct location. For example, this is how it was being done for WindowsDesktop:
<PropertyGroup Condition=" '$(ImportWindowsDesktopTargets)' == 'true'">
<AfterMicrosoftNETSdkTargets>$(AfterMicrosoftNETSdkTargets);$(MSBuildThisFileDirectory)../../Microsoft.NET.Sdk.WindowsDesktop/targets/Microsoft.NET.Sdk.WindowsDesktop.targets</AfterMicrosoftNETSdkTargets>
</PropertyGroup>
@dsplaisted I think we're already using $(AfterMicrosoftNETSdkTargets)
for this .targets
file:
Looking at the logs, I think it is imported at the right time, it's nearly last:
So theoretically I think switching to system.commandline "fixed" this bug in that now we try to use a separate restore command when the target framework is specified on the command line. However, this has created a bug here such that we pass the
-t:run
option to the separate restore command and it fails because we didn't specify a target framework.
It seems like Sarah was correct here. Fixing one bug (It sounds like RestoringCommand
wasn't correctly detecting when it needed to run a separate restore command) exposed another bug. The new bug is that additional targets specified (such as Run
) get passed through to the restore command, when they should be filtered out and only passed to the actual command run after the restore.
@sfoslund Could you work on fixing this? I tried, but ran into issues where an argument such as -t:Run
got interpreted as the SlnOrProjectArgument
by the parser, and thus wasn't handled correctly by RestoringCommand
.
Here is the change I made, which added some test coverage and tried to fix RestoringCommand
: dsplaisted@ad79b3f
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.