Can SonarScanner for MsBuild scan TSQL - sonarqube

I have SonarQube installed and we are trying to run it on a product that contains the following code types
Javascript
VBScript
XML
C#
VB.net
T/SQL
Now we have got it running to scan all the code apart from the T/SQL code.
This TSQL code sits under the same directory as all the other code but doesn't have a specific visual studio project.
The only way we have been able to run a scan on the SQL is using the standard sonarqube runner, but that causes a new product to be created on our dashboard.
Any thoughts or suggestions.

Currently, if you want the TSQL files to be analyzed and appear under the same SonarQube project as the other code you will need to reference it from an MSBuild project.
There are a couple of ways you could do this:
1) include the TSQL files in one of your existing projects using a snippet like the following:
<ItemGroup>
<!-- Include additional files that should be analyzed by the SonarScanner for MSBuild -->
<None Include="*.tsql" >
<!-- Don't show the items in the Solution Explorer -->
<Visible>False</Visible>
</None>
</ItemGroup>
2) Create a separate dummy MSBuild project whose only purpose is to specify the additional files to be analyzed. This is slightly more complicated as the dummy project needs some additional content to make it work with the SonarScanner for MSBuild targets.
The following template works with v4.3 of the scanner, and should work with recent previous versions too.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- The only purpose of this project is to specify additional files to be analyzed by the SonarScanner for MSBuild -->
<!-- 1. Set a unique GUID id for the project -->
<PropertyGroup>
<ProjectGuid>{EA2BAA27-D799-4FBE-9430-7499ACF3E431}</ProjectGuid>
</PropertyGroup>
<!-- 2. Specify the files to be analysed -->
<ItemGroup>
<SonarQubeAnalysisFiles Include="**\*.js" />
</ItemGroup>
<!-- ******************************************************** -->
<!-- Boilerplate - no need to change anything below this line -->
<!-- ******************************************************** -->
<!-- Import the SQ targets (will only exist if the scanner "begin" step has been executed) -->
<PropertyGroup>
<SQImportBeforeTargets>$(localappdata)\Microsoft\MSBuild\$(MSBuildToolsVersion)\Microsoft.Common.targets\ImportBefore\SonarQube.Integration.ImportBefore.targets</SQImportBeforeTargets>
</PropertyGroup>
<Import Condition="Exists('$(SQImportBeforeTargets)')" Project="$(SQImportBeforeTargets)" />
<!-- Re-define the standard step of targets used in builds -->
<Target Name="Build" />
<Target Name="Clean" />
<Target Name="CoreCompile" />
<Target Name="Rebuild" DependsOnTargets="Clean;Build" />
<!-- Re-define one of the standard SQ targets as we have already set the list of files to analyze above -->
<Target Name="CalculateSonarQubeFilesToAnalyze" >
<PropertyGroup>
<!-- Set a property indicating whether there are any files to analyze -->
<AnalysisFilesExist Condition=" #(SonarQubeAnalysisFiles) != '' ">true</AnalysisFilesExist>
</PropertyGroup>
</Target>
</Project>

Related

Visual Studio project with a custom build step only (no default build)

