-
Notifications
You must be signed in to change notification settings - Fork 151
Create an InnoSetup Installer
- Create an InnoSetup Installer (Windows)
- Automatically Generate An InnoSetup File
- Note About Installation Location
- Note About License Screens
- Generate The Installer Program
- Example Script File With CMake Customization
To create an InnoSetup installer for distribution on Windows, a setup script needs to be generated. This script file is then provided to InnoSetup's iscc
compiler which will create the installer itself.
A basic InnoSetup script is composed of separate sections that contain metadata for the plugin as well as installation instructions.
[Setup]
AppId=00000000-0000-0000-0000-000000000000
This ID should be a unique identifier for the plugin, generating a version 4 UUID should be sufficient for this.
AppName=my-plugin-for-obs
AppVersion=1.0.0
AppPublisher=My Name
AppPublisherUrl=https://my-plugin.com
AppSupportUrl=https://my-plugin.com/support
AppUpdatesUrl=https://my-plugin.com/updates
These fields contain the metadata for the plugin. To keep the maintenance burden of a new version down, the file (and thus these values) can possibly be automatically filled out by the build system. See below for instructions on this.
DefaultDirName={commonappdata}\obs-studio\plugins\my-plugin
DefaultGroupName=my-plugin-for-obs
These two options set the default installation destination used by the installer as well as the start menu directory ("group") to create. It might also be worth to set the DirExistsWarning
directive to no
to allow silent updating (so any existing files will be silently overwritten by the installer).
OutputBaseFilename=My-Plugin-For-OBS-Installer
This option sets the base name for the installer application generated by InnoSetup, which would commonly result in an installer named My-Plugin-For-OBS-Installer.exe
to be generated.
Compression=lzma
SolidCompression=yes
The compression format lzma
has a significantly better compression ratio than zip
, but it will also take a bit longer to create an archive.
As this process is not commonly repeated all too often, the compression ratio benefits should outweigh the compression time cost. The SolidCompression
directive also instructs InnoSetup to compress all files at once instead of separately, which can improve compression ratio as well.
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
The installer program itself can be localized via the Languages
section. Each language requires its own 3rd-party definition files as InnoSetup only ships with English default files. More information can be found in InnoSetup's documentation.
[Files]
Source: "<Path to plugin files>\*"; DestDir: "{app}"; Flags: recursesubdirs createallsubdirs
Source: "<Path to other plugin file>"; DestDir: "{app}"
The Files
section contains information about where to put files contained in the installer (and also which files to ignore). Each Source
can either be a single file or a wildcard expression to match all files in a directory. If relative paths are provided, then the current working directory of the process invoking the iscc
compiler is used as a root for these paths.
The built-in constant {app}
represents the destination directory chosen by the user as part of the installation process.
If a wildcard is used, additional Flags
can be provided to influence InnoSetup's file discovery behavior:
-
recursesubdirs
tells InnoSetup to recursively discover all directories and their sub-directories found in the source location. -
createallsubdirs
tells InnoSetup to not skip empty sub-directories it may encounter during the recursive discovery and also recreate these empty directories at the install destination.
As no DestName
directive is provided, all file names will be kept as-is. Optionally the ignoreversion
flag could be used to instruct InnoSetup to ignore any and all version information found in source and destination files.
[Icons]
Name: "{group}\{cm:ProgramOnTheWeb,my-plugin-for-obs}"; Filename: "https://my-plugin.com"
This section defines the start menu entries that should be created as part of the installation. In this example only a web link to the plugin's web site is added.
Important
In the past the installer script also created a start menu entry for the uninstall program, similar to this:
Name: "{group}\{cm:UninstallProgram,my-plugin-for-obs}"; Filename: {uninstallexe}
This is bad practice - Microsoft's own guidance since Windows 95 has been for developers to not add such an entry to the start menu, as users are supposed to use the corresponding "Add/Remove Programs" setting provided by Windows itself. In fact, Windows 11 has started to automatically hide these entries if they are added.
The {cm:<...>}
entry uses a template name from the default language file which takes a name argument. As this example only provides an English language file, such entries will use the English template strings.
Many values used by the InnoSetup script are kept in the buildspec.json
file and are thus known to the build system already. So instead of writing the InnoSetup file manually, one could use the build system to generate the file.
When using CMake as the build system generator, this can be achieved via the configure_file
command and a CMake template file which commonly uses the final output name with an .in
suffix (e.g. my-template-installer.iss.in
).
To avoid repetitions inside the script file, CMake variables can be defined at the very top of it (before any other section):
#define MyAppName "@CMAKE_PROJECT_NAME@"
#define MyAppVersion "@CMAKE_PROJECT_VERSION@"
#define MyAppPublisher "@PLUGIN_AUTHOR@"
#define MyAppURL "@PLUGIN_WEBSITE@"
When configure_file
is called with this template file as its first argument, CMake will replace any strings of the format @VARIABLE_NAME@
with the value of the variable. Note that it is not strictly necessary to use #define
, as CMake will replace any other occurrences directly, e.g.:
AppId={{@UUID_APP@}
This will put a CMake variable called UUID_APP
into a string enclosed by curly braces and assign it to the AppId
variable (note the double curly braces at the beginning - these are necessary to make InnoSetup use the actual opening curly brace character and not interpret it as an InnoSetup constant).
Important
The UUID_APP
variable needs to be provided to CMake either via the preset or directly on the CMake command line.
By default CMake will put files generated by configure_file
into the binary output directory. If another (more controlled) output directory is desired, provide it as the second argument to the function.
In a now obsolete variant of the plugin template the InnoSetup script file was generated automatically. This was removed in favor of this documentation because of the maintenance burden to keep a valid and working InnoSetup script as part of the template's code base.
This variant used a [Code]
section in the installer script to detect the installation location of OBS Studio to be able to copy plugins directly into the application directories.
This practice is now discouraged and no example code is provided for it:
- This approach required a version of OBS Studio that was installed via its own installation program. Any version not "installed" (but instead just extracted in some other location) would not be discovered.
- It also lead to a mix of 1st-party and 3rd-party plugins in the application directory, which - coupled with the unfortunate practice of naming plugins
obs-your-plugin
- made it unnecessarily hard for users to distinguish between OBS Studio's own modules and 3rd party plugins
Plugins should be installed in %PROGRAMDATA\obs-studio\plugins
instead, which this guide assumes as well.
The obsolete variant of the InnoSetup script provided by the template also used the LICENSE
file to create a license approval screen as part of the installer. There is no need to display such a license screen to users and it is considered an anti-pattern to do so (because the GPL is not an EULA). The Free Software Foundation (FSF) has the following to say about this practice:
Merely agreeing to the GPL doesn't place any obligations on you. You are not required to agree to anything to merely use software which is licensed under the GPL. You only have obligations if you modify or distribute the software. If it really bothers you to click through the GPL, nothing stops you from hacking the GPLed software to bypass this.
Thus this part of the installation script is not used by this guide either.
To generate the actual installer program, the iscc
compiler is used:
iscc <Path to generated .iss file> /O<Output path for generated installer>
Be aware that the compiler will use the current working directory to resolve any relative links that might have been used for Source
directives in the Files
section.
To build the installer program as part of the GitHub Actions CI workflow, the Windows packaging script Package-Windows.ps1
needs to be modified to include the iscc
compilation steps. The script file can be found in the scripts
sub-directory of the .github
directory.
As iscc
is an external program, Invoke-External
(a custom PowerShell function used as part of the build scripts) should be used to allow for proper error handling in the PowerShell script. This example will generate an installer using the release
sub-directory of the project root as its output directory and will also override the output name of the script:
# Declare the location of the InnoSetup setup file
$IsccFile = "${ProjectRoot}/build_${Target}/<NAME OF YOUR GENERATED INNOSETUP SCRIPT FILE>"
# Throw an error if the provided path is invalid
if ( ! ( Test-Path -Path $IsccFile ) ) {
throw 'InnoSetup install script not found. Run the build script or the CMake build and install procedures first.'
}
Log-Information 'Creating InnoSetup installer...'
# Push the current location on the "BuildTemp" directory stack for easier return later
Push-Location -Stack BuildTemp
# Change to "release" sub-directory of the project root directory
Ensure-Location -Path "${ProjectRoot}/release"
# Copy the directory for the specified configuration (e.g. "Release") to a new directory named "Package"
Copy-Item -Path ${Configuration} -Destination Package -Recurse
# Invoke the InnoSetup iscc compiler with the specified setup file and the sub-directory "release" in
# the project root directory as the output directory
Invoke-External iscc ${IsccFile} /O"${ProjectRoot}/release" /F"${OutputName}-Installer"
# Remove the copied "Package" directory and its contents
Remove-Item -Path Package -Recurse
# Pop the location stored in the "BuildTemp" directory stack earlier
Pop-Location -Stack BuildTemp
Log-Group
This example expects CMake to have used the Visual Studio generator, which is a multi-config generator. As explained in CMake Build System Guide this means that the configuration type is not fixed at the point of time the build system is generated and thus is not available when the InnoSetup script file is generated.
Instead the PowerShell script will receive the configuration that was used to build the plugin and copies the files into a generic directory called Package
which is then used by the installer script. This corresponds to the Source
directive using ..\release\Package\*
in the script.
Note
If the generated installer is placed in a directory called release
in the project's root (next to the generated .zip
archive), it will be automatically discovered by the GitHub Actions workflows and added to a GitHub release.
#define MyAppName "@CMAKE_PROJECT_NAME@"
#define MyAppVersion "@CMAKE_PROJECT_VERSION@"
#define MyAppPublisher "@PLUGIN_AUTHOR@"
#define MyAppURL "@PLUGIN_WEBSITE@"
[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{@UUID_APP@}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={commonappdata}\obs-studio\plugins\my-plugin
DefaultGroupName={#MyAppName}
OutputBaseFilename={#MyAppName}-{#MyAppVersion}-Windows-Installer
Compression=lzma
SolidCompression=yes
DirExistsWarning=no
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Files]
Source: "..\release\Package\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: "{group}\{cm:ProgramOnTheWeb,{#MyAppName}}"; Filename: "{#MyAppURL}"
OBS Studio Developer Resources
Plugin Development | Frontend Development | Graphics Development