Question

We are trying to write a msbuild script that will build the solution and copy over all the compiled binaries and dependencies over to a specific output folder. While the build script that we have does build and copy over the binaries to a common folder, but we are not getting the dependencies copied. This probably has to do with the way we have used the msbuild task to build the solution and we are accepting the targetoutputs of the task into an itemgroup and iterating over the item group to copy all the compiled dlls and exes over to a common folder. But this is not including the dependency dlls which gets placed into the individual bin folder of each project.

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
    <ParentSolutionFile />
</PropertyGroup>
<ItemGroup>
    <Assemblies Include="*.dll, *.exe" />
</ItemGroup>
<Target Name="BuildAll">
    <CombinePath BasePath="$(MSBuildProjectDirectory)" Paths="Source\Solutions\xxx.sln">
        <Output TaskParameter="CombinedPaths" PropertyName="ParentSolutionFile" />
    </CombinePath>
    <Message Text="$(ParentSolutionFile)" />
    <MSBuild Projects="$(ParentSolutionFile)">
        <Output TaskParameter="TargetOutputs" ItemName="Assemblies" />
    </MSBuild>
    <Message Text="%(Assemblies.Identity)" />
    <Copy SourceFiles="%(Assemblies.Identity)" DestinationFolder="$(MSBuildProjectDirectory)\Binary" OverwriteReadOnlyFiles="True" SkipUnchangedFiles="True" />
</Target>

What will be the preferred way to copy over all the binaries along with the necessary dependencies to a common output folder?

Was it helpful?

Solution

Does not overriding OutputPath do the trick alone?

<MSBuild Projects="$(ParentSolutionFile)" Properties="OutputPath=$(MSBuildProjectDirectory)\Binary">
  <Output TaskParameter="TargetOutputs" ItemName="Assemblies" />
</MSBuild>

And leave out the copy task alltogether?

OTHER TIPS

The build process will place the final result in the directory represented by OutputPath - at least if you are building c# projects. For C/C++ the internal structure and variable names are completely different.

Thus, in theory, you could pass the OutputPath in the MsBuild-task that builds the solution.

<MsBuild Projects="$(ParentSolutionFile)"
    Properties="OutputPath=$(MSBuildProjectDirectory)\Binary"/>

However, the csproj-files will overwrite that value unconditionally with the following code:

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DebugSymbols>true</DebugSymbols>
    <OutputPath>bin\Debug\</OutputPath>

I have solved this by injecting my own build system in each and every csproj-file.

<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\..\build\buildsystem.targets" />

The path is relative to the csproj-file. An absolute path is fine too, or a variable. The trick is to make it work on all dev machines as well as the build agents.

Now, in buildsystem.targets, simply redefine OutputPath as much as you like. Again, the trick is to ensure you get the same - or at least a well defined - location regardless of who builds it (dev, build agent) and regardless how the build was initiated (VS, command line).

A simple way of handling the differences is to import conditionally.

<Import Project="..\..\..\build\buildsystem.targets"
    Condition="'$(BuildingInsideVisualStudio)'!='true'"/>

That will give you no changes if initiating the build from VS and whatever changes you code for if you build from command line.

--Jesper

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top