essay on programming languages, computer science, information techonlogies and all.

Thursday, December 19, 2013

Using MSBUILD

Using MSBUILD and making a build process has advantage on other building tools - e.g. nants ... - and that is IDE. When project file is loaded in Visudal Studio IDE and when project is compiled in build process, there is no difference. So just write code and test it in the IDE is enough to run build process.

But to be consistent on the build result across number of project, it should have a common configuration setting that applies to all the project. This can be easily done by just taking out common part of project and import it in the project configuration. Refer below code snippet. There is Import which asks for BuildUnitTest.Default.props. This file can contains all the common setting across all the unit test that is based on the boot unit test framework.

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{YOUR_GUID_GO_HERE}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>YOUR_PROJECT_NAMESPACE_GOES_HERE</RootNamespace>
<ProjectName>YOUR_PROJECT_NAME_GOES_HERE</ProjectName>
</PropertyGroup>
<PropertyGroup>
<SRC_ROOT>..\..</SRC_ROOT> <!-- example of a custom property -->
<UseOfAtl>Static</UseOfAtl>
</PropertyGroup>
<Import Project="$(SRC_ROOT)\Build\BoostUnitTest.Default.props" />
<ItemDefinitionGroup> <!-- project specific setting -->
<ClCompile>
<AdditionalIncludeDirectories>..\include;..\SequenceControl;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<!-- your project file goes here -->
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
Now the BuildUnitTest.Default.props can be looked like below. Note setting like OutDir and IntDir. By using this common project file, all the project can emit the generated output file to the OutDir which is consitently named location and all the intermediate file can go to the consitently named IntDir. And note the Debug and Release usage to make consistent setting applying to all the project that import this file.

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup>
<ConfigurationType>Application</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v100</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
<WholeProgramOptimization>false</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings"/>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<OutDir>..\bin\$(Configuration)\</OutDir>
<IntDir>..\Intermediate\$(ProjectName)\$(Configuration)\</IntDir>
<IgnoreImportLibrary>false</IgnoreImportLibrary>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PrecompiledHeader />
<WarningLevel>Level3</WarningLevel>
<PreprocessorDefinitions>WIN32;_WINDOWS;_CONSOLE;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SRC_ROOT)\3rdParty\boost_1_53;$(SRC_ROOT);$(SRC_ROOT)\Common;..\bin\$(Configuration)\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<ExceptionHandling>Async</ExceptionHandling>
</ClCompile>
<Link>
<AdditionalDependencies>comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SRC_ROOT)\3rdParty\boost_1_53\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<GenerateDebugInformation>true</GenerateDebugInformation>
<SubSystem>Console</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
<Link>
<TargetMachine>MachineX86</TargetMachine>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<ClCompile>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
</ClCompile>
<Link>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<ClCompile>
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
</ClCompile>
<Link>
<OptimizeReferences>true</OptimizeReferences>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
</Link>
</ItemDefinitionGroup>
</Project>
After having number of this kind os project, it is time to weave those together and make a one project file that can build all the projects. Refer below BuildAll.proj. All solution files are listed at the SolutionToBuild. And all unit test that can be run can be liseted at AfterBuild.

<?xml version="1.0" encoding="utf-8"?>
<Project
ToolsVersion="4.0"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
DefaultTarget="FullBuild">
<PropertyGroup>
<SRC_ROOT>..</SRC_ROOT>
</PropertyGroup>
<ItemGroup>
<AllConfigurations Include="Debug"/>
<!--<AllConfigurations Include="Release"/>-->
</ItemGroup>
<ItemGroup>
<SolutionToBuild Include="$(SRC_ROOT)\Foo\Foo.sln"/>
<!-- Your solution files goes here -->
<SolutionToBuild Include="$(SRC_ROOT)\Bar\Bar.sln"/>
</ItemGroup>
<PropertyGroup>
<FullBuildDependsOn>
$(FullBuildDependsOn);
BeforeBuild;
CoreBuild;
AfterBuild
</FullBuildDependsOn>
</PropertyGroup>
<Target
Name="FullBuild"
DependsOnTargets="$(FullBuildDependsOn)">
</Target>
<Target Name="BeforeBuild">
<!-- TODO : Get latest source from version control -->
</Target>
<Target Name="CoreBuild">
<MSBuild
Projects="@(SolutionToBuild)"
Properties="Configuration=%(AllConfigurations.Identity)" />
</Target>
<Target Name="AfterBuild">
<!-- TODO : Unit Test -->
<Exec
Command="YourUnitTest1.exe"
WorkingDirectory="$(SRC_ROOT)\YourUnitTestProject\bin\%(AllConfigurations.Identity)"
/>
</Target>
<Target Name="Clean">
<MSBuild
Projects="@(SolutionToBuild)"
Targets="Clean"
Properties="Configuration=%(AllConfigurations.Identity)" />
</Target>
</Project>
view raw BuildAll.proj hosted with ❤ by GitHub
And time to write a simple batch file that can kick off the build process. Refer below BuildAll.bat.

@echo off
@SET TARGET=%1
if "x%1"=="x" SET TARGET=FullBuild
msbuild BuildAll.proj /t:%TARGET%
view raw BuildAll.bat hosted with ❤ by GitHub
Note that this BuildAll.bat can be used in the command line with vcavr32.bat set. Command window can have below setting.
Target:
%windir%\System32\cmd.exe /K cd /d "C:\YourBuildRoot" & %comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat"" x86
Start in:
C:\YourBuildRoot
This way of making build process doesn't ask for any other tools. Just Visual Studio - demonstrated in here with 2010 - is enough and can be extended to various ways without much effort and learning.

No comments: