Events
Mar 17, 9 PM - Mar 21, 10 AM
Join the meetup series to build scalable AI solutions based on real-world use cases with fellow developers and experts.
Register nowThis browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
--output
option no longer valid for build-related commandsIn the 7.0.200 SDK, there was a change to no longer accept the --output
/-o
option when using a solution file with the following commands:
build
clean
pack
publish
store
test
vstest
This is because the semantics of the OutputPath
property, which is controlled by the --output
/-o
option, aren't well defined for solutions. Projects built in this way will have their output placed in the same directory, which is inconsistent and has led to a number of user-reported issues.
This change was reduced to a warning level of severity in the 7.0.201 SDK, and pack
was removed from the list of commands that are affected.
.NET 7.0.200 SDK, reduced to a warning only in the 7.0.201 SDK.
Previously, if you specified --output
/-o
when using a solution file, the output for all built projects would be placed in the specified directory in an undefined and inconsistent order.
The dotnet
CLI will error if the --output
/-o
option is used with a solution file. Starting in the 7.0.201 SDK, a warning will be emitted instead, and in the case of dotnet pack
no warning or error will be generated.
This breaking change may require modifications to build scripts and continuous integration pipelines. As a result it affects both binary and source compatibility.
This change was made because the semantics of the OutputPath
property, which is controlled by the --output
/-o
option, aren't well defined for solutions. Projects built in this way will have their output placed in the same directory, which is inconsistent and has led to a number of user-reported issues.
When a solution is built with the --output
option, the OutputPath
property is set to the same value for all projects, which means that all projects will have their output placed in the same directory. Depending on the complexity of the projects in the solution, different and inconsistent results may occur. Let's take a look at some examples of different solution shapes and how they are affected by a shared OutputPath
.
Imagine a solution that contains a single project targeting a single TargetFramework
, net7.0
. In this case, providing the --output
option is equivalent to setting the OutputPath
property in the project file. During a build (or other commands, but let's scope the discussion to build for now), all of the outputs for the project will be placed in the specified directory.
Now imagine a solution that contains a single project with multiple TargetFrameworks
, net6.0
and net7.0
. Because of multi-targeting, the project will be build twice, once for each TargetFramework
. For each of these 'inner' builds the OutputPath
will be set to the same value, and so the outputs for each of the inner builds will be placed in the same directory. This means that whichever build completes last will overwrite the outputs of the other build, and in a parallel-build system like MSBuild operates in by default, 'last' is indeterminate.
Now imagine a solution that contains a library project, a console project that references the library project, and a test project that references the console project. All of these projects target a single TargetFramework
, net7.0
. In this case, the library project will be built first, and then the console project will be built. The test project will be built last, and will reference the console project. For each built project, the outputs of each build will be copied into the directory specified by the OutputPath
, and so the final directory will contain assets from all three projects. This works for testing, but for publishing may result in test assets being sent to production.
Now take the same chain of projects and add a net6.0
TargetFramework
build to them in addition to the net7.0
build. The same problem as the single-project, multi-targeted build occurs - inconsistent copying of TFM-specific assets to the specified directory.
So far we have been looking at scenarios with a linear dependency graph - but many solutions may contain multiple related applications. This means that multiple apps may be built concurrently to the same output folder. If the apps include a dependency file with the same name, then the build may intermittently fail when multiple projects try to write to that file in the output path concurrently.
If multiple apps depend on different versions of a file, then even if the build succeeds, which version of the file is copied to the output path may be non-deterministic. This can happen when the projects depend (possibly transitively) on different versions of a NuGet package. Within a single project, NuGet helps ensure that its dependencies (including any transitive dependencies through NuGet packages and/or project references) are unified to the same version. Because the unification is done within the context of a single project and its dependent projects, this means it is possible to resolve different versions of a package when two separate top-level projects are built. If the project that depends on the higher version copies the dependency last, then often the apps will run successfully. However, if the lower version is copied last, then the app that was compiled against the higher version will fail to load the assembly at runtime. Because the version that is copied can be non-deterministic, this can lead to sporadic, unreliable builds where it is very difficult to diagnose the issue.
For more examples of how this underlying error presents in practice, see the discussion on dotnet/sdk#15607.
The general recommendation is to perform the action that you previously took without the --output
/-o
option, and then move the output to the desired location after the command has completed. It's also possible to perform the action at a specific project and still apply the --output
/-o
option, as that has more well-defined semantics.
If you want to maintain the existing behavior exactly, then you can use the --property
flag to set a MSBuild property to the desired directory. The property to use varies based on the command:
Command | Property | Example |
---|---|---|
build |
OutputPath |
dotnet build --property:OutputPath=DESIRED_PATH |
clean |
OutputPath |
dotnet clean --property:OutputPath=DESIRED_PATH |
pack |
PackageOutputPath |
dotnet pack --property:PackageOutputPath=DESIRED_PATH |
publish |
PublishDir |
dotnet publish --property:PublishDir=DESIRED_PATH |
store |
OutputPath |
dotnet store --property:OutputPath=DESIRED_PATH |
test |
TestResultsDirectory |
dotnet test --property:OutputPath=DESIRED_PATH |
NOTE For best results, the DESIRED_PATH should be an absolute path. Relative paths will be 'anchored' (i.e. made absolute) in ways that you may not expect, and may not work the same with all commands.
.NET feedback
.NET is an open source project. Select a link to provide feedback:
Events
Mar 17, 9 PM - Mar 21, 10 AM
Join the meetup series to build scalable AI solutions based on real-world use cases with fellow developers and experts.
Register nowTraining
Learning path
Solution Architect: Design Microsoft Power Platform solutions - Training
Learn how a solution architect designs solutions.
Documentation
dotnet publish command - .NET CLI
The dotnet publish command publishes a .NET project or solution to a directory.
Breaking change: 'dotnet publish' uses Release configuration - .NET
Learn about a breaking change in the .NET 8 SDK where 'dotnet publish' uses the 'Release' configuration by default.
dotnet build command - .NET CLI
The dotnet build command builds a project and all of its dependencies.