Skip to content

Commit

Permalink
Add makensis as an option for building the Windows installer
Browse files Browse the repository at this point in the history
  • Loading branch information
markt-asf committed Feb 13, 2025
1 parent 33a0e89 commit d49abb6
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 110 deletions.
78 changes: 68 additions & 10 deletions BUILDING.txt
Original file line number Diff line number Diff line change
Expand Up @@ -249,19 +249,42 @@ You can build them by using the following commands:
cd ${tomcat.source}
ant embed

(5.4) Building the Windows installer

The Windows installer uses the NSIS installer framework.
It can be build on Windows, on any other platform which provides
the Wine Windows emulator or the NSIS binary "makensis".

Linux and MacOS are platforms, on which you can install Wine or
"makensis".

Selecting between Wine and makensis on non-Windows platforms can
be done by setting the ant property "nsis.tool" to either "wine"
or "makensis" in build.properties.

If you want to sign the installer, you will need to set some
properties with names prefixed with "codesigning" in your build.properties.
For details see the targets "jsign-installer" and "jsign-uninstaller"
in build.xml and the default property values in build.properties.default.


(6) Building a full release (as provided via the ASF download pages)

1. Remark on building the Windows installer

A full release includes the Windows installer which requires a Windows
environment to be available to create it. If not building in a Windows
environment, the build scripts assume that Wine is available. If this is not
the case, the skip.installer property may be set to skip the creation of the
Windows installer.
environment, an installed Wine emulator or an installed native
"makensis" binary from the NSIS project. Creating a reproducible
installer using the "makensis" option needs a special build of "makensis".
For details see below.

Provided that Wine is available on non-Windows platforms, a full release
build may be made on Windows, Linux or MacOS.
Provided that Wine or "makensis" is available on non-Windows platforms,
a full release build may be made on Windows, Linux or MacOS.

1. Configure GPG, if needed
If you do not want to build the Windows installer, the skip.installer
property may be set to skip the creation of the Windows installer.

2. Configure GPG, if needed

If the released artifacts have to be cryptographically signed with a
PGP signature, like the official ASF releases are, the following
Expand All @@ -278,14 +301,14 @@ You can build them by using the following commands:
You will be prompted for the GPG passphrase when the release build
starts, unless "gpg.passphrase" property is set.

2. If building the Windows installer
3. If building the Windows installer on Windows

If running the build in a UAC enabled environment, building the Windows
installer requires elevated privileges. The simplest way to do this is to
open the command prompt used for the build with the "Run as administrator"
option.

3. Configure the code signing service
4. Configure the code signing service

ASF committers performing official releases will need to configure the code
signing service so that the Windows installer is signed during the build
Expand All @@ -300,7 +323,42 @@ You can build them by using the following commands:

Release managers will be provided with the necessary credentials by the PMC.

4. Build the release:
If you want to verify the installer from a release by rebuilding it,
you can use the detached signatures provided in the official releases.
In this case you have to use the sources from the source release
archive, which contains these signatures. You also have to build
on Windows, or use Wine, or use a special build of makensis to
create a reproducible installer, that fits the signature files.

5. Using a special "makensis" build on non-Windows (optional)

If you want to build a reproducible installer on non-Windows
by using "makensis" instead of "Wine", you need to build
"makensis" from a source download yourself using the following
recipe. To build makensis, you need python, scons and a C compiler.

First detect the needed version by looking for nsis.version
in build.properties.default.

Download and extract NSIS for Windows by running "ant download-dist". Note
the NSIS installation PATH from the output or by checking "nsis.home" in
build.properties.default. For example:
/home/myuser/tomcat-build-libs/nsis-3.10

Download the correct sources from the same site and run the
following command in the extracted source directory:

scons UNICODE=yes PREFIX=/home/myuser/tomcat-build-libs/nsis-3.10/Bin SKIPPLUGINS=all SKIPUTILS=all SKIPMISC=all NSIS_CONFIG_CONST_DATA_PATH=no VERSION=3.10 install-compiler