I want to create a Visual Studio project that would allow me to see a bunch of JavaScript and other files and edit them as normal, but would also have a build step that can run any custom commands I want (currently some npm commands, possibly more later). Basically I want 3 features combined:
Be able to browse and edit files just like for any VS project (C#, C++, etc.)
Be able to run a custom build step by selecting "Build" in Visual Studio (including building the whole solution).
Be able to run that same custom build step from the command line (MSBuild).
Using a "shared project" (.shproj) allows me to easily see and edit the files, but there is no Build item in the context menu, even if I manually add a Build target:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>...</ProjectGuid>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
<Import Project="MyItems.projitems" Label="Shared" />
<PropertyGroup>
<Configuration>Debug</Configuration>
<Platform>Any CPU</Platform>
</PropertyGroup>
<Target Name="Build">
<Exec Command="ECHO My custom build!" />
</Target>
</Project>
I've also tried using a stripped-down VC++ project (since I don't actually want to run the C++ compiler) and this allows a build to be run from VS, but opening the project logs warnings like error MSB4057: The target "GetProjectDirectories" does not exist in the project. and trying to add files to fails with that error or similar ones.
There must be an easier way to do this!
From your current description, I think you want to create a js project in VS IDE.
However, VS IDE has the node js project template by default. And you should install the workload Node.js development under VS_Installer so that you can use it.
After that, you can create such project.
1) Adding js files or other files by right-click on the project-->Add-->Existing Item so that you can modify the files on VS IDE.
2) If you want to execute a custom build step that does not break the whole build, you should make the custom target depends on the default build.
You can use this:
<Target Name="CustomStep" AfterTargets="Build">
<Exec Command="ECHO My custom build!" />
</Target>
or
<Target Name="CustomStep" BeforeTargets="Build">
<Exec Command="ECHO My custom build!" />
</Target>
Note: If you use
<Target Name="Build">
<Exec Command="ECHO My custom build!" />
</Target>
It will overwrite the system build process and instead, run the command, which breaks the whole default build.
3) If you want to execute the custom build on msbuild command, you should specify the name of the custom target:
msbuild xxx\xxx.proj -t: CustomStep(the name of the custom target)
===============================================
Besides, if you still want to use C++ project template, you could create a empty c++ project which does not contain any clcompile files and then do the same steps.
If you do not want to use C++ compiler, you should only remove any xml node on the vcxproj file like these:
<ClCompile Include="xxx.cpp" />
<ClInclude Include="xxx.h" />
When you use the empty C++ project, you do not have to worry about that.
=========================================
Update 1
If you want to build this project on a build sever without VS IDE, I suggest you could install Build Tool for VS2019 which is an independent, lightweight build command line(It is equivalent to dotnet cli).
Build Tool for VS2019
Under All Downloads-->Tools for Visual Studio 2019--> Build Tools for Visual Studio 2019
Then, you have to install the related build workload such as Node.js Build tools and then we can use the command line to build node.js project on build sever.
The entire installation process is fast.
Inspired by Perry Qian-MSFT's answer, I managed to strip down a Node.js project to the bare minimum that I needed to get Visual Studio to load and build it, but without referencing any external files.
The main trick was VS needs a target named "CoreCompile" to be defined to show the Build menu item! (It also needs a "Build" target, but that one is more obvious.)
My project now looks like this:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>(some guid)</ProjectGuid>
<ProjectHome>.</ProjectHome>
<ProjectTypeGuids>{3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}</ProjectTypeGuids>
</PropertyGroup>
<!-- These property groups can be empty, but need to be defined for VS -->
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
</PropertyGroup>
<Import Project="My.Build.targets" />
<!-- Define empty standard MSBuild targets, since this project doesn't have them. Doing it this way allows My.Build.targets to also be used in a project that does define them. -->
<Target Name="Build" />
<Target Name="ReBuild" />
<Target Name="Clean" />
<!-- NOTE: a target named "CoreCompile" is needed for VS to display the Build menu item. -->
<Target Name="CoreCompile" />
<!-- Files shown in Visual Studio - adding and removing these in the UI works as expected -->
<ItemGroup>
<Content Include="myfile..." />
</ItemGroup>
</Project>
And My.Build.targets looks like this:
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="MyBuild" AfterTargets="Build">(build steps)</Target>
<Target Name="MyReBuild" AfterTargets="ReBuild">(re-build steps)</Target>
<Target Name="MyClean" AfterTargets="Clean">(clean steps)</Target>
<!-- This target is needed just to suppress "warning NU1503: Skipping restore for project '...'. The project file may be invalid or missing targets
required for restore." -->
<Target Name="_IsProjectRestoreSupported" Returns="#(_ValidProjectsForRestore)">
<ItemGroup>
<_ValidProjectsForRestore Include="$(MSBuildProjectFullPath)" />
</ItemGroup>
</Target>
</Project>

How to build code using MSBuild.exe from comand line without Visual Studio

