Sdk: CLI builds referenced libraries as debug for release build

Created on 29 Mar 2018  路  4Comments  路  Source: dotnet/sdk

Steps to reproduce

Linux:

  1. Create a library library1 (dotnet new library)
  2. Create a console app console1 (dotnet new console)
  3. Reference library from console app (dotnet add reference)
  4. Create solution (dotnet new sln)
  5. Add console1 to solution (dotnet sln add)
  6. Run publish with release

Expected behavior

library1 should be build for Release

Actual behavior

dotnet publish -c Release -r linux-x64
Microsoft (R) Build Engine version 15.6.82.30579 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  Restoring packages for /home/norekhov/test/library1/library1.csproj...
  Restoring packages for /home/norekhov/test/console1/console1.csproj...
  Restore completed in 351.22 ms for /home/norekhov/test/console1/console1.csproj.
  Restore completed in 351.16 ms for /home/norekhov/test/library1/library1.csproj.
  library1 -> /home/norekhov/test/library1/bin/Debug/netstandard2.0/library1.dll
                                       ^^^^^^^^^^^^^^^ // Why ?
  console1 -> /home/norekhov/test/console1/bin/Release/netcoreapp2.0/linux-x64/console1.dll
  console1 -> /home/norekhov/test/console1/bin/Release/netcoreapp2.0/linux-x64/publish/

Environment data

dotnet --info output:

.NET Command Line Tools (2.1.101)

Product Information:
 Version:            2.1.101
 Commit SHA-1 hash:  6c22303bf0

Runtime Environment:
 OS Name:     debian
 OS Version:  9
 OS Platform: Linux
 RID:         linux-x64
 Base Path:   /usr/share/dotnet/sdk/2.1.101/

Microsoft .NET Core Shared Framework Host

  Version  : 2.0.6
  Build    : 74b1c703813c8910df5b96f304b0f2b78cdf194d


Most helpful comment

some context into why this is the default behavior when building a solution from the command line.

Each project has its own configuration options, and a solution additionally has a "solution configuration". These can differ: it's possible to configure a solution configuration named "Debug" that builds one or more projects in project configuration "Release" (or even a custom project configuration like "AssertButDontOptimize").

When you build a solution using MSBuild, MSBuild first parses the .sln file in the context of the (specified or default) solution configuration. It then passes metadata about that configuration to each project. The individual projects consult that metadata when traversing ProjectReferences. In that way, you get the correct project configuration for every reference to a project within a solution.

When the solution configuration doesn't have information about the project in question, MSBuild can't know what configuration to build for the reference. By default, it specifies no configuration, which means that the "default" configuration is built. In standard template projects, this is Debug. The property @peterhuene points out, ShouldUnsetParentConfigurationAndPlatform changes this: instead of _unsetting_ the configuration and building the project's default configuration, it _passes down_ the explicit configuration of the current project. That is often what you want, but not always: for instance, you might heavily use custom configurations within your solution, but not in the outside-the-solution project. That would fail, since the reference would attempt to build a configuration that isn't defined.

All 4 comments

Hi @sherlock1982. Thank you for reporting this to us!

This is by design when building a solution containing a referenced project that is not in the solution.

There are two ways to mitigate this, the preferred being that you add the library project to the solution.

The other mitigation is to set the ShouldUnsetParentConfigurationAndPlatform property to false:

dotnet publish -c Release -r linux-x64 -p:ShouldUnsetParentConfigurationAndPlatform=false

This however will force all of the referenced projects not in the solution to use the Release configuration the configuration of the project referencing them.

@rainersigwald might be able to give some context into why this is the default behavior when building a solution from the command line.

For now I'm closing this as by design. Please re-open this issue if you have any additional questions or concerns.

some context into why this is the default behavior when building a solution from the command line.

Each project has its own configuration options, and a solution additionally has a "solution configuration". These can differ: it's possible to configure a solution configuration named "Debug" that builds one or more projects in project configuration "Release" (or even a custom project configuration like "AssertButDontOptimize").

When you build a solution using MSBuild, MSBuild first parses the .sln file in the context of the (specified or default) solution configuration. It then passes metadata about that configuration to each project. The individual projects consult that metadata when traversing ProjectReferences. In that way, you get the correct project configuration for every reference to a project within a solution.

When the solution configuration doesn't have information about the project in question, MSBuild can't know what configuration to build for the reference. By default, it specifies no configuration, which means that the "default" configuration is built. In standard template projects, this is Debug. The property @peterhuene points out, ShouldUnsetParentConfigurationAndPlatform changes this: instead of _unsetting_ the configuration and building the project's default configuration, it _passes down_ the explicit configuration of the current project. That is often what you want, but not always: for instance, you might heavily use custom configurations within your solution, but not in the outside-the-solution project. That would fail, since the reference would attempt to build a configuration that isn't defined.

This is specifically bizarre and hard to track down because running dotnet build sln -c release instead doesn't exhibit the same behavior. This looks more like a bug at design time than really desired behavior because of this.

The only reason there is a (dynamically generated) .sln file at all is to convince dotnet build to build more than one .csproj file in one invocation.

There are repeated calls for a dotnet publish --no-build that publishes the last build. I really hope whatever model enables this behavior difference between build and publish isn't why this request isn't getting filled.

The only reason there is a (dynamically generated) .sln file at all is to convince dotnet build to build more than one .csproj file in one invocation.

I would recommend using a traversal project instead of a solution for that purpose, specifically so that you aren't exposed to the darker corners of solution-file handling.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

natemcmaster picture natemcmaster  路  3Comments

dasMulli picture dasMulli  路  3Comments

fmorriso picture fmorriso  路  3Comments

darrensimio picture darrensimio  路  3Comments

davkean picture davkean  路  3Comments