Reputation: 3481
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:
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?
Upvotes: 4
Views: 6035
Reputation: 1319
If you need this to work with OutDir, there's an alternative method...
You can use TreatAsLocalProperty to redefine OutDir in a way that appends the multi-target folders to the output path; for example:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' And '$(OutDir)' != '' ">
<!-- OutDir is passed to msbuild via command line, but it
prevents AppendTargetFrameworkToOutputPath from functioning.
Combined with TreatAsLocalProperty="OutDir", we can redefine
outdir so it appends the $(TargetFramework) to support multi-targeting -->
<OutDir>$(OutDir)\$(TargetFramework)</OutDir>
</PropertyGroup>
Full SDK style project example:
<Project Sdk="Microsoft.NET.Sdk" TreatAsLocalProperty="OutDir">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net462</TargetFrameworks>
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
<OutputType>Library</OutputType>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<AssemblyTitle>Some.Assembly</AssemblyTitle>
<Description>Some Assembly</Description>
<AssemblyVersion>1.0.0</AssemblyVersion>
<FileVersion>1.0.0</FileVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' And '$(OutDir)' != '' ">
<!-- OutDir is passed to msbuild via command line, but it
prevents AppendTargetFrameworkToOutputPath from functioning.
Combined with TreatAsLocalProperty="OutDir", we can redefine
outdir so it appends the $(TargetFramework) to support multi-targeting -->
<OutDir>$(OutDir)\$(TargetFramework)</OutDir>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
</ItemGroup>
</Project>
Upvotes: 1
Reputation: 100751
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..
Upvotes: 7