How do I conditionally compile an NSIS script based on commandline parameters? - nsis

I'm trying to generalize a setup file by externally passing the version number. I want to be able to do this:
makensis myscript.nsi parameter=value
and then read the parameter within the script, so that using the same script I can generate differently versioned executables. I found this & this, but they seem to be for passing commandline parameters to the generated setup.exe. Is this possible, and how?

You can add symbols to the globally defined list from the command line using the /D switch:
makensis /DMyVersion="1.0.1" install.nsi
Then you can use them using the ${} syntax:
!ifdef MyVersion
StrCpy $Version "${MyInstallerName}"
!else
StrCpy $Version "1.0.0"
!endif
Also of possible interest is the GetVersion plugin discussed in this SO question: NSIS - put EXE version into name of installer

Related

READ THE ENVIRONMENT VARIABLE DURING THE COMPILE TIME IN NSIS

HI Everyone As i was working with the NSIS code, i need to get the environment variable value during the compile time, I Found this code written in somewhere But am not getting understand what does 'Foo' means. & How can we execute the below code in compile time, in my compiler Am not getting the environment variable value with the below following code, Can anybody give a brief example about where we can execute this & How it works?
Edit : As you requested i was inserting the link of Code referred from this forum "https://stackoverflow.com/questions/22149007/nsis-how-to-check-at-compile-time-if-an-environment-variable-exists"
; NSIS 2+
!define DOLLAR $
!if "$%foo%" == "${DOLLAR}%foo%"
!echo "%foo% not set"
!endif
; NSIS 3+
!if "$%foo%" == "${U+24}%foo%"
!echo "%foo% not set"
!endif
This code tries to check if a environment variable has been set (on the computer where the compiler is executing). If it has not been set the compiler just returns the raw string (like a batch file does). The code you found escapes the $ to check if the raw string is returned.
Foo is just a placeholder name, meaning the %Foo% variable. If you want to check %windir% for example, use !if "$%windir%" == "${U+24}%windir%".
If you just want the value, just use $%windir%:
ReadEnvStr $0 WINDIR
MessageBox MB_OK "%windir% was $%windir% when this installer was compiled. On this machine it is $0"

Precedence of !define and /D - How can I set an overridable default value?

I'm building an installer for a system that is generally installed by my coworkers, but several things can vary from one target machine to the next, including the locations of the files-to-be-installed on the compiling machine. I thought I could set a "gflag" in the source (with !define) and override it in the call to makensis.exe (with /D), but I can't even get my installer to recognize that a /D flag was passed.
More relevant documentation is behind the /h flag:
PS C:\> &"C:\Program Files (x86)\NSIS\makensis.exe" /h
Usage:
makensis [ option | script.nsi | - ] [...]
Options:
#...
/Ddefine[=value] defines the symbol "define" for the script [to value]
#...
I'm using this NSIS code:
!ifndef test
!define test Foo
!endif
Section
DetailPrint "${test}"
SectionEnd
I compile the installer in PowerShell:
&"C:\Program Files (x86)\NSIS\makensis.exe" "C:\path\to\test.nsi" /Dtest=Bar
Among the output, I see this:
Command line defined: "test=Bar"
The installer is successfully created, but it prints Foo while it should print Bar. If I comment !define test Foo, I get a warning when compiling:
1 warning:
unknown variable/constant "{test}" detected, ignoring (C:\Mach4\Installer\test.nsi:6)
And then ${test} is printed, indicating that the gflag has no value. Why does it not have a value of Bar?
The command line is parsed in order. In your case that means the script is parsed before /Dtest=Bar is parsed. Try this instead:
"C:\Program Files (x86)\NSIS\makensis.exe" /Dtest=Bar "C:\path\to\test.nsi"

Nsis doesn't see environment variables

Here is the part os nsis script (.nsi):
!ifndef QTDIR
!error "Please define QT installation directory via /DQTDIR=C:\qt\4.8.4"
!endif
But after executing this command:
set QTDIR=C:\path\to\qt
the erorr still occurs. The same result on two computers, both windows 7. Nsis version is 2.46 .
!ifdef and !ifndef operate on defines internally in the compiler process. You can set one in your script with !define or use the -D MakeNSIS command line argument.
MakeNSIS can also read Windows environment variables: !echo "The value of QTDIR is $%QTDIR%".
You can also support both:
!ifndef QTDIR
!define QTDIR "$%QTDIR%"
!endif
!if ! /fileexists "${QTDIR}"
!error "QTDIR not valid"
!endif