Can you please explain step by step how to build code using command line without Visual Studio and generate DLL?
I am using Visual Studio 2010 SP1. I need sample file(.sln,.csproj) which is going to using with MSBuild and need command that I can compile code without Visual Studio and generate DLL.
Finally I got the solution.
Please do following steps to generate DLL from xml file without having Visual Studio IDE.
Basically, we require only two types files
1. class file like Helloworld.cs , Welcome.cs
2. XML file
Here below is the format of XML file which helps to generate DLL file
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<!-- Generate DLL/Assembly Name -->
<AssemblyName>MSBuildSample</AssemblyName>
<OutputPath>Bin\</OutputPath>
<OutputType>Library</OutputType>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data.Linq" />
</ItemGroup>
<ItemGroup>
<!-- Mentioned here class file to compile -->
<Compile Include="Helloworld.cs" />
<Compile Include="Welcome.cs" />
<!-- <Compile Include="C:\testing\test.Designer.cs" />
<EmbeddedResource Include="C:\testing\test.resx" /> -->
</ItemGroup>
<Target Name="Build">
<Csc Sources="#(Compile)"
Resources="#(EmbeddedResource)"
References="#(Reference)"
TargetType="library"
OutputAssembly="C:\testing\test.dll" />
</Target>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
Save this file as MSBuild.xml in same folder where your class file reside and then you need to run following command from Command Line
MSBuild.exe MSBuild.xml /property:Configuration=Debug
This will helps you to compile and generate DLL from XML file without having Visual Studio.
This is very basic .xml file but you can complie and generate dll file from your project file (.csproj) file too. You just need to add following lines if not exists in that .csproj file.
<PropertyGroup>
<OutputType>Library</OutputType>
<OutputPath>Bin\</OutputPath>
</PropertyGroup>

How can I apply configuration transforms to EntLib.config?

