Get list of projects in solution with MSBuild - visual-studio

I have a Visual Studio solution with a number of C++ projects (.vcxproj). There is one utility project with a custom build step. On this build step I would like to get a list of projects in solution and pass it to an external tool. Is there a way to have such a list? Something like $(ProjectsInSolution)?
See also https://social.msdn.microsoft.com/Forums/vstudio/en-US/51254ee1-abaf-496a-89f9-cf87fc2ae1e8/list-project-from-solution-sln-file?forum=msbuild

Get list of projects in solution with MSBuild
You could use MSBuild Community Tasks's GetSolutionProjects for this question.
To accomplish this, create a new project in that solution, like GetProjectsPath. You should add MSBuildTasks to your test project. After that, you will find following scripts in your project file(If not, add it manually):
<Import Project="..\packages\MSBuildTasks.1.5.0.235\build\MSBuildTasks.targets" Condition="Exists('..\packages\MSBuildTasks.1.5.0.235\build\MSBuildTasks.targets')" />
Then unload your project. Then at the very end of the project, just before the end-tag </Project>, place below scripts:
<Target Name="GetProjectsPath" AfterTargets="Build">
<GetSolutionProjects Solution="..\GetProjectsPath.sln">
<Output ItemName="ProjectFiles" TaskParameter="Output" />
</GetSolutionProjects>
<Message Text="Get Projects Path in the solution!" />
<Message Text="Relative project paths:" />
<Message Text="%(ProjectFiles.ProjectPath)" />
<Message Text="Full paths to project files:" />
<Message Text="%(ProjectFiles.FullPath)" />
</Target>
When you build this project, you will get the all projects path in the solution:
Hope this helps.

Related

How to build project in multiple configurations to automate the build process?

I have a solution, which contains a native project. For the main project to properly work, the following steps should be taken:
The native project has to be built in Release/x86 configuration
The native project has to be built in Release/x64 configuration
All .NET projects have to be built
Both binaries from steps 1 and 2 have to be placed in the main project's output folder.
Is there a way to configure project, so that all of those steps happen upon simply choosing "Build | Rebuild all"? I know of the batch build option, but I'd still have to execute step 4 manually.
I think you have to use msbuild script to build your project rather than VS IDE. Scripts are more flexible and can realize your requirements.
1) create a new file called build.proj and then add these on that file:
<Project>
<ItemGroup>
<!--include all c# csproj files to build these projects all at once-->
<NetProjectFile Include="**\*.csproj" />
<!--include the c++ proj files-->
<NativeProjectFile Include="**\*.vcxproj" />
</ItemGroup>
<Target Name="Build">
<MSBuild Projects="#(NetProjectFile)" Targets="Restore;Build" Properties="Configuration=Debug;Platform=AnyCPU"/>
<!--OutDir is the path of the execute file ,pdb.... if you also want the intermediate files to be in the same folder, you should also use IntDir -->
<MSBuild Projects="#(NativeProjectFile)" Targets="Build" Properties="Configuration=Release;Platform=x86;OutDir=xxx\xxx\"/>
<MSBuild Projects="#(NativeProjectFile)" Targets="Build" Properties="Configuration=Release;Platform=x64;OutDir=xxx\xxx\"/>
</Target>
</Project>
3) Just run msbuild build.proj -t:Build to get what you want.

csproj file settings for several build projects

