As the title says, I want to output 2 .msi files from one project (one is per-user, and the other is per-machine). I have seen in this thread that it can't be done in some conventional way, but perhaps there is a way to do so as some kind of hack in post-build.
I only need to rerun compilation and linking after the original build with slightly changed command line (actually, I need only different Product.wxs file). However, my light and candle command lines are huge, and I would risk making my project hard to maintain if I would hard-code them.
So, in conclusion, I need to know if there is a way to write a command line that would behave the same as Votive does when creating its build command line (getting all the files in project, linking them, passing project dependencies...), only in post build.
P.S.: I also had an idea of getting the whole command line from Votive, and only changing the Product file, that would also help, so if someone has suggestion on how to do it...
Create multiple configurations of your solution / project and set a preprocessor variable to some value for one of the configurations. In your wix source, conditionally include whatever else it is that needs included based on your preprocessor variable.
Related
My colleagues and I have user specific settings in csproj.user files. They are not checked into the repository. I would like for the build server to use its own set of csproj.user files, overriding certain properties, leaving the "base" project configuration at a decent developer default. But from the looks of it there is no such option in the msbuild command-line for doing that.
Is there really no way, other than copy csproj.user-files to where it'll be picked up by subsequent msbuild invocations?
While writing I realize I'm too much of a prude about these things and should just copy as a step prior build. Still posting in case someone knows a better way, for instance a way that does not modify the source tree.
Passing properties to the MSBuild command line overrides properties in the solution, including dependent projects. Here omitting debug information in build server, otherwise generated for release build to improve profiling:
msbuild MySolution.sln /p:DebugType=none ...
This does not work should I want different properties for different projects. Building projects individually should work nicely though.
Finally, passing arguments on command line can get messy, so to get a more "settings file"-like experience one may instead use #file arguments and MSBuild response files.
Situation: An application, that is built into several variations, with different functionality enabled. Each variation has its own main project, with its own output "bin" folder. Call the variations A and B.
There are various common class libraries, which generate dlls. Those all get automatically copied to both output folders. This is working fine.
Now, add another project. It generates an exe, C.exe. It will be loaded as a separate process by the application. (It creates a NamedPipe, providing a ServiceContract via NetNamedPipedBinding.)
When there was only "A" (no "B"), I simply had A and C specify the same output folder.
But now there are TWO places that C needs to go.
For Debug build, must go to A/bin/Debug and B/bin/Debug. Similar for Release build.
The source language is VB, but an answer based on C# projects would almost certainly be adaptable to my situation.
I've written an answer by using XCopy in Post Build Events.
Looking for alternative answers.
Is there a way that is easier to maintain / not dependent on manually entering paths?
My concern is that as variants are added, or moved around, it is necessary to know about the Build Events and manually edit them.
Doing work for a company that is not great at keeping track of such details over the years.
Looking for a way that is less likely to break, or easier for a junior programmer to maintain.
In Project "C", Properties, Post Build Events, use xcopy to copy the .exe and corresponding .pdb. Do this for both the "Debug" configuration and the "Release" configuration of Project C.
(For VB, this is under Compile tab, "Build Events..." button at lower right.)
In project A's Properties, find what its output path is. in this case, the path specified was bin\x86\Debug\. xcopy needs to be told this path, relative to project A inside the solution; this becomes $(SolutionDir)\A\bin\x86\Debug\. The resulting lines, to copy both the exe and its pdb for debugging:
xcopy /y "$(ProjectDir)$(OutDir)*" "$(SolutionDir)\A\bin\x86\Debug\"
This copies ALL files in "C"s output folder to "A"s output folder.
Before adding this line, examine "C"s output folder. Are there any files in it that should not be copied to A? If so, can they be deleted? (And will they STAY deleted, when you rebuild "C"?) If not, you will need to specify more carefully the source files, in xcopy line. Or use multiple xcopy lines, to specify the individual files.
Note the "A", which is the main project being copied to.
Repeat that line for "B".
As more variants of main project are created, add a line for them as well.
If one project specifies a different output path, then the lines need to be correspondingly changed.
I'm developer on a big system (>100 Projects in Solution, >100 000 LOC, > 10 Services, ...) and did the installation of this system in the past with wix and it worked fine. Now I need a way to patch (Minor Upgrade) parts of the system and run into several issues.
My Current Wix Setup is as following:
I have VS2010 and Wix3.6 Toolset and TFS2012 to Build the whole thing and get an installer
I'm using a Setup Library Project Type per Service
I'm using exactly one Setup Project to bundle things together and get one installer for the whole system.
It's not possible to change this setup.
The Setup Library Projects are set up as following:
I use the heat-directory msbuild task to generate the components and files and I'm using preprocessor variables to modify the file paths.
I need to modify the file paths because it must be possible to build an installer on the local developer system and to build the installer on the tfs build system which is different in folder structures.
The TFS uses always the same directory to compile subsequent versions of the software and moves the output after successful compilation to a unique folder structure.
Now I need a patch.
I created the Patch.wxs and called candle and light for it. I called torch to get the difference file. And finally want to create the patch with pyro.
Everything worked fine with a simple testproject, but on the big system
Pyro has the problem that it can't find the files to install.
Through my setup (see above), I must use preprocessor variables and have a full qualified path in my wix output (for example: C:\builds\myproduct\prodct.exe as file source). After moving the TFS output to another location this path is not valid anymore. I tried to use -bt and -bu switches for pyro, but this does only work for relative paths or for named bindpaths.
Now I wanted to change my wix project setup to use named bindpaths rather than preprocessor variables, but it seems that this is not possible.
heat can only use preprocessor variables or wixvariables but it seems not to be possible to use bindpath variables. heat provides a switch -wixvar which should create binder variables instead of preprocessor variables but I does exactly nothing.
Now I tried do use no wix and no preprocessor variables in heat and tell light per -bu -bt switches where to find the files. But if I do not set a preprocessor variable the resulting files look like Sources\product.exe. I can't get rid of this Sources. I know that I can transform all the xml with xslt and remove the Sources but thats a workaround which I would only implement if no other solution is possible. This would also mean that there is a problem in the wix toolchain.
It looks like pyro does only support bindpath variables and heat does only support preprocessor and wix variables. This seems to be really crazy, because how should they work together?
How can I create a patch if I use lit, light, candle, heat, torch and pyro and if the original build paths have changed (which is very common on a build system) and the file paths are created with heat and therefore be fixed or preprocessor or wix variables?
As you've found heat wasn't designed to be used in the patching scenario. It was only in recent versions of the WiX toolset that the generated GUIDs got to a point where there was even a chance that heat could successfully build output that would be patchable. Still need to do work there to make patching where heat is used work well.
Ultimately, I believe the answer is to simplify the "original source" problem. It is challenging to get all the bindpaths set up correctly and that makes patching, which is a hard problem, even harder. We've kicked around a few ideas but nothing has come together yet.
You could always use admin image based patching. It's slower but can be easier to get the "original source" and "target" laid out. That path does lose filtering though.
Basically, we need to do a bit more work in patching scenarios to make it much easier.
PS: "Source" in the path for a File/#Source attribute is an alias for the "default bindpath". You can use bindpaths there.
I just joined a team that has no CI process in place (not even an overnight build) and some sketchy development practices. There's desire to change that, so I've now been tasked with creating an overnight build. I've followed along with this series of articles to: create a master solution that contains all our projects (some web apps, a web service, some Windows services, and couple off tools that compile to command line executables); created an MSBuild script to automatically build, package, and deploy our products; and created a .cmd file to do it all in one click. Here's a task that I'm trying to accomplish now as part of all this:
The team currently has a practice of keeping the web.config and app.config files outside of source control, and to put into source control files called web.template.config and app.template.config. The intention is that the developer will copy the .template.config file to .config in order to get all of the standard configuration values, and then be able to edit the values in the .config file to whatever he needs for local development/testing. For obvious reasons, I would like to automate the process of renaming the .template.config file to .config. What would be the best way to do this?
Is it possible to do this in the build script itself, without having to stipulate within the script every individual file that needs to be renamed (which would require maintenance to the script any time a new project is added to the solution)? Or might I have to write some batch file that I simply run from the script?
Furthermore, is there a better development solution that I can suggest that will make this entire process unnecessary?
After a lot of reading about Item Groups, Targets, and the Copy task, I've figured out how to do what I need.
<ItemGroup>
<FilesToCopy Include="..\**\app.template.config">
<NewFilename>app.config</NewFilename>
</FilesToCopy>
<FilesToCopy Include="..\**\web.template.config">
<NewFilename>web.config</NewFilename>
</FilesToCopy>
<FilesToCopy Include"..\Hibernate\hibernate.cfg.template.xml">
<NewFilename>hibernate.cfg.xml</NewFilename>
</FilesToCopy>
</ItemGroup>
<Target Name="CopyFiles"
Inputs="#(FilesToCopy)"
Outputs="#(FilesToCopy->'%(RootDir)%(Directory)%(NewFilename)')">
<Message Text="Copying *.template.config files to *.config"/>
<Copy SourceFiles="#(FilesToCopy)"
DestinationFiles="#(FilesToCopy->'%(RootDir)%(Directory)%(NewFilename)')"/>
I create an item group that contains the files that I want to copy. The ** operator tells it to recurse through the entire directory tree to find every file with the specified name. I then add a piece of metadata to each of those files called "NewFilename". This is what I will be renaming each file to.
This snippet adds every file in the directory structure named app.template.config and specifies that I will be naming the new file app.config:
<FilesToCopy Include="..\**\app.template.config">
<NewFilename>app.config</NewFilename>
</FilesToCopy>
I then create a target to copy all of the files. This target was initially very simple, only calling the Copy task in order to always copy and overwrite the files. I pass the FilesToCopy item group as the source of the copy operation. I use transforms in order to specify the output filenames, as well as my NewFilename metadata and the well-known item metadata.
The following snippet will e.g. transform the file c:\Project\Subdir\app.template.config to c:\Project\Subdir\app.config and copy the former to the latter:
<Target Name="CopyFiles">
<Copy SourceFiles="#(FilesToCopy)"
DestinationFiles="#(FilesToCopy->'%(RootDir)%(Directory)%(NewFileName)')"/>
</Target>
But then I noticed that a developer might not appreciate having his customized web.config file being over-written every time the script is run. However, the developer probably should get his local file over-written if the repository's web.template.config has been modified, and now has new values in it that the code needs. I tried doing this a number of different ways--setting the Copy attribute "SkipUnchangedFiles" to true, using the "Exist()" function--to no avail.
The solution to this was building incrementally. This ensures that files will only be over-written if the app.template.config is newer. I pass the names of the files as the target input, and I specify the new file names as the target output:
<Target Name="CopyFiles"
Input="#(FilesToCopy)"
Output="#(FilesToCopy->'%(RootDir)%(Directory)%(NewFileName)')">
...
</Target>
This has the target check to see if the current output is up-to-date with respect to the input. If it isn't, i.e. the particular .template.config file has more recent changes than its corresponding .config file, then it will copy the web.template.config over the existing web.config. Otherwise, it will leave the developer's web.config file alone and unmodified. If none of the specified files needs to be copied, then the target is skipped altogether. Immediately after a clean repository clone, every file will be copied.
The above turned out be a satisfying solution, as I've only started using MSBuild and I'm surprised by its powerful capabilities. The only thing I don't like about it is that I had to repeat the exact same transform in two places. I hate duplicating any kind of code, but I couldn't figure out how to avoid this. If anyone has a tip, it'd be greatly appreciated. Also, while I think the development practice that necessitates this totally sucks, this does help in mitigating that suck factor.
Short answer:
Yes, you can (and should) automate this. You should be able to use MSBuild Move task to rename files.
Long answer:
It is great that there is a desire to change from a manual process to an automatic one. There are usually very few real reasons not to automate. Your build script will act as living documentation of how build and deployment actually works. In my humble opinion, a good build script is worth a lot more than static documentation (although I am not saying you should not have documentation - they are not mutually exclusive after all). Let's address your questions individually.
What would be the best way to do this?
I don't have a full understanding of what configuration you are storing in those files, but I suspect a lot of that configuration can be shared across the development team.
I would suggest raising the following questions:
Which of the settings are developer-specific?
Is there any way to standardise local developer machines so that settings could be shared?
Is it possible to do this in the build script itself, without having to stipulate within the script every individual file that needs to be renamed?
Yes, have a look at MSBuild Move task. You should be able to use it to rename files.
...which would require maintenance to the script any time a new project is added to the solution?
This is inevitable - your build scripts must evolve together with your solution. Accept this as a fact and include in your estimates time to make changes to your build scripts.
Furthermore, is there a better development solution that I can suggest that will make this entire process unnecessary?
I am not aware of all the requirements, so it is hard to recommend something very specific. I can say suggest this:
Create a shared build script for your solution
Automate manual tasks as much as possible (within reason)
If you are struggling to automate something - it could be an indicator of an area that needs to be rethought/redesigned
Make sure your team mates understand how the build works and are able to make changes to it themselves - don't "own" the build and become a bottleneck
Bear in mind that going from no build script to full automation is not an overnight process. Be patient and first focus on automating areas that are causing the most pain.
If I have misinterpreted any of your questions, please let me know and I will update the answer.
First, I have a base assumption from watching Visual Studio compile things with its default .*proj files that, if you build the same solution twice in a row, it detects that nothing has changed and seems to fly through the solution build. Does this mean it knows that nothing was changed in a project and doesn't have to make a new DLL output?
If that's the case, I have a question. Say I have a solution with multiple class libraries, and an MSBuild task in each project that automatically increments the build's version by modifying AssemblyInfo.cs. Thing is (if my previous assumption is correct) it does this every time and triggers a new rebuild of each class library. Is there a target or property in MSBuild that can tell if the project needs recompilation, and skip my versioning step if so?
I ask because let's say I update project A, but not project B in a solution. If I run a build on the solution, I want it to update the version on project A, but since project B hasn't changed, I want to leave it alone.
Found something: http://msdn.microsoft.com/en-us/library/ms171483.aspx
MSBuild can compare the timestamps of
the input files with the timestamps of
the output files and determine whether
to skip, build, or partially rebuild a
target. In the following example, if
any file in the #(CSFile) item
collection is newer than the hello.exe
file, MSBuild will run the target;
otherwise it will be skipped:
<Csc
Sources="#(CSFile)"
OutputAssembly="hello.exe"/> </Target>
...that worked. But then got me thinking, what if someone pulls the code down from source control without the assemblies (which is how we do it)? Since it has no output to compare against, it'll do a compile and increment the version anyway. I think the complexities might lead me to abandon this approach.
It doesn't really matter if you increment on a developers box - what's important is that your daily/CI build is only incremented when needed. So, what I've done in the past is have some small XML file contain the next build number, and have an MSBuild task take this xml file and create a file called Version.cs (containing the versioning attributes you'd usually find in AssemblyInfo.cs).
Version.cs is never checked into your soure control - it's generated by the build.
Developers will sync the current XML file, build their binaries, and get the current version number. The continous integration build may also do the same thing. But a daily/official build will check out the XML file, increment the version information, and then check it in. From that moment on the version number has officially changed.
There are variations on this theme, but the general idea works.