Skip to content

Instantly share code, notes, and snippets.

@amake
Last active February 21, 2025 09:01
Show Gist options
  • Save amake/3e7194e5e61d0e1850bba144797fd797 to your computer and use it in GitHub Desktop.
Save amake/3e7194e5e61d0e1850bba144797fd797 to your computer and use it in GitHub Desktop.
Inno Setup on Linux and macOS

Inno Setup on Linux and macOS

Inno Setup is a popular installer builder for Windows. Of course it is made to run on Windows only, by default. But what if you want to build Windows installers off Windows, i.e. on Linux or macOS?

You’re in luck: It’s possible to run Inno Setup anywhere that Docker runs (including Linux and macOS), and even have a passable experience writing your setup script.

Containerized compiler

To run Inno Setup outside of Windows we will construct a Tower of Babel: install Inno Setup in Wine in a Docker container.

First, get Docker without needing to make an account:

Then you can run the command-line Inno Setup compiler, iscc, like so (assuming you have a setup script called helloworld.iss):

docker run --rm -i -v "$PWD:/work" amake/innosetup helloworld.iss

You can even put iscc on your PATH by wrapping this up in a script, named iscc of course:

#!/usr/bin/env bash

exec docker run --rm -i -v "$PWD:/work" amake/innosetup "$@"

See here for a more advanced wrapper script.

Note that there are some limitations inherent in running the compiler in a container:

  • The setup script will not be able to “see” any files outside of the directory mounted into the Docker container ($PWD in the above scripts), so some care is needed to ensure all referenced files are accessible.
  • I have been unable to get code signing of payload files (SignTool settings) to work. See the Code Signing section below for signing the installer itself.

Setup script

Creating or modifying an Inno Setup setup script can be a pain (when’s the last time you wrote any Pascal?). To make life a little bit easier, I made an Emacs linter for setup scripts: flycheck-innosetup.el.

Here’s a sample config using use-package:

(use-package flycheck
  :config
  (global-flycheck-mode))

(use-package flycheck-innosetup
  :after flycheck
  ;; Point `:load-path' to wherever you put flycheck-innosetup.el. You can
  ;; probably also pull directly from git with
  ;; `https://github.com/raxod502/straight.el'
  :load-path "lisp"
  :ensure nil
  :config
  (flycheck-innosetup-setup))

(use-package pascal
  :ensure nil
  :mode (("\\.iss\\'" . pascal-mode)))

This will get you inline error highlighting, though it can be quite slow if your script references a lot of files.

Code signing

You can sign the installer itself with osslsigncode, which is probably available in your package manager. I have also included it in the amake/innosetup Docker image; a wrapper script can be made in much the same way as for the compiler above.

Continuous integration

A key use case for all of this is to build Windows installers in CI, where you are likely to be running Linux.

One issue to be aware of is that Docker might be running under a different user and may not be able to read your checkout files or write to output directories. Judicious use of umask and/or chmod can remedy this.


Happy installing!

@bilogic
Copy link

bilogic commented Feb 18, 2025

  1. If I do not provide SignTool in the ISS, it compiles properly
  2. When I added SignTool=mysigntool, it kept getting Access denied
  3. Any ideas?
docker run --rm -i -v "$PWD:/work" amake/innosetup:innosetup5 \
    "iss/Mine.iss" \
    '/Smysigntool=echo test'

...
Preparing Setup program executable
Error in Z:\work\iss\Mine.iss: Access denied.
Compile aborted.
XIO:  fatal IO error 11 (Resource temporarily unavailable) on X server ":99"
      after 140 requests (140 known processed) with 0 events remaining.

@Steffen-MLR
Copy link

Steffen-MLR commented Feb 20, 2025

@bilogic
it could be related to the issue with mounting local drives to the container.
if you are running unix system, your local permissions (uid/gid) need to match the ones inside the container. just give it full access using chmod -R 777 .

@bilogic
Copy link

bilogic commented Feb 21, 2025

@Steffen-MLR thanks that was what I eventually did, but it does sound risky since something else can replace the EXE while ISCC is working on them

@Steffen-MLR
Copy link

Steffen-MLR commented Feb 21, 2025

@bilogic
For Production: find out the UID or GID of the user xclient inside the Container and set permissions on the Host like this!
for this Image, uid:gid is 1000:101

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment