0

I'm building a multi-architecture installer for a C++ program with NSIS. I'm using Visual Studio 2010. All is well except I don't know how to make the installer depend on the build for all architectures.

I have created a project to run makensis as a build step, and configured it to depend on all other projects in the solution. I'm currently building for Win32 and X86_64 architectures. The NSIS project is only built as a part of X86_64 configuration. But it packs files built in both X86_64 and Win32 configurations. Here lies the problem. If I build Win32 and then immediately X86_64, all is well. If I start with X86_64, the build fails because it can't find Win32 files. Worse, if I change some source code and rebuild only X86_64, the installer project will happily pick up out-of-date Win32 files without any indication of a problem.

Can I force a Win32 build from an X86_64 build, or do anything else to make this work?

I'm a Unix type, Windows is an alien world to me.

Any

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243

2 Answers2

1

As for "foolproof" solutions, if I understand you correctly:

  • You have solution containing multiple projects (lets say Test.sln),
  • You want to build this solution for several platforms,
  • ... and use the MakeNSIS tool (I have no idea what that is) to create an installer packaging binaries built for all the platforms.

Please correct me if I am wrong. So, to achieve this task:

  • I would completely drop the project you introduced (the one running MakeNSIS),
  • Then would create Test.msbuild file such as the one below,
  • Notice the <Exec> element, that is the place where you want to run you MakeNSIS,
  • Then simply run the msbuild as msbuild Test.msbuild,
  • Using this solution you would have all the projects from Test.sln first built for Win32, then for x64, and MakeNSIS would only be run afterwards.
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="Build" DependsOnTargets="Build_Win32;Build_x64">
    <!-- Run whatever command you like, such as MakeNSIS .. ? -->
    <Exec Command="notepad.exe" />
  </Target>
  <Target Name ="Build_Win32">
    <MSBuild Projects="Test.sln" Properties="Configuration=Release;Platform=Win32" />
  </Target>
  <Target Name ="Build_x64">
    <MSBuild Projects="Test.sln" Properties="Configuration=Release;Platform=x64" />
  </Target>
</Project>

Please provide clarification to your actual question if the above isn't what you asked for.

EDIT:

After clarifying your request in the comment, I would propose following solution. I like the above solution with Test.msbuild more, but here you go:

  1. Add new project BuildInstaller into your solution,
  2. In Configuration Manager uncheck the checkbox "Build" for this new project for all combinations of Configuration/Platform,
  3. Still in Configuration Manager, create new configuration, lets say Installers,
  4. For this new configuration, uncheck the "Build" checkbox for all the projects from the solution, except for the BuildInstaller,
  5. Now open the BuildInstaller.vcxproj in text editor and append the following snippet right before the closing </Project> tag:
<ItemGroup>
  <ProjectsToBuild Include="..\**\*.vcxproj" Exclude="..\**\BuildInstaller.vcxproj"/>
</ItemGroup>
<Target Name="Build" DependsOnTargets="Build_Win32;Build_x64">
  <!-- Run whatever command you like, such as MakeNSIS .. ? -->
  <Exec Command="notepad.exe" />
</Target>
<Target Name="Build_Win32">
  <MSBuild Projects="@(ProjectsToBuild)" Properties="Configuration=Release;Platform=Win32" />
</Target>
<Target Name="Build_x64">
  <MSBuild Projects="@(ProjectsToBuild)" Properties="Configuration=Release;Platform=x64" />
</Target>
  1. This way you effectively override the default build target,
  2. So now:
    • Everytime you build for Release/Debug configuration, installer won't be built, that is preferred from many reasons,
    • Everytime you build for Installers configuration, your new BuildInstaller.vcxproj will take over, will build both win32 and x64 binaries and in the end will run the custom command line executable. Of course binaries will be built using Release configuration which should be desired.

Initially I thought I could drop the <ItemGroup> element and use Projects="..\Test.sln" instead of Projects="@(ProjectsToBuild)" as there should be no circular dependency (BuildInstaller.vcxproj is not built for Release) but the build took forever so there had to be some problem, weird...

Does this satisfy your needs?

Michal Hosala
  • 5,570
  • 1
  • 22
  • 49
  • This looks like something that could work. Is it possible to run this from a project that's a part of Test.sln itself? It looks kinda recursive but perhaps it is possible to create a special configuration just for this project. – n. m. could be an AI Feb 24 '15 at 15:19
  • @n.m. hmm I do not see recursion in this as the `Test.msbuild` is basically a custom build script or should we say chain of instructions to execute? We could call it `TestInstaller.msbuild` to better express its purpose. `Test.sln` should stay as is I believe because it works and builds just as expected based on chosen configuration/platform. You may consider to create brand new solution, something like `TestInstaller.sln` which would be responsible for running the MakeNSIS and _could_ be utilizing the `Test.msbuild` snippet I provided above. – Michal Hosala Feb 24 '15 at 15:37
  • Yes I understand this. The intent is to be able to just hit "build" button in VS and have an installer built. I don't want two .sln files, this is too confusing. – n. m. could be an AI Feb 24 '15 at 15:51
  • @n.m. please see **EDIT:** section of my answer. All the projects that I've been working on so far had the installers build process separated from the solution though, but I am not going to try to convice you to use this approach, if you find it confusing. – Michal Hosala Feb 24 '15 at 17:01
  • Thank you, this looks like what I need. Will definitely try this! – n. m. could be an AI Feb 24 '15 at 19:21
  • Unfortunately this doesn't work. Project dependencies are not taken into account. Major bummer. – n. m. could be an AI Mar 05 '15 at 07:17
  • @n.m. Could you please describe a problematic scenario in a bit more detail so I can perhaps figure out a solution? **UPDATE** section in your question or so, thanks. – Michal Hosala Mar 05 '15 at 08:34
  • I have a solution with dependencies between projects. A build of project X should build all project X depends on, and then build X itself. This doesn't happen. – n. m. could be an AI Mar 05 '15 at 10:22
  • @n.m. hmm, I was trying to find a solution, for now I only have a not very nice workaround. Try replacing the `` elements in the project file with ``, similarly for x64. But I will try to figure out something better. [Here](http://stackoverflow.com/q/328017/3242721) you can find out what is the path to msbuiild.exe. – Michal Hosala Mar 06 '15 at 08:34
  • Thank you, I have thought about that, but msbuild may live in different places on different machines... – n. m. could be an AI Mar 06 '15 at 08:56
  • @n.m. Sorry, I wasn't able to figure out anything better... However, I submited [a bug to microsoft](https://connect.microsoft.com/VisualStudio/feedback/details/1169409) at least as I believe building the sln file instead of group of projects _should_ work, we'll see. – Michal Hosala Mar 08 '15 at 23:33
  • @n.m. just an update, bug was marked as fixed in VS2015, though that won't help you much ... – Michal Hosala Mar 19 '15 at 00:42
0

I think you need to build Win32 configuration first and then 64bit configuration.

The makensis project should be built after both are finished (successfully!).

For example it is possible to call it from Post Build event (for 64bit configuration) or as separate project.

I am not sure whether your makensis project is based on Visual & Installer (http://www.visual-installer.com - sorry for little self promo :) or it is pure (text - batch) project included in VS Solution.

In both cases the Configuration manager in VS allows you to define the build order. The makensis project should be always the last so it can find all dependencies from previous configurations.

Also it is good to use relative path in makensis project - something like ${TARGET_PATH} which will be defined for each configuration with different value.

Slappy
  • 5,250
  • 1
  • 23
  • 29