I had a large Silverlight project with an unwieldy web.config, which used transforms against the web.debug.config, web.uat.config, and web.release.config files.
I've not separated out my EntLib configuration into EntLib.config, with matching EntLib.debug.config, EntLib.uat.config and EntLib.release.config files. I've edited the .csproj file and used DependentUpon so that the files are nested under EntLib.config. Now I'm trying to get VS2010 to apply the transforms when I use the Publish... menu option to publish the files straight to the test server.
I've been trying to apply this as shown below but it doesn't seem to work. I can see the transformed EntLib.config file in obj\$(Configuration)\TransformWebConfig\transformed but it isn't deployed. I've also tried using Project > Build Deployment Package which I've then run on another machine. Both leave me with EntLib.config in its original form plus each of the EntLib.($Configuration).config files alongside it. Should it work? Any help anyone can offer would be appreciated.
<PropertyGroup>
<ConfigFileName>EntLib.config</ConfigFileName>
</PropertyGroup>
<PropertyGroup>
<!-- This property is used to handle circular dependency between
TransformWebConfig and our custom target TransformAppConfig -->
<FirstRun Condition="$(FirstRun) == ''">true</FirstRun>
</PropertyGroup>
<!-- This target will be called one time after a call to TransformWebConfig -->
<Target Name="TransformAppConfig" AfterTargets="TransformWebConfig" Condition="$(FirstRun) == 'true'">
<MSBuild Projects="$(MSBuildProjectFile)" Targets="TransformWebConfig" Properties="ProjectConfigFileName=$(ConfigFileName);
Configuration=$(Configuration);
FirstRun=false" />
</Target>
<!-- This target will be called one time before PreAutoParameterizationWebConfigConnectionStrings
to add $(ConfigFileName) to autoparameterization step -->
<Target Name="AddToAutoParameterizationStep" BeforeTargets="PreAutoParameterizationWebConfigConnectionStrings">
<ItemGroup>
<_WebConfigsToAutoParmeterizeCS Include="#(FilesForPackagingFromProject)" Condition="('%(FilesForPackagingFromProject.Filename)%(FilesForPackagingFromProject.Extension)'=='$(ConfigFileName)') And !%(FilesForPackagingFromProject.Exclude)">
<TransformOriginalFile>$(AutoParameterizationWebConfigConnectionStringsLocation)\original\%(DestinationRelativePath)</TransformOriginalFile>
<TransformOutputFile>$(AutoParameterizationWebConfigConnectionStringsLocation)\transformed\%(DestinationRelativePath)</TransformOutputFile>
<TransformScope>$(_PackageTempDir)\%(DestinationRelativePath)</TransformScope>
</_WebConfigsToAutoParmeterizeCS>
<_WebConfigsToAutoParmeterizeCSOuputFiles Include="#(_WebConfigsToAutoParmeterizeCS->'%(TransformOutputFile)')">
</_WebConfigsToAutoParmeterizeCSOuputFiles>
</ItemGroup>
</Target>
I use T4 and TextTransform.exe to create different configs based on build configuration. You can take a look on my snippets for app.config, but the same technique can be applied for web.config.
1) Project structure
ProjectDir
App_Config
Configuration.tt // template for all configs
Debug.App.tt // settings for Debug
Release.App.tt // settings for Release
ProductDeploy.App.tt // settings for deploy
App.config // autogenerated. Ignored in SVN
project.csproj
2) project.csproj modification allows to have up-to-date config for specified Platform/Configuration.
<PropertyGroup>
<T4Template>$(ProjectDir)\App_Config\$(Configuration).App.tt</T4Template>
<T4CommonTemplate>$(ProjectDir)\App_Config\Configuration.tt</T4CommonTemplate>
<T4Config>$(ProjectDir)\App.config</T4Config>
<T4LastConfiguration>$(BaseIntermediateOutputPath)\$(Configuration).t4lastbuild</T4LastConfiguration>
</PropertyGroup>
<Target Name="BeforeBuild" DependsOnTargets="ExecuteT4Templates" />
<Target Name="ExecuteT4Templates" Inputs="$(T4Template);$(T4CommonTemplate);$(T4LastConfiguration)" Outputs="$(T4Config)">
<MakeDir Directories="$(BaseIntermediateOutputPath)" Condition="!Exists('$(BaseIntermediateOutputPath)')" />
<ItemGroup>
<T4ConfigFlags Include="$(BaseIntermediateOutputPath)\*.t4lastbuild" />
</ItemGroup>
<Delete Files="#(T4ConfigFlags)" />
<WriteLinesToFile File="$(T4LastConfiguration)" Lines="T4 Succeeded" Overwrite="true" />
<Exec Command="TextTransform "$(T4Template)" -out "$(T4Config)"" WorkingDirectory="C:\Program Files\Common Files\microsoft shared\TextTemplating\1.2\" />
</Target>
<Target Name="AfterClean">
<ItemGroup>
<T4ConfigFlags Include="$(BaseIntermediateOutputPath)\*.t4lastbuild" />
</ItemGroup>
<Delete Files="#(T4ConfigFlags)" />
</Target>
3) Configuration.tt sample
<## template language="C#"#>
<## output extension= ".config"#>
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
<add name = "NameSpace.Properties.Settings.SomeConnectionString"
connectionString = "<#= this.SomeConnectionString #>"
providerName = "System.Data.SqlClient" />
</connectionStrings>
<applicationSettings>
<NameSpace.Properties.Settings>
<setting name="DefAppSetting" serializeAs="String">
<value><#= this.DefAppSetting #></value>
</setting>
</NameSpace.Properties.Settings>
</applicationSettings>
</configuration>
<#+
string SomeConnectionString = "default SomeConnectionString";
string DefAppSetting = "some_value";
#>
4) Debug.App.tt sample
<#
SomeConnectionString = "Data Source=.;Initial Catalog=SomeDB;Integrated Security=True";
DefAppSetting = "debug_some_value";
#>
<## include file="Configuration.tt" #>
I solved this using this article: Xml Document Transforms (XDT) for any XML file in your project by Vishal Joshi and posted the specifics here: How to apply transforms to EntLib.config.
My own solution followed Vishal's option to store his XDT targets file in the project so that it gets stored in source control and is available to everyone, rather than storing it locally on the machine.

How to use the new VS 2010 configuration transforms and apply them to other .config files?

