0

How can I get the build output directory of a referenced project in MSBuild 17?

<!-- Installer.wixproj -->
<Project Sdk="WixToolset.Sdk/4.0.0">
    <ItemGroup>
        <ProjectReference Include="..\Ref\Ref.csproj" />
    </ItemGroup>

    <Target Name="ShowProject" AfterTargets="Build">
        <Message Text="Output path is $(Ref.OutputDir)" Importance="high" />
    </Target>
</Project>

Expected result from dotnet build Installer.wixproj:

MSBuild version 17 ...
   Output path is C:\Path\To\Solution\Ref\bin\Release
Jeremy Morren
  • 615
  • 9
  • 23
  • Out of the box the output directory of a referenced project is not available. But you can add a custom target that provides the output directory and an example of how to do that is in the question/answer that @Christian.K cites. (But the answer is old and there are some better options.) – Jonathan Dodds Jun 26 '23 at 19:47
  • @JonathanDodds Do you have any links to the better options? – Jeremy Morren Jun 27 '23 at 00:15
  • In a [`Directory.Build.targets` file](https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-by-directory?view=vs-2022) create a target that outputs `$([System.IO.Path]::Combine('$(MSBuildProjectDirectory)', '$(OutputPath)'))`. From the project that needs the output paths, use the `msbuild` task to run this shared target from the projects in the `@(ProjectReference)` ItemGroup. In the `msbuild` task it is important to pass to each project the current `$(Configuration)`, `$(Platform)`, and `$(TargetFramework)`. – Jonathan Dodds Jun 27 '23 at 02:58
  • @JeremyMorren Hi Jeremy, any update of this issue, does my answer answered your question? :) – Bowman Zhu-MSFT Jun 28 '23 at 06:49

2 Answers2

1

Unfortunately, the approach above did not work for desktop applications i.e. self contained etc. I am posting the code that worked for me in the end.

Note: I am also including the Wixv4-specific part, in case anyone uses it for that. The harvest directories target does not run in JetBrains Rider, but does via the dotnet cli.

<Project Sdk="WixToolset.Sdk/4.0.0">
    <PropertyGroup>
        <Platform Condition="'$(RuntimeIdentifier)' == 'win-x64'">x64</Platform>
        <Platform Condition="'$(RuntimeIdentifier)' == 'win-x86'">x86</Platform>
    </PropertyGroup>
    <ItemGroup>
        <!-- This is required to make the HarvestDirectories target run -->
        <HarvestDirectory Include="obj/" Visible="false" ComponentGroupName="CMP_None" SupressCom="true" SuppressRegistry="true" />
    </ItemGroup>
    
    <ItemGroup>
        <ProjectReference Include="..\App\App.csproj" />
    </ItemGroup>
    
    <ItemGroup>
        <PackageReference Include="WixToolset.Heat" Version="4.0.1" />
        <PackageReference Include="WixToolset.UI.wixext" Version="4.0.1" />
    </ItemGroup>

    <Target Name="GenerateHarvestDirectories" BeforeTargets="HarvestDirectory">
        <MSBuild Projects="%(ProjectReference.Identity)" Targets="GetTargetPath" Properties="Configuration=$(Configuration);RuntimeIdentifier=$(RuntimeIdentifier);SelfContained=$(SelfContained)">
            <Output TaskParameter="TargetOutputs" ItemName="PrimaryAssembly" />
        </MSBuild>

        <Message Text="Harvesting CMP_%(PrimaryAssembly.Filename): %(PrimaryAssembly.RelativeDir)" Importance="high" />
        <ItemGroup>
            <HarvestDirectory ComponentGroupName="CMP_%(PrimaryAssembly.Filename)" SuppressCom="true" SuppressRegistry="true" SuppressRootDirectory="true" DirectoryRefId="InstallDir" Include="%(PrimaryAssembly.RelativeDir)" />
        </ItemGroup>
    </Target>
</Project>

The GenerateHarvestDirectories target runs for each referenced project. Result (paths removed for brevity):

$ dotnet build Installer.wixproj -c Release -r win-x64 --self-contained

MSBuild version 17.5.1+f6fdcf537 for .NET
  ...
  App -> ...\App\bin\Release\net7.0-windows10.0.17763\win-x64\App.dll
  Harvesting CMP_App: ...App\bin\Release\net7.0-windows10.0.17763\win-x64\
  Installer -> ...\Installer\bin\x64\Release\Installer.msi
Jeremy Morren
  • 615
  • 9
  • 23
-1

Do you mean this?

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\Ref\Ref.csproj" />
  </ItemGroup>


    <Target Name="ShowProject" AfterTargets="Build">
        <Message Text="Output path is $(ProjectDir)\Ref\$(OutDir)" Importance="high" />

    </Target>
</Project>

I can get the reference project output path after main project build step:

enter image description here

By the way, if you only want to go to release directory instead of output directory, then you need custom property:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <ProjectReference Include="..\Ref\Ref.csproj" />
  </ItemGroup>


    <Target Name="ShowProject" AfterTargets="Build">
        <!--<Message Text="Output path is $(ProjectDir)\Ref\$(OutDir)" Importance="high" />-->
        <PropertyGroup>
            <CustomOutputPath>$(ProjectDir)\Ref\bin\Release</CustomOutputPath>
        </PropertyGroup>
        <Message Text="Output path is $(CustomOutputPath)" Importance="high" />


    </Target>
</Project>

enter image description here

Bowman Zhu-MSFT
  • 4,776
  • 1
  • 9
  • 10
  • This will work if you know that the referenced project has a particular output directory structure and that used properties have the same values (release builds are called "Release", etc.) and that the referenced project is build using the same configuration, etc.. If you don't, or can't rely on it, it won't. The only reliable thing is to actually "build" the other project (to have MSBuild evaluate its properties) and then have it print its output path and pick it up. If your approach is good enough for the OP, than I would agree that it solves his problem. – Christian.K Jul 05 '23 at 05:20