NSIS - put EXE version into name of installer

NSIS has a Name variable that you define in the script:
Name "MyApp"
It defines the name of the installer, that gets displayed as the window title, etc.
Is there a way to pull the .NET Version number out of my main EXE and append it to the Name?
So that my installer name would automatically be 'MyApp V2.2.0.0" or whatever?
There might be a very simple way to do this, but I don't know what it is. When I first started using NSIS, I developed this workaround to suit my needs and haven't revisited the problem since to see if there's anything more elegant.
I wanted my installers to have the same version number, description, and copyright info as my main executable. So I wrote a short C# application called GetAssemblyInfoForNSIS that pulls that file info from an executable and writes it into a .nsh file that my installers include.
Here is the C# app:
using System;
using System.Collections.Generic;
using System.Text;
namespace GetAssemblyInfoForNSIS {
class Program {
/// <summary>
/// This program is used at compile-time by the NSIS Install Scripts.
/// It copies the file properties of an assembly and writes that info a
/// header file that the scripts use to make the installer match the program
/// </summary>
static void Main(string[] args) {
try {
String inputFile = args[0];
String outputFile = args[1];
System.Diagnostics.FileVersionInfo fileInfo = System.Diagnostics.FileVersionInfo.GetVersionInfo(inputFile);
using (System.IO.TextWriter writer = new System.IO.StreamWriter(outputFile, false, Encoding.Default)) {
writer.WriteLine("!define VERSION \"" + fileInfo.ProductVersion + "\"");
writer.WriteLine("!define DESCRIPTION \"" + fileInfo.FileDescription + "\"");
writer.WriteLine("!define COPYRIGHT \"" + fileInfo.LegalCopyright + "\"");
writer.Close();
}
} catch (Exception e) {
Console.WriteLine(e.Message + "\n\n");
Console.WriteLine("Usage: GetAssemblyInfoForNSIS.exe MyApp.exe MyAppVersionInfo.nsh\n");
}
}
}
}
So if you use that application like so:
GetAssemblyInfoForNSIS.exe MyApp.exe MyAppVersionInfo.nsh
You would get a file named MyAppVersionInfo.nsh that looks something like this (assuming this info is in your executable):
!define VERSION "2.0"
!define DESCRIPTION "My awesome application"
!define COPYRIGHT "Copyright © Me 2010"
At the top of my NSIS script, I do something like this:
!define GetAssemblyInfoForNSIS "C:\MyPath\GetAssemblyInfoForNSIS.exe"
!define PrimaryAssembly "C:\MyPath\MyApp.exe"
!define VersionHeader "C:\MyPath\MyAppVersionInfo.nsh"
!system '"${GetAssemblyInfoForNSIS}" "${PrimaryAssembly}" "${VersionHeader}"'
!include /NONFATAL "${VersionHeader}"
!ifdef VERSION
Name "My App ${VERSION}"
!else
Name "My App"
!endif
!ifdef DESCRIPTION
VIAddVersionKey FileDescription "${DESCRIPTION}"
!endif
!ifdef COPYRIGHT
VIAddVersionKey LegalCopyright "${COPYRIGHT}"
!endif
The first 3 defines set up the file names to use in the !system call to GetAssemblyInfoForNSIS.exe. This system call takes place during your installer's compilation and generates the .nsh file right before you include it. I use the /NONFATAL switch so that my installer doesn't fail completely if an error occurs in generating the include file.
You can do this without .NET by using the GetVersion plugin, but following the same basic logic:
Here is ExtractVersionInfo.nsi:
!define File "...\path\to\your\app.exe"
OutFile "ExtractVersionInfo.exe"
SilentInstall silent
RequestExecutionLevel user
Section
## Get file version
GetDllVersion "${File}" $R0 $R1
IntOp $R2 $R0 / 0x00010000
IntOp $R3 $R0 & 0x0000FFFF
IntOp $R4 $R1 / 0x00010000
IntOp $R5 $R1 & 0x0000FFFF
StrCpy $R1 "$R2.$R3.$R4.$R5"
## Write it to a !define for use in main script
FileOpen $R0 "$EXEDIR\App-Version.txt" w
FileWrite $R0 '!define Version "$R1"'
FileClose $R0
SectionEnd
You compile this once, and then call it from your real installer:
; We want to stamp the version of the installer into its exe name.
; We will get the version number from the app itself.
!system "ExtractVersionInfo.exe"
!include "App-Version.txt"
Name "My App, Version ${Version}"
OutFile "MyApp-${Version}.exe"
Since NSISv3.0 this can be done with !getddlversion without using any third-party software:
!getdllversion "MyApp.exe" ver
Name "MyName ${ver1}.${ver2}.${ver3}.${ver4}"
OutFile "my_name_install_v.${ver1}.${ver2}.${ver3}.${ver4}.exe"
I found a way to do this on the NSIS wiki:
http://nsis.sourceforge.net/Version_Info_manipulations_on_compile-time
You can achieve this using MSBuild.
Just add your .nsi script to project and set this file property
Copy to Output Directory value Copy always or Copy if newer.
Add to your project file (e.g. .csproj or .vbproj) following code (suppose your nsi script has name installer.nsi)
<Target Name="AfterBuild" Condition=" '$(Configuration)' == 'Release'">
<!-- Getting assembly information -->
<GetAssemblyIdentity AssemblyFiles="$(TargetPath)">
<Output TaskParameter="Assemblies" ItemName="myAssemblyInfo"/>
</GetAssemblyIdentity>
<!-- Compile NSIS installer script to get installer file -->
<Exec Command='"%programfiles(x86)%\nsis\makensis.exe" /DVersion=%(myAssemblyInfo.Version) "$(TargetDir)installer.nsi"'>
<!-- Just to show output from nsis to VS Output -->
<Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" />
</Exec>
</Target>
Use $Version variable in your nsi script:
# define installer name
OutFile "MyApp-${Version}.exe"
Call simple VBS script after NSIS compile:
Set ddr = CreateObject("Scripting.FileSystemObject")
Version = ddr.GetFileVersion( "..\path_to_version.exe" )
ddr.MoveFile "OutputSetup.exe", "OutputSetup_" & Version & ".exe"
Since NSIS v3.0a0 you can do it directly in the script, no external tools needed: !getdllversion
Sample code (from the documentation):
!getdllversion "$%WINDIR%\Explorer.exe" Expv_
!echo "Explorer.exe version is ${Expv_1}.${Expv_2}.${Expv_3}.${Expv_4}"