I have setup some configuration transforms in my web.config for my connectionStrings, etc. But I have separated out some areas of my web.config into separate files, ex) appSettings.config.
How can I configure Visual Studio and MSBuild to perform config transformations on these additional config files?
I have already followed the approach of the web.config to relate the files together within my web application project file, but transformations are not automatically applied.
<ItemGroup>
<Content Include="appSettings.Debug.config">
<DependentUpon>appSettings.config</DependentUpon>
</Content>
</ItemGroup>
By default the target managing the transformation (TransformWebConfig) works only on web.config file.
To make it work on your appSettings.config file you'll have to :
Set the Build Action of your file to Content
Call the MSBuild target TransformWebConfig with ProjectConfigFileName=appSettings.config and Configuration=$(Configuration).
To call MSBuild TransformWebConfig target for appSettings.config just after the transformation of web.config files, you need to add this at the end of your project file :
<PropertyGroup>
<!-- Name of your custom config file -->
<ConfigFileName>appSettings.config</ConfigFileName>
</PropertyGroup>
<PropertyGroup>
<!--
This property is used to handle circular dependency between
TransformWebConfig and our custom target TransformAppConfig
-->
<FirstRun Condition="$(FirstRun) == ''">true</FirstRun>
</PropertyGroup>
<!-- This target will be called one time after a call to TransformWebConfig -->
<Target Name="TransformAppConfig"
AfterTargets="TransformWebConfig"
Condition="$(FirstRun) == 'true'">
<MSBuild Projects="$(MSBuildProjectFile)"
Targets="TransformWebConfig"
Properties="ProjectConfigFileName=$(ConfigFileName);
Configuration=$(Configuration);
FirstRun=false"/>
</Target>
<!--
This target will be called one time before PreAutoParameterizationWebConfigConnectionStrings
to add $(ConfigFileName) to autoparameterization step
-->
<Target Name="AddToAutoParameterizationStep"
BeforeTargets="PreAutoParameterizationWebConfigConnectionStrings">
<ItemGroup>
<_WebConfigsToAutoParmeterizeCS Include="#(FilesForPackagingFromProject)"
Condition="('%(FilesForPackagingFromProject.Filename)%(FilesForPackagingFromProject.Extension)'=='$(ConfigFileName)') And !%(FilesForPackagingFromProject.Exclude)">
<TransformOriginalFile>$(AutoParameterizationWebConfigConnectionStringsLocation)\original\%(DestinationRelativePath)</TransformOriginalFile>
<TransformOutputFile>$(AutoParameterizationWebConfigConnectionStringsLocation)\transformed\%(DestinationRelativePath)</TransformOutputFile>
<TransformScope>$(_PackageTempDir)\%(DestinationRelativePath)</TransformScope>
</_WebConfigsToAutoParmeterizeCS>
<_WebConfigsToAutoParmeterizeCSOuputFiles Include="#(_WebConfigsToAutoParmeterizeCS->'%(TransformOutputFile)')">
</_WebConfigsToAutoParmeterizeCSOuputFiles>
</ItemGroup>
</Target>
Something that makes this a lot easier, take a look at the SlowCheetah VS add-in at ... visualstudiogallery
Here is the code that works for me:
<PropertyGroup>
<!-- Name of your custom config file -->
<ConfigFileName>ConnectionStrings.config</ConfigFileName>
<ConfigTransformFileName>ConnectionStrings.$(Configuration).config</ConfigTransformFileName>
</PropertyGroup>
<PropertyGroup>
<!--
This property is used to handle circular dependency between
TransformWebConfig and our custom target TransformAppConfig
-->
<FirstRun Condition="$(FirstRun) == ''">true</FirstRun>
</PropertyGroup>
<Target Name="AddConfigToTransform" AfterTargets="CollectWebConfigsToTransform">
<ItemGroup>
<WebConfigsToTransform Include="#(FilesForPackagingFromProject)" Condition="'%(FilesForPackagingFromProject.Filename)%(FilesForPackagingFromProject.Extension)'=='$(ConfigFileName)'">
<TransformFile>%(RelativeDir)$(ConfigTransformFileName)</TransformFile>
<TransformOriginalFile>$(TransformWebConfigIntermediateLocation)\original\%(DestinationRelativePath)</TransformOriginalFile>
<TransformOutputFile>$(TransformWebConfigIntermediateLocation)\transformed\%(DestinationRelativePath)</TransformOutputFile>
<TransformScope>$([System.IO.Path]::GetFullPath($(_PackageTempDir)\%(DestinationRelativePath)))</TransformScope>
</WebConfigsToTransform>
</ItemGroup>
</Target>
<!--
This target will be called one time before PreAutoParameterizationWebConfigConnectionStrings
to add $(ConfigFileName) to autoparameterization step
-->
<Target Name="AddToAutoParameterizationStep" BeforeTargets="PreAutoParameterizationWebConfigConnectionStrings">
<ItemGroup>
<_WebConfigsToAutoParmeterizeCS Include="#(FilesForPackagingFromProject)" Condition="('%(FilesForPackagingFromProject.Filename)%(FilesForPackagingFromProject.Extension)'=='$(ConfigFileName)') And !%(FilesForPackagingFromProject.Exclude)">
<TransformOriginalFile>$(AutoParameterizationWebConfigConnectionStringsLocation)\original\%(DestinationRelativePath)</TransformOriginalFile>
<TransformOutputFile>$(AutoParameterizationWebConfigConnectionStringsLocation)\transformed\%(DestinationRelativePath)</TransformOutputFile>
<TransformScope>$(_PackageTempDir)\%(DestinationRelativePath)</TransformScope>
</_WebConfigsToAutoParmeterizeCS>
<_WebConfigsToAutoParmeterizeCSOuputFiles Include="#(_WebConfigsToAutoParmeterizeCS->'%(TransformOutputFile)')">
</_WebConfigsToAutoParmeterizeCSOuputFiles>
</ItemGroup>
</Target>

