views:

1689

answers:

2

I have a normal SLN file, and I'm compiling it fine with msbuild from the command line. I do this:

C:\slndir> msbuild /p:OutDir=C:\slnbin\

And it dumps everything into C:\slnbin, except for websites, which get deployed to C:\slnbin_PublishedWebsites\.

What I would like is to not only have all the binaries dropped in the bin dir, but also have each executeable program have it's own "deployed" folder, similar to what each website gets.

So, for example, If I have the following projects: - Common - Lib1 - Service1 - Lib2 - Service2

I wan to get:

  C:\slnbin\ // Everything
  C:\slbin\Deploy\Service1 // Common, Lib1, Service1
  C:\slbin\Deploy\Service2 // Common, Lib2, Service2

I tried doing stuff like "msbuild /p:OutDir=C:\slnbin\$(ProjectName)", but it just treats it as a literal and creates an actual "$(ProjectName)" subdir.

Preferrably, I would not have to modify every individual project and so on.

Is this possible? Easy?

+1  A: 

You'll have to do this "by hand". Create a master MSBUILD project file that builds the solution, then copies all the solution outputs where it wants them. This is (roughly) how Visual Studio Team Build does it.

John Saunders
So I can't leverage the fact that the csproj files know all their dependencies? Would this mean I have to maintain dependences in two locations (csprojs and msbuild)?
MichaelGG
+6  A: 

Like John Saunders said, you need to have a master MSBuild file that handles the process.

Here is a sample using MSBuild Community Tasks : GetSolutionProjects that gets the projects for a given solution

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Package">

  <Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>

  <!-- Specify here, the solution you want to compile-->
  <ItemGroup>
    <Solution Include="C:\slndir\solution.sln"/>
  </ItemGroup>

  <PropertyGroup>
    <Platform>AnyCPU</Platform>
    <Configuration>Debug</Configuration>

    <!-- Your deployment directory -->
    <DeployDir>C:\slbin\Deploy</DeployDir>
  </PropertyGroup>

  <!-- Gets the projects composing the specified solution -->
  <Target Name="GetProjectsFromSolution">
    <GetSolutionProjects Solution="%(Solution.Fullpath)">
      <Output ItemName="ProjectFiles" TaskParameter="Output"/>
    </GetSolutionProjects>
  </Target>

  <Target Name="CompileProject" DependsOnTargets="GetProjectsFromSolution">
    <!-- 
      Foreach project files
        Call MSBuild Build Target specifying the outputDir with the project filename.
    -->
    <MSBuild Projects="%(ProjectFiles.Fullpath)"
             Properties="Platform=$(Platform);
             Configuration=$(Configuration);
             OutDir=$(DeployDir)\%(ProjectFiles.Filename)\"
             Targets="Build">
    </MSBuild>
  </Target>
</Project>
madgnome
This is working great for us. One question -- when you call MSBuild passing Projects="%(ProjectFiles.Fullpath)", is MSBuild smart enough to only build each project one time? For example, if you have foo.dll that is in the Solution, and is referenced by 4 other projects, will it build foo.dll one time, or 4 times, or 5 times?
Charlie Flowers
"Unlike using the Exec Task to start MSBuild.exe, this task uses the same MSBuild process to build the child projects. The list of already-built targets that can be skipped is shared between the parent and child builds. This task is also faster because no new MSBuild process is created." So I guess foo.dll will be build one time but I'm not sure.
madgnome