build and deployment automation for msbuild EXE projects - continuous-integration

I'm working on some automated build changes and have some questions as to the best approach for building/packaging EXE applications.
Conceptually, there are two scripts. The first builds everything at puts the resulting binaries on a share so they are available for deployment. The second set of scripts are each responsible for copying and configuring some application from that build result.
The first script, which builds the entire solution, copies the build result to known pickup location by overriding the msbuild output path. This causes binaries for all to be dropped in the same folder (except web applications, where each project is in its own website under _PublishedWebsites). This is problematic as when I build an installer for a single EXE project, I only want to include the EXE and dependencies of that EXE. However since all project outputs are in the same folder then it is not clear which are needed by the individual application.
Given that the build has put the binaries for all the executables in one folder, how can I build an MSI that only includes the binaries needed for a particular EXE?
I am using psake/powershell for the build scripts, using msbuild to compile the solution files. I am using WixSharp the build the installer from a command-line app (not CSC).

SUMMARY
Since Wix# actually builds the MSI when you "run" the .exe it creates, and uses the WiX toolkit, you would need to output the executable Wix# + WiX Toolkit creates to your drop folder. Then make sure the WiX toolkit executable files are either on your PATH or in your output folder, and create Powershell script(s) that invoke your Wix# executable(s) in the drop folder. One straightforward approach would be to have one Wix# project for each separate "product installer", and have each these Wix# executables be output to your drop folder, for further processing/generation of the MSI files by your downstream Powershell (or other) scripts.
I am using Wix# integrated into the VS2013 IDE, so my answer should be interpreted in that context. My Wix# installer is simply one project of several in my overall solution.
EXAMPLE FOR A SINGLE Wix# PROJECT IN A VISUAL STUDIO SOLUTION
So, for example, if your Wix# project code file is set up in VS as a project named named MyWebsiteSetup, and the Wix# code file is MyWebsiteSetup.cs, your Wix# executable will be located at \MyWebsiteSetup\bin\debug\MyWebsiteSetup.exe.
Have the build place this MyWebSiteSetup.exe file in the drop folder, along with the other files Wix# places in bin\debug folder. Then have your second set of scripts run the MyWebsiteSetup.exe program, which will generate the MSI. I believe you may need to have the installation component files the Wix# code requires be deployed to the drop folder as well, and in the expected folder structure. Wix# seems to place all the other support files it needs in the bin\debug folder, so just having all the files copied from the Wix# project's bin\debug to the drop folder should get you what you need.
ADAPTING THE EXAMPLE TO MULTIPLE PRODUCTS (MULTIPLE Wix# PROJECTS)
Now, your question was how to do this for multiple websites where all the files are placed in the same drop folder. There are several ways to approach this, but the one I suggest is to have a separate Wix# project in Visual Studio for each separate product, and have the Wix# output files for each of those projects deployed to the drop folder along with the product files. If your separate products were named MyWebSiteSetupA, MyWebSiteSetupB, and MyWebSiteSetupC, they will generate executables MyWebSiteSetupA.exe, MyWebSiteSetupB.exe, and MyWebSiteSetupC.exe. You would simply have your second set of scripts invoke each of those in turn. Each of the Wix# code files (.cs files) for those projects of course will have been coded to know what files it needs to pick up when it runs, and when the resulting exe is run, it will get the files it needs, provided you've made them available where expected, and build the individual MSI's for each product's installer.
There are of course, numerous other approaches for this, with flexible tools like PowerShell, each approach with pros and cons, but I hope this helps get you started with an approach you can then tailor to your needs.

Related

Cannot include duplicate files in msi installer

I'm using Windows 7 64, VS 2013.
I'm trying to create an MSI installer that contains 2 C# applications distributed in 2 different folders, both folders are containing 1 DLL file that is the same. I am adding all necessary dependencies, everything seems fine, but after installing, one of the applications throws an error regarding loading of that DLL.
My assumption is that the VS installer project keeps the files in a common folder and when it sees the same file it automagically refers both application to use the same exact DLL.
My work-around for this problem is to rename the DLL when adding it into installer project and make a small .bat script that renames the DLL after installation. This works, but I'm guessing there's a more elegant way to do it besides having scripts run at install/uninstall time that will rename some DLLs.
Strictly speaking, Windows Installer has something called the component rules. One aspect of this is that a given file in a given folder can only belong to one component. The same files in two different folders would be two different components because a component can only define files for one folder.
WiX creates MSI and has a feature called smart cabbing where the file would be normalized when compressed into a cab and embedded into the MSI.
Visual Studio installer projects are of very low quality and will killed by Microsoft before being brought back to live as an add on. It has horrible dependency scanning and you are finding that the "automagical" behavior doesn't work very well.

How to include arbitrary files in a .NET setup project

We have a folder of text files that needs to be copied to the server whenever our application is deployed. Currently, we handle this by manually copying/pasting the folder's contents.
How can I include this as an automated step in the MSI?
I want the folder (and it's contents) to be included in the MSI. Then, on install, I want to the files in the MSI to overwrite the existing files (in a given local directory).
The files are in source control (TFS), but they are not part of any .NET project.
I've used the Nullsoft Installer before (among others), and that's basically all it does (you tell it what files to pull in and where to put that at install time). Visual Studio automates a lot of this... but I just can't see where to do the basic task.

TFS 2010 build cannot handle custom MSBuild script which generate multiple files in multiple directories

I have a custom MSBuild script (e.g. WpfResources.proj), in which I scan through multiple folders for *.resx files anc build .NET satellite resource dlls using the AL task. The output of this WpfResources.proj contain multiple *.resources.dll under different folders (corresponding to different projects which will need these resource dlls).
The example output folder structure is shown as following:
WpfResources
Bin
Project1
zh-CN
Project1.resources.dll
es-ES
Project1.resources.dll
...
Project2
zh-CN
Project2.resources.dll
es-ES
Project2.resources.dll
...
This WpfResources.proj can be built correctly by MSBuild.exe. However if I run it in TFS 2010 build (i.e. create a build definition and refers to the WpfResources.proj to build), it failed to copy all those resource dlls into the drop location. Actually it outputs nothing to the drop location even though on the actual build PC, the output is fine.
How can TFS 2010 build handle custom MSBuild scripts which output multiple files under multiple folders? Is there something missing in my WpfResources.proj which the Team build will consider as outputs of this MSBuild project?
On a build system, TFS handles the binary output directory and the copying of its output to a drop folder a bit special. It generates a central output directory for all output files.
I would imagine that your MSBuild project does output the standard way as if it were on a development system, with output bins under the project folder structure. TFS will not copy them to the drop folder, because by default, it only copies the binaries it produced under the central output folder.
For our systems, we solved the issue (that also goes for building VS Setup projects) but having a manual copy action embedded in the build template that copies the MSBuild output to either the centralized bin output folder, or directly towards the drop folder location.
For adding such a custom action, please see the fine TFS2010 customization blog of Ewald Hofman at: http://www.ewaldhofman.nl/post/2010/04/29/Customize-Team-Build-2010-e28093-Part-4-Create-your-own-activity.aspx.
Hope that helps.

Where should i put dll file(that i use in my project)

Im setting up a svn repository and wondering where i should put the dll files.
What Ive currently done is put them in the /bin/debug folder and then link them in my project file in visual studio.
is this the way to do it?
I presume you are asking about third party dll files, because the output (exe/dll) files generated by the project are better left unmanaged by SVN, because they are regenerated on each and every build.
What I usualy do is create a Lib folder, that is on the top level of my source tree, and put all needed references there, usually in additional folder divided by tool or by functionality (logging, emailing, apis, etc, etc...)
You should not put anything from the bin/Debug or bin/Release in your source control. If you do that, you will lose them when you clean your solution or your projects.
What you have to do is create a folder, within the solution folder for example, and reference the dlls in your projects. Any third-party dll that is in the references of a project will be copied to the bin/Debug or bin/Release folder when the project is compiled.
We typically have a seperate folder called dlls or something where we keep all 3rd party dlls/assemblies
Dlls are only needed at runtime. For a quick fix, you may copy your dlls in the Debug folder where your .exe file is. This Debug folder is at the same level as the solution .sln file in Visual Studio. Which thing you will have to do each time you start a new project... Debug folder
A better solution would be to copy all third party dlls, plus all the corresponding .h and .lib files, in 2 folders, say C:\dev\include and C:\dev\lib, and then add these 2 folders to your path environment variable once for all. This way, you'll be able to access them from all your projects, without having to copy them over and over.
Now, if you want someone to be able to run your project on another computer, you'll need to copy all needed .h, .lib and .dll files in your project in a separate folders that you create, say include and lib again, in your project directory where your own program files are, as mentioned in the previous posts. Project folder
PS. Sorry, it would not let me upload the 2 screenshots, so click on links.
I typically put it in a Lib folder within my Visual Studio project solution folder. I would also create sub folders all the way to indicate whether the dll is for a 32 bit or 64 bit build and also which version of Visual Studio was used to build it. So something like this: Lib\WIN32\VC2015\ . Then in the Project Properties of the project, under the Debugging Configuration Property, I set Environment to
PATH=$(SolutionDir)Lib\WIN32\VC2015;%PATH%
By doing this, I can have separate dll folders for different project configurations if I want to and also the dll files are in a good place to check into source control as well.

How do I get the lowest level project from a solution for build purposes?

If I have a visual studio solution with a multiple projects, from the projects how do I figure out which one will have all the dlls once the solution is built?
The reason is I need to copy those dll's for my custom written build app. I know in the Visual studio GUI, if I right click on the solution and go to Project Build Order, the lowest level item will be the project which will have the complete list of built dll's and referenced dll's. So is there any logic I can use to work this out through code?
You could write some code to read the solution / project files (the formats are not hard) and work out the dependency tree yourself.
However, a better approach is to change all the projects to output to a common \bin directory to start with by altering the build properties in Visual Studio. This avoids you having numerous copies of binaries in various individual project bin directories and makes life easier when it grows to a size where you need to split into multiple solutions.
A directory structure something like the following is often useful:
\bin (Common output directory for all projects)
\src (I usually keep the solution file in \src)
\ProjectA
\ProjectB
\lib (Common libraries, e.g. nunit or log4net etc)

Resources