When & How to use ILMerge with Visual Studio Project / Solution

I'm developing a medium sized enterprise application.
There are many projects / solutions to this.
For example:
Company.Data
Company.Data.LinqToSql
Company.Entities (business objects)
Company.BLL
I then have some applications - for example a windows service:
MyWindowsService.
When i deploy this (by creating a setup project) it installs a load of DLL's from the output of the above mentioned projects.
Is this where i should be using ILMerge? to create one assembly.... Company.dll for example?
How would i go about integrating this into my build process?
The question ILMerge Best Practices
has good info on why.
When I use ILMerge, I use it to build a single DLL, to simplify deployment.
As to How, I define a separate, custom VS project, "Converged.csproj" if you like. In that .csproj file I define a custom Compile target. It is boilerplate code, that performs an ILMerge on all the referenced assemblies for the project.
It looks like this:
<Target Name="Compile">
<!-- Outputs="$(IntermediateOutputPath)$(TargetFileName)" -->
<!-- Outputs="$(TargetPath)" -->
<Message Text="Performing the Ilmerge." />
<!-- in this CreateItem stanza, we collect all the DLLs for the referenced projects -->
<CreateItem Include="#(_ResolvedProjectReferencePaths)">
<Output TaskParameter="Include" ItemName="AssembliesToMerge" />
</CreateItem>
<!-- This weird bit of hieroglyphics is the assemblies to merge, quoted, and separated by spaces -->
<!-- Example: "c:\foo\project1\bin\Debug\ProjectOne.dll" "c:\foo\project2\bin\Debug\ProjectTwo.dll" -->
<Message Text="AssembliesToMerge= #(AssembliesToMerge -> '"%(Fullpath)"', ' ')" />
<!-- Message Text="TargetPath= $(TargetPath)" / -->
<Message Text="TargetFileName= $(TargetFileName)" />
<!-- produce the merged assembly - putting the output in the "IntermediateOutputPath" eg obj\Debug. -->
<!-- it will be copied later by the CopyFilestoOutputDirectory task defined in Microsoft.Common.Targets -->
<Error
Text="ILMerge cannot be found. You need to download and install ILMerge in order to build DotNetZip."
Condition="!Exists('$(ProgramFiles)\Microsoft\Ilmerge\Ilmerge.exe')" />
<Exec Command=""$(ProgramFiles)\Microsoft\Ilmerge\Ilmerge.exe" /t:library /xmldocs /out:"$(IntermediateOutputPath)$(TargetFileName)" #(AssembliesToMerge -> '"%(Fullpath)"', ' ') " />
<!-- for some reason the XML doc file does not get copied automatically from obj\Debug to bin\Debug. -->
<!-- we do it here explicitly. -->
<Copy SourceFiles="$(IntermediateOutputPath)$(AssemblyName).XML" DestinationFolder="$(OutDir)" SkipUnchangedFiles="true" OverwriteReadOnlyFiles="$(OverwriteReadOnlyFiles)" />
</Target>

Resources