I have this solution structute:
Solution.sln
|--WebUI.csproj (has Core.csproj as dependency)
|--Core.csproj
|--Tests
|--UnitTests
|--WebUI.UnitTest.csproj (has Core.csproj and WebUI.csproj as dependencies)
|--Core.UnitTest.csproj (has Core.csproj as dependency)
What should I add to WebUI.csproj to build WebUI.UnitTest.csproj and Core.UnitTest.csproj all together? (in my WebUI\bin folder I need these libs: WebUI.UnitTest.dll and Core.UnitTest.dll).
Thanks!
The direct method is that add WebUI.UnitTest project and Core.UnitTest project as dependencies for WebUI project. But the WebUI.UnitTest project already has WebUI.csproj as dependencies, this method does not work in your solution structure. If you just want to have WebUI.UnitTest.dll and Core.UnitTest.dll in your WebUI\bin folder, you can add a task in your WebUI.csproj to copy those files to the folder:
<Target Name="AfterBuild">
<PropertyGroup>
<SolutionDir>$([System.IO.Path]::GetDirectoryName($(MSBuildProjectDirectory)))</SolutionDir>
</PropertyGroup>
<Exec Command=""$(MSBuildBinPath)\MSBuild.exe" "$(SolutionDir)\WebUI.UnitTest\WebUI.UnitTest.csproj"" />
<Exec Command=""$(MSBuildBinPath)\MSBuild.exe" "$(SolutionDir)\Core.UnitTest\Core.UnitTest.csproj"" />
<PropertyGroup>
<CopyFileOutput>$(SolutionDir)\WebUI.UnitTest\bin\Debug\WebUI.UnitTest.dll;$(SolutionDir)\Core.UnitTest\bin\Debug\Core.UnitTest.dll</CopyFileOutput>
</PropertyGroup>
<Copy
SourceFiles="$(CopyFileOutput)"
DestinationFolder="$(SolutionDir)\WebUI\bin"
/>
Note that: The stijn`s comment is right, you build the solution, WebUI.UnitTest.csproj and Core.UnitTest.csproj should get built already.
I have also added build steps of WebUI.UnitTest.csproj and Core.UnitTest.csproj in the WebUI.csproj so that you just only need to build the WebUI.csproj.

MSBuild or NAnt script that generates C# files, adds them to a project and compiles the project

I've just written a code generator app for FluentMigrator API that emits an unknown number of C# class files. I wish to compile the code generator, run it to emit the C# classes then add the new C# files to an existing C# project and then compile final solution.
What's the best approach for adding the code generated C# files to a project?
Given what we know from your post, there could be a couple approaches.
You have an API that will generate some class files and want to integrate this into your build process so you would make an API call to generate new class files, then incorporate those class files into your build.
If your executable emits output files into it's current working directory, you could use an Exec task to run your command in the $(IntermeidateOutputPath) so as to not clutter up your project's source tree:
<Exec Command="MyExe.exe " WorkingDirectory="$(IntermediateOutputPath)\AutoGenClasses\" />
Following this command, you could append those output classes into the default compile group:
<ItemGroup>
<Compile Include="$(IntermediateOutputPath)\AutoGenClasses\**\*.cs" />
</ItemGroup>
Now you'd probably want to control when this occurs, so you'd embed this code into a separate <Target /> and schedule it to occur before the build occurs.
<Target Name="AutoGenClasses" BeforeTargets="Compile">
<Message Text="Starting the AutoGenClasses task..." Importance="high" />
<Exec Command="MyExe.exe " WorkingDirectory="$(IntermediateOutputPath)\AutoGenClasses\" />
<ItemGroup>
<Compile Include="$(IntermediateOutputPath)\AutoGenClasses\**\*.cs" />
</ItemGroup>
<Message Text="... completed the AutoGenClasses." Importance="high" />
</Target>

Visual Studio Express 2012 for Web - don't generate bin and obj folders

Can I turn off generating these folders on build? They contain some .dll, .pdb and other files I don't need. I'm just using Typescript compilation.
Yes, it is possible. I relied on the following nice overview on how to hijack a build process:
http://sedodream.com/2013/06/01/HijackingTheVisualStudioBuildProcess.aspx
Three main tricks:
1) project_name.csproj is the one you need to modify, it is XML MSBUILD file.
2) You cannot remove dependency from WebApplication.targets, you need to "deactivate" them as below.
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v11.0\WebApplications\Microsoft.WebApplication.targets" Condition="false" />
3) You have to implement general contract for clean/build/rebuild targets.
Mine looks like:
<Target Name="Build">
<Exec Command="call node_modules\.bin\tsc.cmd src/main.ts --out js/game.min.js > $(Temp)\tscout.txt" IgnoreExitCode="true" WorkingDirectory="$(SolutionDir)" />
<Exec Command="type $(Temp)\tscout.txt" />
</Target>
<Target Name="Rebuild" DependsOnTargets="Clean;Build">
</Target>
<Target Name="Clean">
<RemoveDir Directories="js">
</RemoveDir>
</Target>
You could create a New WebSite instead of New Project. That one should not create any binary output.

Copy built assemblies (including PDB, .config and XML comment files) to folder post build

Is there a generic way I can get a post-build event to copy the built assembly, and any .config and any .xml comments files to a folder (usually solution relative) without having to write a post-build event on each project in a solution?
The goal is to have a folder that contains the last successful build of an entire solution.
It would be nice to use the same build solution over multiple solutions too, possibly enabling/ disabling certain projects (so don't copy unit tests etc).
Thanks,
Kieron
You can set common OutputPath to build all projects in Sln in one temp dir and copy required files to the latest build folder. In copy action you can set a filter to copy all dlls without "test" in its name.
msbuild.exe 1.sln /p:Configuration=Release;Platform=AnyCPU;OutputPath=..\latest-temp
There exists more complicated and more flexible solution. You can setup a hook for build process using CustomAfterMicrosoftCommonTargets. See this post for example.
Sample targets file can be like that:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildDependsOn>
$(BuildDependsOn);
PublishToLatest
</BuildDependsOn>
</PropertyGroup>
<Target Name="PreparePublishingToLatest">
<PropertyGroup>
<TargetAssembly>$(TargetPath)</TargetAssembly>
<TargetAssemblyPdb>$(TargetDir)$(TargetName).pdb</TargetAssemblyPdb>
<TargetAssemblyXml>$(TargetDir)$(TargetName).xml</TargetAssemblyXml>
<TargetAssemblyConfig>$(TargetDir)$(TargetName).config</TargetAssemblyConfig>
<TargetAssemblyManifest>$(TargetDir)$(TargetName).manifest</TargetAssemblyManifest>
<IsTestAssembly>$(TargetName.ToUpper().Contains("TEST"))</IsTestAssembly>
</PropertyGroup>
<ItemGroup>
<PublishToLatestFiles Include="$(TargetAssembly)" Condition="Exists('$(TargetAssembly)')" />
<PublishToLatestFiles Include="$(TargetAssemblyPdb)" Condition="Exists('$(TargetAssemblyPdb)')" />
<PublishToLatestFiles Include="$(TargetAssemblyXml)" Condition="Exists('$(TargetAssemblyXml)')" />
<PublishToLatestFiles Include="$(TargetAssemblyConfig)" Condition="Exists('$(TargetAssemblyConfig)')" />
<PublishToLatestFiles Include="$(TargetAssemblyManifest)" Condition="Exists('$(TargetAssemblyManifest)')" />
</ItemGroup>
</Target>
<Target Name="PublishToLatest"
Condition="Exists('$(LatestDir)') AND '$(IsTestAssembly)' == 'False' AND '#(PublishToLatestFiles)' != ''"
DependsOnTargets="PreparePublishingToLatest">
<Copy SourceFiles="#(PublishToLatestFiles)" DestinationFolder="$(LatestDir)" SkipUnchangedFiles="true" />
</Target>
</Project>
In that targets file you can specify any actions you want.
You can place it here "C:\Program Files\MSBuild\v4.0\Custom.After.Microsoft.Common.targets" or here "C:\Program Files\MSBuild\4.0\Microsoft.Common.targets\ImportAfter\PublishToLatest.targets".
And third variant is to add to every project you want to publish import of custom targets. See How to: Use the Same Target in Multiple Project Files

Resources