You need to specify the correct value in VERSION (this ends up in the installer binary
so it needs to match). The PREFIX needs to be the bin directory of the NSIS
binary distribution that "ant download-dist" installed.

Use this "makensis" binary by making sure, that it gets found by setting
an appropriate PATH environment variable. In addition set the ant property
"nsis.tool" to "makensis" in build.properties.

6. Build the release:

Apache Tomcat releases are fully reproducible.

Expand Down
3 changes: 3 additions & 0 deletions build.properties.default
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ version.dev=-dev

# ----- Build tools -----
ant.version.required=1.10.2
# Which tool to use for building Windows installer
# on unix platform: wine or makensis.
nsis.tool=wine

# ----- Build control flags -----
compile.debug=true
Expand Down
154 changes: 81 additions & 73 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,11 @@
<filter token="JASPIC_SPEC_VERSION" value="${jaspic.spec.version}"/>
</filterset>

<!-- Path filter set -->
<filterset id="path.filters">
<filter token="BASEDIR" value="${basedir}"/>
</filterset>

<!-- Files to change line endings for depending on target platform -->
<patternset id="text.files" >
<include name="**/INSTALLLICENSE"/>
Expand Down Expand Up @@ -2592,19 +2597,35 @@ Apache Tomcat ${version} native binaries for Win64 AMD64/EMT64 platform.
<target name="-installer-pre-init">
<property environment="env" />
<condition property="wine.ok">
<or>
<and>
<equals arg1="${nsis.tool}" arg2="wine" forcestring="true"/>
<available file="wine" filepath="${env.PATH}" />
</and>
</or>
</condition>
<condition property="makensis.ok">
<or>
<and>
<equals arg1="${nsis.tool}" arg2="makensis" forcestring="true"/>
<available file="makensis" filepath="${env.PATH}" />
</and>
</or>
</condition>
<condition property="installer.ok">
<or>
<os family="windows" />
<available file="wine" filepath="${env.PATH}" />
<isset property="skip.installer"/>
<isset property="wine.ok"/>
<isset property="makensis.ok"/>
</or>
</condition>
</target>

<target name="-installer-init" depends="-installer-pre-init" unless="${wine.ok}">
<fail message="The executable wine was not found on the current path.
Wine is required to build the Windows installer when running a release build on
a non-Windows platform. To skip building the Windows installer, set the
skip.installer property in build.properties" />
<target name="-installer-init" depends="-installer-pre-init" unless="${installer.ok}">
<fail message="The executable ${nsis.tool} was not found on the current path.
Either wine or makensis are required to build the Windows installer on a non-Windows platform.
Choose the tool by setting property nsis.tool in build.properties.
To skip building the Windows installer, set the skip.installer property in build.properties" />
</target>

<target name="-installer-prep"
Expand All @@ -2615,20 +2636,16 @@ skip.installer property in build.properties" />
<include name="*.bmp" />
<include name="*.ico" />
<include name="*.xml" />
<include name="Uninstall.exe.sig" />
</fileset>
</copy>
<copy file="res/install-win/tomcat-installer.exe.sig"
tofile="${tomcat.release}/v${version}/bin/${final.name}.exe.sig"
failonerror="false"
quiet="true" />
<copy file="${nsis.installoptions.dll}" todir="${tomcat.dist}" />
<copy file="${nsis.nsexec.dll}" todir="${tomcat.dist}" />
<copy file="${nsis.nsisdl.dll}" todir="${tomcat.dist}" />
<copy file="${nsis.system.dll}" todir="${tomcat.dist}" />
<copy file="${nsis.nsdialogs.dll}" todir="${tomcat.dist}" />
<copy file="res/install-win/tomcat.nsi" tofile="${tomcat.dist}/tomcat.nsi" overwrite="true" encoding="ISO-8859-1">
<filterset refid="version.filters"/>
<filterset refid="path.filters"/>
</copy>
<fixcrlf srcdir="${tomcat.dist}" eol="crlf"
encoding="ISO-8859-1" fixlast="false" >
Expand All @@ -2640,44 +2657,54 @@ skip.installer property in build.properties" />
</touch>
</target>

