Sdk: "Dotnet build" command should generate an error directing you to use "dotnet msbuild" if you try to specify a target to run (/t:TargetName)

Created on 22 Nov 2016  路  15Comments  路  Source: dotnet/sdk

Once you get used to using dotnet build to build your MSBuild projects, and you learn that you can pass MSBuild command-line parameters, it's natural to try something like this:

dotnet build MyProj.csproj /t:MyCustomTarget

That's what I did and then I spent like an hour banging my head against the wall trying to figure out why it was trying to build the "Build" target when "MyCustomTarget" didn't have any dependencies on it. The CLI was passing both /t:Build and /t:MyCustomTarget to MSBuild.

Now I know that I should use dotnet msbuild instead of dotnet build for this. But why the difference? I think it will be pretty common for people who want to run custom targets to not know there is a separate msbuild command, and to run into this same issue.

I would propose that the dotnet build command should do what the dotnet msbuild command does today, which is to specify no specific targets. Then the default target will be built, which will be "Build" on normal projects. Then there won't be any need for a separate dotnet msbuild command.

All 15 comments

I think this was in case the project had no DefaultTargets but won't MSBuild choose 'Build' anyway?

At the very least, if the /t:Build could only be added if the user did not specify a target to build.

I can make this change if approved.

Microsoft.Common.CurrentVersion.targets [has DefaultTargets="Build'](https://github.com/Microsoft/msbuild/blob/fbba93c46c3603d4eef64cbfe5aaf86a8e6b2e88/src/XMakeTasks/Microsoft.Common.CurrentVersion.targets#L17), so I think the only way you wouldn't get the Build target as the default would be if you didn't import the standard targets, or if you overrode it yourself. In both of those cases I think it's fine fordotnet build` to not explicitly specify a target.

Only adding /t:Build if you didn't pass in your own /t argument is also OK, but could still result in unexpected behavior if you did define your own default targets and expected dotnet build to behave the same way as msbuild.

@dsplaisted aren't you asking for dotnet build to become dotnet msbuild?

@piotrpMSFT Yes, basically. I think dotnet build should do what dotnet msbuild does today, and then there's probably not a need for a separate dotnet msbuild command.

The intent of dotnet build is to call dotnet msbuild /t:build. I don't think it's a fair assumption that the default target for a proj file is the build target...

@blackdwarf let's close on this...

@dsplaisted @piotrpMSFT as discussed, the solution to this is to keep the commands separate because of added value that CLI commands bring on top of MSBuild. However, to avoid this situation we should have an error that will be shown to users if they pass in a /t:<target> or /target:<target> to point them to use dotnet msbuild, which is the right path for these scenarios.

I've updated the bug title based on our discussion.

thanks!

Personally, I find it pretty odd that running dotnet build on my project doesn't run the default targets that I've specified. Additionally, the difference between dotnet build and dotnet msbuild seems artificial to me, and not very helpful. I feel like having dotnet build be an alias for dotnet msbuild /t:build is only going to help people make mistakes, not avoid them. If a project specifies non-standard default targets, then why would I want dotnet build to run a potentially nonexistant "Build" target? Just trying to understand, maybe there's something I'm missing.

Related: CoreRT asks you to run dotnet build /t:LinkNative so that their additional target runs after build.
Seems legit now but since a decision on how build should work will require target authors to follow, it should be decided soon to avoid breaking changes that require documentation or target changes.

I't settle for some documentation explaining this in the help commands.
It was rather confusing not being able to run alternative targets.

I actually prefer the breaking change approach that dotnet build becomes dotnet msbuild. Running dotnet msbuild /t:Build explicitly I believe is adding very little and as a matter of fact, taking away in the default targets case.

I actually prefer the breaking change approach that dotnet build becomes dotnet msbuild

I think I would have agreed with you before we did implicit restore, but now dotnet build does an implicit restore and dotnet msbuild and msbuild don't. So if dotnet build became dotnet msbuild, I guess we should also add a --norestore parameter, without which we would implicitly pass -restore.

+1 for the subtle usage of dash-style msbuild arguments, @dsplaisted 馃槀

I guess we should also add a --norestore parameter, without which we would implicitly pass -restore

that is the current behaviour.

I'm also for removing the -t:Build default case.
--no-incremental currently changes it to -t:Rebuild, which is okay-ish. though I wish it would have been named --rebuild from the beginning to match what VS has called it for countless years. Maybe it could be renamed with --no-incremental remaining as an alias for compatibility?

The only time dotnet build doesn't pass -restore is when the user passes in /p:TargetFramework= (yes, literal string with slash, no logical property matching. -p:TargetFramework= or /p:Foo=Bar;TargetFaramework= or even an ENV var won't be caught). This doesn't seem to be necessary as it was introduced to avoid overriding NuGet restore parameters, but NuGet can actually cope with both plural TargetFrameworks and TargetFramework being defined (resulting in https://github.com/dotnet/cli/issues/7563 as a side effect).
Is there any need for keeping this behaviour? It would only be needed to prevent passing in different TFMs at build time than are defined in the project for single-targeting. MSBuild 15.7 introduced a special restore parameters argument. If this behaviour should be kept, I'd propose to implement a similar "filter out from restore parameters" parameter (and I believe I could even implement this).

Was this page helpful?
0 / 5 - 0 ratings