nsis-0.1: Build NSIS Installers

Safe HaskellSafe-Infered




NSIS (Nullsoft Scriptable Install System, http://nsis.sourceforge.net/) is a tool that allows programmers to create installers for Windows. This library provides an alternative syntax for NSIS scripts, as an embedded Haskell language, removing much of the hard work in developing an install script. Simple NSIS installers should look mostly the same, complex ones should be significantly more maintainable.

For examples, see the Examples source directory.

Much of the documentation from the Installer section is taken straight from the NSIS documentation.


Core types

nsis :: Action () -> StringSource

Create the contents of an NSIS script from an installer specification.

nsisNoOptimise :: Action () -> StringSource

Like nsis, but don't try and optimise the resulting NSIS script. Useful to figure out how the underlying installer works, or if you believe the optimisations are introducing bugs (but please do report any such bugs!).

data Action a Source

Monad in which installers are defined. A useful command to start with is section.

type Exp ty = Action (Value ty)Source

The type of expressions - namely an Action producing a Value. There are instances for Num and IsString, and turning on {-# LANGUAGE OverloadedStrings #-} is strongly recommended.

The fromString function converts any embedded $VAR into a variable lookup, which may refer to one of the builtin NSIS variables (e.g. $SMPROGRAMS, $TEMP, $PROGRAMFILES), or a named variable created with constant or mutable. The string $$ is used to escape $ values. Bracket the variables to put text characters afterwards (e.g. $(SMPROGRAMS)XXX). In contrast to standard strings, / is treated as \ and // is treated as /. Remember to escape any slashes occuring in URLs.

If the string is Exp String then any Int variables used will be automatically shown (see strShow). If the string is Exp ty then it must be of the form "$VAR" where $VAR is a variable of type ty.

The Eq and Ord instances for Exp throw errors for all comparisons (use %==, %<= etc), but min and max are defined. The Num (arithmetic) and Monoid (string concatenation) instances are both fully implemented. From Integral and Fractional, only /, mod and div are implemented, and all as integer arithmetic. No functions from Enum or Real are implemented.

When using a single expression multiple times, to ensure it is not evaluated repeatedly, use share.

data Value ty Source

A Value, only used by Exp, which can be produced using return. The ty argument should be one of String, Int or Bool.




share :: Exp t -> (Exp t -> Action a) -> Action aSource

The Exp language is call-by-name, meaning you must use share to avoid evaluating an exression multiple times. Using share, if the expression has any side effects they will be run immediately, but not on subsequent uses. When defining functions operating on Exp, if you use the same input expression twice, you should share it. For example:

 strPalindrom x = share x $ \x -> x %== strReverse x

If the expression was not shared, and x read from a file, then the file would be read twice.

scope :: Action a -> Action aSource

Introduce a variable scope. Scopes are automatically introduced by operations such as iff, loop, while etc. Inside a scope you may define new variables whose names may clash with variables outside the scope, but the local versions will be used.

If you have any non-evaluated expressions, before introducing any potentially clashing variables in the scope you should share them or use constant_ on them. For example:

 operate x = do
     x <- constant_ x
     scope $ do
         constant "TEST" 0

It is important to turn x into a constant_ before defining a new constant $TEST, since if x refers to $TEST after the new definition, it will pick up the wrong variable.

constant :: Typeable t => String -> Exp t -> Action (Exp t)Source

Create a constant with a name, ensuring the expression is shared. After defining the expression, you can refer to it with $NAME in a String. To introduce a new scope, see scope.

 constant HELLO Hello World
 alert $HELLO!

constant_ :: Exp t -> Action (Exp t)Source

Create a constant with no name, ensuring the expression is shared. Equivalent to share return.

mutable :: Typeable t => String -> Exp t -> Action (Exp t)Source

Create a mutable variable a name, which can be modified with @=. After defining the expression, you can refer to it with $NAME in a String. To introduce a new scope, see scope.

 h <- mutable "HELLO" "Hello World"
 "$HELLO" @= "$HELLO!"
 h        @= "$HELLO!" -- equivalent to the above
 alert "$HELLO"        -- with 2 exclamation marks

mutable_ :: Exp t -> Action (Exp t)Source

Create an unnamed mutable variable, which can be modified with @=.

 h <- mutable "Hello World"
 h @= h & "!"
 alert h

(@=) :: Exp t -> Exp t -> Action ()Source

Assign a value to a mutable variable. The variable must have been originally created with mutable or mutable_, or there will be an error when generating the install file.

Typed variables

mutableInt, constantInt :: String -> Exp Int -> Action (Exp Int)Source

Versions of mutable and constant restricted to Exp Int, used to avoid ambiguous type errors.

mutableInt_, constantInt_ :: Exp Int -> Action (Exp Int)Source

Versions of mutable_ and constant_ restricted to Exp Int, used to avoid ambiguous type errors.

mutableStr, constantStr :: String -> Exp String -> Action (Exp String)Source

Versions of mutable and constant restricted to Exp String, used to avoid ambiguous type errors.

mutableStr_, constantStr_ :: Exp String -> Action (Exp String)Source

Versions of mutable_ and constant_ restricted to Exp String, used to avoid ambiguous type errors.

Control Flow

iff :: Exp Bool -> Action () -> Action () -> Action ()Source

Test a boolean expression, reunning the first action if it is true and the second if it is false. The appropriate branch action will be run within a scope. See ? for an expression orientated version.

 iff (x %== 12) (alert "is 12") (alert "is not 12")

iff_ :: Exp Bool -> Action () -> Action ()Source

A version of iff where there is no else action.

while :: Exp Bool -> Action () -> Action ()Source

A while loop, run the second argument while the first argument is true. The action is run in a scope. See also loop.

 x <- mutable_ x
 while (x %< 10) $ do
    x @= x + 1

loop :: (Action () -> Action ()) -> Action ()Source

A loop with a break command. Run the action repeatedly until the breaking action is called. The action is run in a scope. See also while.

 x <- mutable_ x
 loop $ \break -> do
     iff_ (x %>= 10) break
     x @= x + 1

onError :: Action () -> Action () -> Action ()Source

Run an intitial action, and if that action causes an error, run the second action. Unlike other programming languages, any uncaught errors are silently ignored. All actions are run in scope.

 onError (exec "\"$WINDIR/notepad.exe\"") (alert "Failed to run notepad")

(?) :: Exp Bool -> (Exp t, Exp t) -> Exp tSource

An expression orientated version of iff, returns the first component if the first argument is true or the second if it is false.

 x %== 12 ? (x, x + 5)

(%&&), (%||) :: Exp Bool -> Exp Bool -> Exp BoolSource

Short circuiting boolean operators, equivalent to && and || but on Exp.

data Label Source

A code label, used for goto programming, see newLabel.

newLabel :: Action LabelSource

Create a new label, used with goto and label to write line jump based programming. Where possible you should use structured alternatives, such as iff, while and loop. Each created label must be used with one call to label, and any number of calls to goto. As an example:

 abort <- newLabel
 while var $ do
     iff_ cond1 $ goto abort
     iff_ cond2 $ goto abort
     var @= strDrop 1 var 
 label abort

Note that the above example could have been written in a simpler manner with loop.

label :: Label -> Action ()Source

Define the location of a label, see newLabel for details. This function will fail if the same Label is passed to label more than once.

goto :: Label -> Action ()Source

Jump to a label, see newLabel for details. This function will fail if label is not used on the Label.


(%==), (%/=) :: Exp a -> Exp a -> Exp BoolSource

The standard equality operators, lifted to Exp.

(%<=), (%>), (%>=), (%<) :: Exp Int -> Exp Int -> Exp BoolSource

The standard comparison operators, lifted to Exp.

true, false :: Exp BoolSource

Boolean constants corresponding to True and False

not_ :: Exp Bool -> Exp BoolSource

Boolean negation.

strRead :: Exp String -> Exp IntSource

Convert a String to an Int, any errors are silently ignored.

(&) :: Exp String -> Exp String -> Exp StringSource

Concatenate two strings, for example "$FOO" & "$BAR" is equivalent to "$FOO$BAR".

strConcat :: [Exp String] -> Exp StringSource

Perform string concatenation on a list of expressions.

strLength :: Exp String -> Exp IntSource

Return the length of a string, strLength "test" %== 4.

strTake :: Exp Int -> Exp String -> Exp StringSource

Take the first n characters from a string, strTake 2 "test" %== "te".

strDrop :: Exp Int -> Exp String -> Exp StringSource

Drop the first n characters from a string, strDrop 2 "test" %== "st".

strReplace :: Exp String -> Exp String -> Exp String -> Exp StringSource

Replace one string with another string, in a target string. As some examples:

 strReplace "t" "XX" "test" %== "XXesXX"
 strReplace "ell" "" "hello world" %== "ho world"

strIsPrefixOf :: Exp String -> Exp String -> Exp BoolSource

Is the first string a prefix of the second.

strUnlines :: [Exp String] -> Exp StringSource

Join together a list of strings with \r\n after each line. Note that unlike standard unlines, we use the Windows convention line separator.

File system manipulation

data FileHandle Source

The type of a file handle, created by fileOpen.


fileOpen :: FileMode -> Exp FilePath -> Action (Exp FileHandle)Source

Open a file, which must be closed explicitly with fileClose. Often it is better to use writeFile' or withFile instead.

 h <- fileOpen ModeWrite "C:/log.txt"
 fileWrite h "Hello world!"
 fileClose h

fileWrite :: Exp FileHandle -> Exp String -> Action ()Source

Write a string to a file openned with fileOpen.

fileClose :: Exp FileHandle -> Action ()Source

Close a file file openned with fileOpen.

withFile' :: FileMode -> Exp FilePath -> (Exp FileHandle -> Action ()) -> Action ()Source

With a fileOpen perform some action, then automatically call fileClose. If the action argument jumps out of the section then the fileClose call will be missed.

writeFile' :: Exp FilePath -> Exp String -> Action ()Source

Write a file, like writeFile.

writeFileLines :: Exp FilePath -> [Exp String] -> Action ()Source

Write a file comprising of a set of lines.

createDirectory :: Exp FilePath -> Action ()Source

Creates (recursively if necessary) the specified directory. Errors can be caught using onError. You should always specify an absolute path.

 createDirectory "$INSTDIR/some/directory"

Registry manipulation

Process execution

exec :: Exp String -> Action ()Source

Execute the specified program and continue immediately. Note that the file specified must exist on the target system, not the compiling system. $OUTDIR is used for the working directory. Errors can be caught using onError. Note, if the command could have spaces, you should put it in quotes to delimit it from parameters. e.g.: exec "\"$INSTDIR/command.exe\" parameters". If you don't put it in quotes it will not work on Windows 9x with or without parameters.

 exec "\"$INSTDIR/someprogram.exe\""
 exec "\"$INSTDIR/someprogram.exe\" some parameters"


Global installer options

name :: Exp String -> Action ()Source

Sets the name of the installer. The name is usually simply the product name such as 'MyApp' or 'Company MyApp'.

 name "MyApp"

outFile :: Exp FilePath -> Action ()Source

Specifies the output file that MakeNSIS should write the installer to. This is just the file that MakeNSIS writes, it doesn't affect the contents of the installer. Usually should end with .exe.

 outFile "installer.exe"

installDir :: Exp FilePath -> Action ()Source

Sets the default installation directory. Note that the part of this string following the last \ will be used if the user selects browse, and may be appended back on to the string at install time (to disable this, end the directory with a \). If this doesn't make any sense, play around with the browse button a bit.

 installDir "$PROGRAMFILES/MyApp"

installIcon, uninstallIcon :: Exp FilePath -> Action ()Source

Set the icon used for the installer/uninstaller.

 installIcon "NSISDIR/Contrib/Graphics/Icons/modern-install.ico"

headerImage :: Maybe (Exp FilePath) -> Action ()Source

Set the image used for the header splash. Pass Nothing to use the default header image.

 headerImage $ Just "$NSISDIR/Contrib/Graphics/Header/win.bmp"

installDirRegKey :: HKEY -> Exp String -> Exp String -> Action ()Source

This attribute tells the installer to check a string in the registry, and use it for the install dir if that string is valid. If this attribute is present, it will override the installDir attribute if the registry key is valid, otherwise it will fall back to the installDir default. When querying the registry, this command will automatically remove any quotes. If the string ends in ".exe", it will automatically remove the filename component of the string (i.e. if the string is "C:program filesfoo/foo.exe", it will know to use "C:program filesfoo").

 installDirRegKey HKLM "Software/NSIS" ""
 installDirRegKey HKLM "Software/ACME/Thingy" "InstallLocation"


Section commands

writeUninstaller :: Exp FilePath -> Action ()Source

Writes the uninstaller to the filename (and optionally path) specified. Only valid from within an install section, and requires that you have an uninstall section in your script. You can call this one or more times to write out one or more copies of the uninstaller.

 writeUninstaller "$INSTDIR/uninstaller.exe"

setOutPath :: Exp FilePath -> Action ()Source

Sets the output path ($OUTDIR) and creates it (recursively if necessary), if it does not exist. Must be a full pathname, usually is just $INSTDIR.

 setOutPath "$INSTDIR"


data MessageBoxType Source



Display with an OK button


Display with an OK and a cancel button


Display with abort, retry, ignore buttons


Display with retry and cancel buttons


Display with yes and no buttons


Display with yes, no, cancel buttons


Display with exclamation icon


Display with information icon


Display with question mark icon


Display with stop icon


Display with installer's icon


Make messagebox topmost


Set foreground


Right align text


RTL reading order


Button 1 is default


Button 2 is default


Button 3 is default


Button 4 is default

data FileMode Source

Mode to use with 'Development.



Read a file.


Opened for both read and write, contents preserved.