<target name="-installer-create-tempinstaller"
unless="skip.installer" depends="-installer-prep">
<exec dir="${tomcat.dist}" executable="${nsis.exe}" osfamily="windows">
<arg value="/DUNINSTALLONLY" />
<target name="-installer-wine" if="${wine.ok}">
<exec dir="${tomcat.dist}" executable="wine" osfamily="unix">
<arg value="${nsis.exe}" />
<arg value="/DNSISDIR=${nsis.home}" />
<arg value="/V2" />
<arg value="tomcat.nsi" />
</exec>
<exec dir="${tomcat.dist}" executable="wine" osfamily="unix">
<arg value="${nsis.exe}" />
<arg value="/DUNINSTALLONLY" />
</target>

<target name="-installer-makensis" if="${makensis.ok}">
<exec dir="${tomcat.dist}" executable="makensis" osfamily="unix">
<arg value="-DNSISDIR=${nsis.home}" />
<arg value="-V2" />
<arg value="tomcat.nsi" />
</exec>
</target>

<target name="-installer" unless="skip.installer"
depends="-installer-prep,-installer-wine,-installer-makensis">
<exec dir="${tomcat.dist}" executable="${nsis.exe}" osfamily="windows">
<arg value="/DNSISDIR=${nsis.home}" />
<arg value="/V2" />
<arg value="tomcat.nsi" />
</exec>
</target>

<target name="-installer-create-uninstaller"
unless="skip.installer" depends="-installer-create-tempinstaller">
<!-- Execute the temporary installer to create the uninstaller -->
<exec dir="${tomcat.dist}" executable="${tomcat.dist}/tempinstaller.exe"
osfamily="windows" />
<exec dir="${tomcat.dist}" executable="wine" osfamily="unix">
<arg value="${tomcat.dist}/tempinstaller.exe" />
</exec>
<!-- Reproducible builds: consistent timestamps for installer files -->
<touch datetime="${tstamp.file}" pattern="yyyy-MM-dd HH:mm:ss">
<fileset dir="${tomcat.dist}"/>
</touch>
<target name="installer-sign"
description="Builds and optionally signs the Windows installer"
depends="-installer" unless="skip.installer" >
<move file="${tomcat.dist}/tomcat-installer.exe" tofile="${tomcat.release}/v${version}/bin/${final.name}.exe" />
<!-- .exe has changed so need to redo checksums and OpenPGP signature -->
<delete file="${tomcat.release}/v${version}/bin/${final.name}.exe.asc" />
<delete file="${tomcat.release}/v${version}/bin/${final.name}.exe.sha512" />
<hashAndSign file="${tomcat.release}/v${version}/bin/${final.name}.exe" />
</target>

<target name="-installer-sign-uninstaller"
unless="skip.installer" depends="-installer-create-uninstaller,setup-jsign"
if="${do.codesigning}">
<!-- If the detached signature doesn't exist, this will sign the file -->
<!-- and create the detached signature. If the detached signature does -->
<!-- exist it will be attached to the file. -->
<jsign file="${tomcat.dist}/Uninstall.exe"
<!-- Called via a callback in the NSIS installer script -->
<target name="jsign-installer"
depends="setup-jsign" if="${do.codesigning}" >
<echo>Signing ${tomcat.dist}/tomcat-installer.exe</echo>
<!-- Copy pre-existing detachced signature to signing directory -->
<copy file="res/install-win/tomcat-installer.exe.sig"
tofile="${tomcat.dist}/tomcat-installer.exe.sig"
failonerror="false" />
<!-- If the detached signature doesn't exist, this will sign the file -->
<!-- and create the detached signature. If the detached signature does -->
<!-- exist it will be attached to the file. -->
<jsign file="${tomcat.dist}/tomcat-installer.exe"
storepass="${codesigning.storepass}"
storetype="${codesigning.storetype}"
keypass="${codesigning.keypass}"
Expand All @@ -2686,35 +2713,22 @@ skip.installer property in build.properties" />
tsaurl="http://ts.ssl.com"
tsmode="RFC3161"
detached="true"/>
<!-- Copy detached signature to source tree -->
<copy file="${tomcat.dist}/Uninstall.exe.sig" todir="res/install-win"/>
<!-- Reproducible builds: consistent timestamps for installer files -->
<touch datetime="${tstamp.file}" pattern="yyyy-MM-dd HH:mm:ss">
<fileset dir="${tomcat.dist}"/>
</touch>
</target>

