Search code examples
msbuildvisual-studio-2017

MSBuild output in subfolder for each targetframework when using OutDir


When using the new SDK style csproj format, it is possible to use a <targetframeworks> element for a semicolon-separated list of target frameworks to build the project for.

This results in one subfolder per target framework in the build output folder:

build output folder structure

However, when passing the OutDir property on the msbuild command line, it does NOT create the subfolders, and the built assemblies are all placed in the same folder.

Command line that works, but doesn't allow output location:

msbuild projectfile.csproj

Command line that selects output directory, but places built assemblies in same folder (effectively overwriting the target framework assemblies that are built first):

msbuild projectfile.csproj /p:OutDir=buildtemp

Is there a way to place the build output in a non-default folder while still retaining the targetframwork subfolders?


Solution

  • The property that is now used is OutputPath, however setting it from the CLI makes it a global property and overrules the automatic appending of the output path. The workaround is to make an intermediate property that is global and consume it from the project.

    Add this to your project file inside a PropertyGroup:

    <OutputPath>$(BaseOutputPath)</OutputPath>
    

    Then you can set this property globally when calling the build command:

    martin.ullrich@martins-imac:~/tmp$ dotnet build /p:BaseOutputPath=bin/foo
    
      tmp -> /Users/martin.ullrich/tmp/bin/foo/netstandard1.4/tmp.dll
      tmp -> /Users/martin.ullrich/tmp/bin/foo/netstandard1.6/tmp.dll
    

    The problem here is that the SDK tries to change the OutputPath property based on TargetFramework and AppendTargetFrameworkToOutputPath. But if the value is specified via CLI, the project logic cannot overwrite it.

    Also note that BaseOutputPath is actually used in the SDK defaults (defaulted to bin\), but it will try to append the configuration name by default..