Install from dynamic location

I have 2 versions of the same exe file for my project. The installer is supposed to pick one of the 2 versions depending on some conditions.
In a normal case i would do File executable\myExe.exe. Because i now have 2 versions of the file, i would have to do something like File "${ExeSourcePath}\myExe.exe", and $ExeSourcePath is determined by checking various conditions. When compiling this code i get
File: "${ExeSourcePath}\myExe.exe" -> no files found.
Anyone knows why? I'm only allowed to use fixed paths with the File command or am i doing something wrong?
${ExeSourcePath} is a precompiler define and $ExeSourcePath is a variable used at runtime, the File command can only use precompiler defines.
There are two ways you can handle this:
A) Include both files and decide at runtime based on the users system or choices made during install:
!include LogicLib.nsh
Section
ReadRegStr $0 HKLM "Software\foo\bar" baz
${If} $0 > 5
File "c:\myproject\version2\app.exe"
${Else}
File "c:\myproject\version1\app.exe"
${EndIf}
SectionEnd
B) Only include one file based on command line passed to makensis (/Dusev2 app.nsi) or something on your system:
Section
!define projectroot "c:\myproject"
!searchparse /noerrors /file ....... usev2 ;Or you can use !system etc
!ifdef usev2
File "${projectroot}\version2\app.exe"
!else
File "${projectroot}\version1\app.exe"
!endif
SectionEnd

Resources