<target name="-installer" unless="skip.installer"
depends="-installer-sign-uninstaller">
<exec dir="${tomcat.dist}" executable="${nsis.exe}" osfamily="windows">
<arg value="/DNSISDIR=${nsis.home}" />
<arg value="/V2" />
<arg value="tomcat.nsi" />
</exec>
<exec dir="${tomcat.dist}" executable="wine" osfamily="unix">
<arg value="${nsis.exe}" />
<arg value="/DNSISDIR=${nsis.home}" />
<arg value="/V2" />
<arg value="tomcat.nsi" />
</exec>
<move file="${tomcat.dist}/tomcat-installer.exe" tofile="${tomcat.release}/v${version}/bin/${final.name}.exe" />
<hashAndSign file="${tomcat.release}/v${version}/bin/${final.name}.exe" />
<!-- Move detached signature to source tree -->
<move file="${tomcat.dist}/tomcat-installer.exe.sig" tofile="res/install-win/tomcat-installer.exe.sig"/>
</target>

<target name="installer-sign"
description="Builds and optionally signs the Windows installer"
depends="-installer,setup-jsign" if="${do.codesigning}" >
<jsign file="${tomcat.release}/v${version}/bin/${final.name}.exe"
<!-- Called via a callback in the NSIS installer script -->
<target name="jsign-uninstaller"
depends="setup-jsign" if="${do.codesigning}" >
<echo>Signing ${codesigning.file_to_sign}</echo>
<!-- Copy pre-existing detachced signature to signing directory -->
<copy file="res/install-win/Uninstall.exe.sig"
tofile="${codesigning.file_to_sign}.sig"
failonerror="false" />
<!-- If the detached signature doesn't exist, this will sign the file -->
<!-- and create the detached signature. If the detached signature does -->
<!-- exist it will be attached to the file. -->
<jsign file="${codesigning.file_to_sign}"
storepass="${codesigning.storepass}"
storetype="${codesigning.storetype}"
keypass="${codesigning.keypass}"
Expand All @@ -2723,14 +2737,8 @@ skip.installer property in build.properties" />
tsaurl="http://ts.ssl.com"
tsmode="RFC3161"
detached="true" />
<!-- Copy detached signature to source tree -->
<copy file="${tomcat.release}/v${version}/bin/${final.name}.exe.sig"
tofile="res/install-win/tomcat-installer.exe.sig"/>
<delete file="${tomcat.release}/v${version}/bin/${final.name}.exe.sig" />
<!-- .exe has changed so need to redo checksums and OpenPGP signature -->
<delete file="${tomcat.release}/v${version}/bin/${final.name}.exe.asc" />
<delete file="${tomcat.release}/v${version}/bin/${final.name}.exe.sha512" />
<hashAndSign file="${tomcat.release}/v${version}/bin/${final.name}.exe" />
<!-- Move detached signature to source tree -->
<move file="${codesigning.file_to_sign}.sig" tofile="res/install-win/Uninstall.exe.sig"/>
</target>

<target name="release-version-check">
Expand Down
Loading

0 comments on commit d49abb6

Please sign in to comment.