Project-system: [Question] <Optimize> default for pdbonly/Release configuration builds?

Created on 27 Nov 2018  路  10Comments  路  Source: dotnet/project-system

Is <Optimize> enabled by default when building with Release configuration or is it even coupled to pdbonly?

In a quick experiment a couple of weeks ago I compared hashes of an assembly with an without <Optimize> set to true and they were identical.

DiscussioQuestion Triage-Approved

All 10 comments

Can you give an example of your project file? /optimize+ is passed to the compiler on release builds by default.

In a new .NET Core project these are the relevant options that are passed to csc.exe for debug and release:

default debug build on .NET Core

/debug+ 
/optimize- 
/debug:portable 
/deterministic+ 

default release build on .NET Core

/debug- 
/optimize+ 
/debug:portable 
/deterministic+ 

Thank you for the clarification.

  1. I assume this is identical for class libraries targeting full .NET Framework?
  2. Are there more of these defaults regarding other artifacts which are part of the project file?
  3. Are these defaults documented somewhere? I am trying to be as neat and clean as possible and kick out everything that isn't really necessary.

I assume this is identical for class libraries targeting full .NET Framework?

Nope in .NET Framework you need to fully specify most everything and nothing is implicit. Given the following project file:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <ProjectGuid>0635cbaa-d0b1-4314-bce0-f9c618139632</ProjectGuid>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>ClassLibrary8</RootNamespace>
    <AssemblyName>ClassLibrary8</AssemblyName>
    <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
    <Deterministic>true</Deterministic>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="System"/>
    <Reference Include="System.Core"/>
    <Reference Include="System.Xml.Linq"/>
    <Reference Include="System.Data.DataSetExtensions"/>
    <Reference Include="Microsoft.CSharp"/>
    <Reference Include="System.Data"/>
    <Reference Include="System.Net.Http"/>
    <Reference Include="System.Xml"/>
  </ItemGroup>
  <ItemGroup>
    <Compile Include="Class1.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
 </Project>

This is what gets passed to the commandline on debug

 /noconfig
 /nowarn:1701,1702
 /nostdlib+
 /errorreport:prompt
 /warn:4
 /define:DEBUG;TRACE
 /highentropyva+
 /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\Microsoft.CSharp.dll"
 /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\mscorlib.dll"
 /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Core.dll"
 /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Data.DataSetExtensions.dll"
 /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Data.dll"
 /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.dll"
 /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Net.Http.dll"
 /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Xml.dll"
 /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Xml.Linq.dll"
 /debug+
 /debug:full
 /filealign:512
 /optimize-
 /out:obj\Debug\ClassLibrary8.dll
 /ruleset:"C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\Team Tools\Static Analysis Tools\\Rule Sets\MinimumRecommendedRules.ruleset"
 /subsystemversion:6.00
 /target:library
 /utf8output
 /deterministic+ 

This is what gets passed to the commandline on release

 /noconfig
 /nowarn:1701,1702
 /nostdlib+
 /errorreport:prompt
 /warn:4
 /define:TRACE
 /highentropyva+
 /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\Microsoft.CSharp.dll"
 /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\mscorlib.dll"
 /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Core.dll"
 /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Data.DataSetExtensions.dll"
 /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Data.dll"
 /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.dll"
 /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Net.Http.dll"
 /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Xml.dll"
 /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Xml.Linq.dll"
 /debug:pdbonly
 /filealign:512
 /optimize+
 /out:obj\release\ClassLibrary8.dll
 /subsystemversion:6.00
 /target:library
 /utf8output
 /deterministic+ 

Are these defaults documented somewhere?

see the documentation here: https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-reference?view=vs-2017

Thanks again for your help, really appreciate it.

Sorry for not being clear, my bad. I thought this was obvious because I am asking this question in the project of the new project system:

I meant if I have migrated my project from the "old way" you just mentioned to the new csproj/new project system format in combination with keeping the (full) .NET Framework targeting (e.g. <TargetFramework>net472</TargetFramework>).

Again, in this case I assume the project system behaves in the same way (regarding the mentioned default(s) from above - optimize for release configuration builds) as if .NET Core would be targeted?

@timmkrause Ah ok. See here for some additional info: https://docs.microsoft.com/en-us/visualstudio/msbuild/how-to-use-project-sdk?view=vs-2017

Basically the SDK will import all of the same information as the project I pasted above, you should not need to add anything new. All of the defaults are implicit. You only need to add properties and items if you want to override the default behavior.

So I have this now after the migration of a file, new project of a .NET Framework class library to the new format (example, I did this for all of my projects):

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net471</TargetFramework>
    <OutputPath>bin\$(Configuration)\</OutputPath>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Net.Http" />
  </ItemGroup>
</Project>

Via dotnet msbuild -pp:msbuild.xml I found the following regarding <Optimize>:

  <!-- User-facing configuration-specific defaults -->
  <PropertyGroup Condition=" '$(Configuration)' == 'Debug' " xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <DebugSymbols Condition=" '$(DebugSymbols)' == '' ">true</DebugSymbols>
    <Optimize Condition=" '$(Optimize)' == '' ">false</Optimize>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)' == 'Release' " xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <Optimize Condition=" '$(Optimize)' == '' ">true</Optimize>
  </PropertyGroup>

So I assume this is basically correct regarding my assumption.

The other question was, how do I know that <OutputPath>bin\$(Configuration)\</OutputPath> is required or not?
By trial and error I realized that I do not need it (remove, build, output still in same directories).
Via dotnet msbuild -pp:msbuild.xml again it seems that there are assumptions in the imported targets regarding the output path, so this somehow proofs this.

This is only a simple example. In my "real" projects which I have migrated there is some more stuff in it which I am questioning if it could be removed, but unfortunately there are so many defaults that seem to be undocumented.
Is msbuild -pp the way to go to verify these things?

The migration here is harder than it needs to be, hopefully in the future we can make this sort of this easier. In the meanwhile, this tool https://github.com/srivatsn/ProjectSimplifier/ does exactly what you are after.

The first projects I did by hand to have a greater learning effect, after that I was using https://github.com/hvanbakel/CsprojToVs2017. Do you know this one? It is a little defensive regarding the defaults...

Going to close this one out, we're still thinking about making migration easier but I think the general gist of the questions above were answered.

Was this page helpful?
0 / 5 - 0 ratings