1

Our solution (A.sln) needs a binary that is built by another (legacy) solution (B.sln). I can't go into details about why this is necessary, it's a long and hairy story.

Constraints

The application produced by A only needs the artifacts of B at runtime, so it doesn't matter when in the build process this dependency is fullfilled. Because of naming conflicts we don't want to build both projects in the same directory, but rather copy some artifacts of B to a subdirectory of the output path of A.

I tried

1) Adding the dependency B as a build target to A by adding the following to A.sln

<Target Name="Build">
  <MSBuild Projects="$(SolutionDir)..\B\B.sln" Properties=" Platform=Win32; Configuration=$(Configuration); " />
</Target>

For some reason this builds B in the output directory of A, which is unwanted.

2) Adding a post build event to A calling msbuild on B by adding the following to A.sln

<PropertyGroup>
  <PostBuildEvent>
    msbuild $(SolutionDir)..\B\B.sln /p:configuration=$(ConfigurationName)
    xcopy /E /R /Y $(SolutionDir)..\B\$(ConfigurationName) $(SolutionDir)$(ConfigurationName)\B\
  </PostBuildEvent>
</PropertyGroup>

For some reason this works in the VS 2015 command prompt, but not in Visual Studio itself. VS (2015) complains that

C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\CodeAnalysis\Microso
ft.CodeAnalysis.targets(219,5): error MSB4175: The task factory "CodeTaskFactory
" could not be loaded from the assembly "C:\Windows\Microsoft.NET\Framework64\v4
.0.30319\Microsoft.Build.Tasks.v12.0.dll". Could not load file or assembly 'file
:///C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Build.Tasks.v12.0.
dll' or one of its dependencies. The system cannot find the file specified. [C:\
Users\Chiel.tenBrinke\Projects\MyProject\B\CppSource\B.vcxproj]

So, what is the best (i.e. easiest, most maintainable, cleanest) way to go about this?

jww
  • 97,681
  • 90
  • 411
  • 885
chtenb
  • 14,924
  • 14
  • 78
  • 116

2 Answers2

1
<PropertyGroup>
  <PostBuildEvent>
    msbuild $(SolutionDir)..\B\B.sln /p:configuration=$(ConfigurationName)
    xcopy /E /R /Y $(SolutionDir)..\B\$(ConfigurationName) $(SolutionDir)$(ConfigurationName)\B\
  </PostBuildEvent>
</PropertyGroup>

I think this might make more sense as an ItemDefinitionGroup, not a PropertyGroup. At least that's how Visual Studio places it.

You can tighten it up with a Condition, too. Maybe something like:

<ItemDefinitionGroup Condition="!Exists('$(ConfigurationName)\b.exe')" Label="Copy b.exe">
  <PostBuildEvent>
    msbuild /t:Build /p:Configuration=$(ConfigurationName) B.vcxproj
    xcopy /E /R /Y ...\B\$(ConfigurationName)\b.exe $(ConfigurationName)\B
  </PostBuildEvent>
</ItemDefinitionGroup>

We had to do similar to hack an out-of-project dependency that could not be expressed properly with the tools. Like you, I felt like a Target was the way to go, but I could not get it to work either...

Anyway, here is our cryptdll.vcxproj that actually uses out-of-project dependency hack, so I know it works.

<!-- The current project file is c.vcxproj. We have a hard requirement to always -->
<!-- use Win32/Debug EXE. Also, b.vcxproj depends on an artifact from a.vcxproj -->
<ItemDefinitionGroup Condition="!Exists('Win32\Debug\b.exe')" Label="MAC tool">
  <PreBuildEvent>
    <Message>Creating Win32/Release cryptest.exe for MAC computation</Message>
    <Command>
      msbuild /t:Build /p:Configuration=Debug;Platform=Win32 a.vcxproj
      msbuild /t:Build /p:Configuration=Debug;Platform=Win32 b.vcxproj
    </Command>
  </PreBuildEvent>
</ItemDefinitionGroup>
jww
  • 97,681
  • 90
  • 411
  • 885
1

The way I ended up doing it was on a project level instead of solution level. The xml in the project of solution A is of the following form:

<Target Name="AfterBuild">
  <MSbuild
      Projects="$(SolutionDir)..\B\CppSource\SomeProject.vcxproj"
      Properties="
      Configuration=$(ConfigurationName);
      OutDir=$(SolutionDir)$(ConfigurationName)\B\;
      "/>
</Target>
chtenb
  • 14,924
  • 14
  • 78
  • 116
  • Do you know what the difference is between a `PostBuildEvent` and a `Target` with `AfterBuild`? – jww Oct 06 '16 at 16:32
  • No idea, but I found this: http://stackoverflow.com/questions/6128567/visual-studio-project-file-difference-between-postbuildevent-and-afterbuild-targ – chtenb Oct 06 '16 at 16:34
  • Thanks. I've got to buy a book on this subject. All MSDN does is confuse me more than I already am with their context-less fragments... – jww Oct 06 '16 at 16:41