mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-26 04:09:35 +03:00
CPack: Add Inno Setup generator
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
if (NOT "$ENV{CMAKE_CI_NIGHTLY}" STREQUAL "")
|
||||
set(CMake_TEST_CPACK_INNOSETUP "ON" CACHE STRING "")
|
||||
set(CMake_TEST_ISPC "ON" CACHE STRING "")
|
||||
endif()
|
||||
set(CMake_TEST_TLS_VERIFY_URL "https://gitlab.kitware.com" CACHE STRING "")
|
||||
|
||||
@@ -0,0 +1,420 @@
|
||||
CPack Inno Setup Generator
|
||||
--------------------------
|
||||
|
||||
.. versionadded:: 3.27
|
||||
|
||||
Inno Setup is a free installer for Windows programs by Jordan Russell and
|
||||
Martijn Laan (https://jrsoftware.org/isinfo.php).
|
||||
|
||||
This documentation explains Inno Setup generator specific options.
|
||||
|
||||
The generator provides a lot of options like components. Unfortunately, not
|
||||
all features (e.g. component dependencies) are currently supported by
|
||||
Inno Setup and they're ignored by the generator for now.
|
||||
|
||||
CPack requires Inno Setup 6 or greater and only works on Windows.
|
||||
|
||||
Variables specific to CPack Inno Setup generator
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You can use the following variables to change the behavior of the CPack
|
||||
``INNOSETUP`` generator:
|
||||
|
||||
|
||||
General
|
||||
"""""""
|
||||
|
||||
None of the following variables is required to be set for the Inno Setup
|
||||
generator to work. If a variable is marked as mandatory below but not set,
|
||||
its default value is taken.
|
||||
|
||||
The variables can also contain Inno Setup constants like ``{app}``. Please
|
||||
refer to the documentation of Inno Setup for more information.
|
||||
|
||||
If you're asked to provide the path to any file, you can always give an
|
||||
absolute path or in most cases the relative path from the top-level directory
|
||||
where all files being installed by an :command:`install` instruction reside.
|
||||
|
||||
CPack tries to escape quotes and other special characters for you. However,
|
||||
using special characters could cause problems.
|
||||
|
||||
The following variable simplifies the usage of Inno Setup in CMake:
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_USE_CMAKE_BOOL_FORMAT
|
||||
|
||||
Inno Setup only uses ``yes`` or ``no`` as boolean formats meanwhile CMake
|
||||
uses a lot of alternative formats like ``ON`` or ``OFF``. Having this option
|
||||
turned on enables an automatic conversion.
|
||||
|
||||
Consider the following example:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
set(CMAKE_INNOSETUP_SETUP_AllowNoIcons OFF)
|
||||
|
||||
If this option is turned on, the following line will be created in the output
|
||||
script: ``AllowNoIcons=no``.
|
||||
Else, the following erroneous line will be created: ``AllowNoIcons=OFF``
|
||||
|
||||
The conversion is enabled in every Inno Setup specific variable.
|
||||
|
||||
:Mandatory: Yes
|
||||
:Default: ``ON``
|
||||
|
||||
|
||||
Setup Specific Variables
|
||||
""""""""""""""""""""""""
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_ARCHITECTURE
|
||||
|
||||
One of ``x86``, ``x64``, ``arm64`` or ``ia64``. This variable specifies the
|
||||
target architecture of the installer. This also affects the Program Files
|
||||
folder or registry keys being used.
|
||||
|
||||
CPack tries to determine the correct value with a try compile (see
|
||||
:variable:`CMAKE_SIZEOF_VOID_P`), but this option can be manually specified
|
||||
too (especially when using ``ia64`` or cross-platform compilation).
|
||||
|
||||
:Mandatory: Yes
|
||||
:Default: Either ``x86`` or ``x64`` depending on the results of the try-compile
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_INSTALL_ROOT
|
||||
|
||||
If you don't want the installer to create the installation directory under
|
||||
Program Files, you've to specify the installation root here.
|
||||
|
||||
The full directory of the installation will be:
|
||||
``${CPACK_INNOSETUP_INSTALL_ROOT}/${CPACK_PACKAGE_INSTALL_DIRECTORY}``.
|
||||
|
||||
:Mandatory: Yes
|
||||
:Default: ``{autopf}``
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_ALLOW_CUSTOM_DIRECTORY
|
||||
|
||||
If turned on, the installer allows the user to change the installation
|
||||
directory providing an extra wizard page.
|
||||
|
||||
:Mandatory: Yes
|
||||
:Default: ``ON``
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_PROGRAM_MENU_FOLDER
|
||||
|
||||
The initial name of the start menu folder being created.
|
||||
|
||||
If this variable is set to ``.``, then no separate folder is created,
|
||||
application shortcuts will appear in the top-level start menu folder.
|
||||
|
||||
:Mandatory: Yes
|
||||
:Default: The value of :variable:`CPACK_PACKAGE_NAME`
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_LANGUAGES
|
||||
|
||||
A :ref:`semicolon-separated list <CMake Language Lists>` of languages you want
|
||||
Inno Setup to include.
|
||||
|
||||
Currently available: ``armenian``, ``brazilianPortuguese``, ``bulgarian``,
|
||||
``catalan``, ``corsican``, ``czech``, ``danish``, ``dutch``, ``english``,
|
||||
``finnish``, ``french``, ``german``, ``hebrew``, ``icelandic``, ``italian``,
|
||||
``japanese``, ``norwegian``, ``polish``, ``portuguese``, ``russian``,
|
||||
``slovak``, ``slovenian``, ``spanish``, ``turkish`` and ``ukrainian``.
|
||||
This list might differ depending on the version of Inno Setup.
|
||||
|
||||
:Mandatory: Yes
|
||||
:Default: ``english``
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_IGNORE_LICENSE_PAGE
|
||||
|
||||
If you don't specify a license file using
|
||||
:variable:`CPACK_RESOURCE_FILE_LICENSE`, CPack uses a file for demonstration
|
||||
purposes. If you want the installer to ignore license files at all, you can
|
||||
enable this option.
|
||||
|
||||
:Mandatory: Yes
|
||||
:Default: ``OFF``
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_IGNORE_README_PAGE
|
||||
|
||||
If you don't specify a readme file using
|
||||
:variable:`CPACK_RESOURCE_FILE_README`, CPack uses a file for demonstration
|
||||
purposes. If you want the installer to ignore readme files at all, you can
|
||||
enable this option. Make sure the option is disabled when using
|
||||
a custom readme file.
|
||||
|
||||
:Mandatory: Yes
|
||||
:Default: ``ON``
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_PASSWORD
|
||||
|
||||
Enables password protection and file encryption with the given password.
|
||||
|
||||
:Mandatory: No
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_USE_MODERN_WIZARD
|
||||
|
||||
Enables the modern look and feel provided by Inno Setup. If this option is
|
||||
turned off, the classic style is used instead. Images and icon files are
|
||||
also affected.
|
||||
|
||||
:Mandatory: Yes
|
||||
:Default: ``OFF`` because of compatibility reasons
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_ICON_FILE
|
||||
|
||||
The path to a custom installer ``.ico`` file.
|
||||
|
||||
Use :variable:`CPACK_PACKAGE_ICON` to customize the bitmap file being shown
|
||||
in the wizard.
|
||||
|
||||
:Mandatory: No
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_SETUP_<directive>
|
||||
|
||||
This group allows adapting any of the ``[Setup]`` section directives provided
|
||||
by Inno Setup where ``directive`` is its name.
|
||||
|
||||
Here are some examples:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
set(CPACK_INNOSETUP_SETUP_WizardSmallImageFile "my_bitmap.bmp")
|
||||
set(CPACK_INNOSETUP_SETUP_AllowNoIcons OFF) # This requires CPACK_INNOSETUP_USE_CMAKE_BOOL_FORMAT to be on
|
||||
|
||||
All of these variables have higher priority than the others.
|
||||
Consider the following example:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
set(CPACK_INNOSETUP_SETUP_Password "admin")
|
||||
set(CPACK_INNOSETUP_PASSWORD "secret")
|
||||
|
||||
The password will be ``admin`` at the end because ``CPACK_INNOSETUP_PASSWORD``
|
||||
has less priority than ``CPACK_INNOSETUP_SETUP_Password``.
|
||||
|
||||
:Mandatory: No
|
||||
|
||||
|
||||
File Specific Variables
|
||||
"""""""""""""""""""""""
|
||||
|
||||
Although all files being installed by an :command:`install` instruction are
|
||||
automatically processed and added to the installer, there are some variables
|
||||
to customize the installation process.
|
||||
|
||||
Before using executables (only ``.exe`` or ``.com``) in shortcuts
|
||||
(e.g. :variable:`CPACK_CREATE_DESKTOP_LINKS`) or ``[Run]`` entries, you've to
|
||||
add the raw file name (without path and extension) to
|
||||
:variable:`CPACK_PACKAGE_EXECUTABLES` and create a start menu shortcut
|
||||
for them.
|
||||
|
||||
If you have two files with the same raw name (e.g. ``a/executable.exe`` and
|
||||
``b/executable.com``), an entry in the section is created twice. This will
|
||||
result in undefined behavior and is not recommended.
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS
|
||||
|
||||
This variable should contain a
|
||||
:ref:`semicolon-separated list <CMake Language Lists>` of pairs ``path``,
|
||||
``instruction`` and can be used to customize the install command being
|
||||
automatically created for each file or directory.
|
||||
|
||||
CPack creates the following Inno Setup instruction for every file...
|
||||
|
||||
.. code-block::
|
||||
|
||||
Source: "absolute\path\to\my_file.txt"; DestDir: "{app}"; Flags: ignoreversion
|
||||
|
||||
...and the following line for every directory:
|
||||
|
||||
.. code-block::
|
||||
|
||||
Name: "{app}\my_folder"
|
||||
|
||||
You might want to change the destination directory or the flags of
|
||||
``my_file.txt``. Since we can also provide a relative path, the line you'd
|
||||
like to have, is the following:
|
||||
|
||||
.. code-block::
|
||||
|
||||
Source: "my_file.txt"; DestDir: "{userdocs}"; Flags: ignoreversion uninsneveruninstall
|
||||
|
||||
You would do this by using ``my_file.txt`` as ``path`` and
|
||||
``Source: "my_file.txt"; DestDir: "{userdocs}"; Flags: ignoreversion uninsneveruninstall``
|
||||
as ``instruction``.
|
||||
|
||||
You've to take care of the `escaping problem <https://cmake.org/cmake/help/book/mastering-cmake/chapter/Packaging%20With%20CPack.html#adding-custom-cpack-options>`_.
|
||||
So the CMake command would be:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
set(CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS "my_file.txt;Source: \\\"my_file.txt\\\"\\; DestDir: \\\"{userdocs}\\\"\\; Flags: ignoreversion uninsneveruninstall")
|
||||
|
||||
To improve readability, you should go around the escaping problem by using
|
||||
:variable:`CPACK_VERBATIM_VARIABLES` or by placing the instruction into a
|
||||
separate CPack project config file.
|
||||
|
||||
If you customize the install instruction of a specific file, you lose the
|
||||
connection to its component. To go around, manually add
|
||||
``Components: <component>``. You also need to add its shortcuts and ``[Run]``
|
||||
entries by yourself in a custom section, since the executable won't be found
|
||||
anymore by :variable:`CPACK_PACKAGE_EXECUTABLES`.
|
||||
|
||||
Here's another example (Note: You've to go around the escaping problem for
|
||||
the example to work):
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
set(CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS
|
||||
"component1/my_folder" "Name: \"{userdocs}\\my_folder\"\; Components: component1"
|
||||
"component2/my_folder2/my_file.txt" "Source: \"component2\\my_folder2\\my_file.txt\"\; DestDir: \"{app}\\my_folder2\\my_file.txt\"\; Flags: ignoreversion uninsneveruninstall\; Components: component2")
|
||||
|
||||
:Mandatory: No
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_MENU_LINKS
|
||||
|
||||
This variable should contain a
|
||||
:ref:`semicolon-separated list <CMake Language Lists>` of pairs ``link``,
|
||||
``link name`` and can be used to add shortcuts into the start menu folder
|
||||
beside those of the executables (see :variable:`CPACK_PACKAGE_EXECUTABLES`).
|
||||
While ``link name`` is the label, ``link`` can be a URL or a path relative to
|
||||
the installation directory.
|
||||
|
||||
Here's an example:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
set(CPACK_INNOSETUP_MENU_LINKS
|
||||
"doc/cmake-@CMake_VERSION_MAJOR@.@CMake_VERSION_MINOR@/cmake.html"
|
||||
"CMake Help" "https://cmake.org" "CMake Web Site")
|
||||
|
||||
:Mandatory: No
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_CREATE_UNINSTALL_LINK
|
||||
|
||||
If this option is turned on, a shortcut to the application's uninstaller is
|
||||
automatically added to the start menu folder.
|
||||
|
||||
:Mandatory: Yes
|
||||
:Default: ``OFF``
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_RUN_EXECUTABLES
|
||||
|
||||
A :ref:`semicolon-separated list <CMake Language Lists>` of executables being
|
||||
specified in :variable:`CPACK_PACKAGE_EXECUTABLES` which the user can run
|
||||
when the installer finishes.
|
||||
|
||||
They're internally added to the ``[Run]`` section.
|
||||
|
||||
:Mandatory: No
|
||||
|
||||
|
||||
Components Specific Variables
|
||||
"""""""""""""""""""""""""""""
|
||||
|
||||
The generator supports components and also downloaded components. However,
|
||||
there are some features of components that aren't supported yet (especially
|
||||
component dependencies). These variables are ignored for now.
|
||||
|
||||
CPack will change a component's name in Inno Setup if it has a parent group
|
||||
for technical reasons. Consider using ``group\component`` as component name in
|
||||
Inno Setup scripts if you have the component ``component`` and its parent
|
||||
group ``group``.
|
||||
|
||||
Here are some additional variables for components:
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_<compName>_INSTALL_DIRECTORY
|
||||
|
||||
If you don't want the component ``compName`` to be installed under ``{app}``,
|
||||
you've to specify its installation directory here.
|
||||
|
||||
:Mandatory: No
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_VERIFY_DOWNLOADS
|
||||
|
||||
This option only affects downloaded components.
|
||||
|
||||
If this option is turned on, the hashes of the downloaded archives are
|
||||
calculated during compile and
|
||||
download time. The installer will only proceed if they match.
|
||||
|
||||
:Mandatory: Yes
|
||||
:Default: ``ON``
|
||||
|
||||
|
||||
Compilation and Scripting Specific Variables
|
||||
""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_EXECUTABLE
|
||||
|
||||
The filename of the Inno Setup Script Compiler command.
|
||||
|
||||
:Mandatory: Yes
|
||||
:Default: ``ISCC``
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_EXECUTABLE_ARGUMENTS
|
||||
|
||||
A :ref:`semicolon-separated list <CMake Language Lists>` of extra
|
||||
command-line options for the Inno Setup Script Compiler command.
|
||||
|
||||
For example: ``/Qp;/Smysigntool=$p``
|
||||
|
||||
Take care of the `escaping problem <https://cmake.org/cmake/help/book/mastering-cmake/chapter/Packaging%20With%20CPack.html#adding-custom-cpack-options>`_.
|
||||
|
||||
:Mandatory: No
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_DEFINE_<macro>
|
||||
|
||||
This group allows to add custom define directives as command-line options to
|
||||
the Inno Setup Preprocessor command. Each entry emulates a
|
||||
``#define public <macro>`` directive. Its macro is accessible from anywhere
|
||||
(``public``), so it can also be used in extra script files.
|
||||
|
||||
Macro names must not contain any special characters. Refer to the Inno Setup
|
||||
Preprocessor documentation for the detailed rules.
|
||||
|
||||
Consider the following example:
|
||||
|
||||
.. code-block:: cmake
|
||||
|
||||
# The following line emulates: #define public MyMacro "Hello, World!"
|
||||
set(CPACK_INNOSETUP_DEFINE_MyMacro "Hello, World!")
|
||||
|
||||
At this point, you can use ``MyMacro`` anywhere. For example in the following
|
||||
extra script:
|
||||
|
||||
.. code-block::
|
||||
|
||||
AppComments={#emit "'My Macro' has the value: " + MyMacro}
|
||||
|
||||
Take care of the `escaping problem <https://cmake.org/cmake/help/book/mastering-cmake/chapter/Packaging%20With%20CPack.html#adding-custom-cpack-options>`_.
|
||||
|
||||
:Mandatory: No
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_EXTRA_SCRIPTS
|
||||
|
||||
A :ref:`semicolon-separated list <CMake Language Lists>` of paths to
|
||||
additional ``.iss`` script files to be processed.
|
||||
|
||||
They're internally included at the top of the output script file using a
|
||||
``#include`` directive.
|
||||
|
||||
You can add any section in your file to extend the installer (e.g. adding
|
||||
additional tasks or registry keys). Prefer using
|
||||
:variable:`CPACK_INNOSETUP_SETUP_<directive>` when extending the
|
||||
``[Setup]`` section.
|
||||
|
||||
:Mandatory: No
|
||||
|
||||
.. variable:: CPACK_INNOSETUP_CODE_FILES
|
||||
|
||||
A :ref:`semicolon-separated list <CMake Language Lists>` of paths to
|
||||
additional Pascal files to be processed.
|
||||
|
||||
This variable is actually the same as
|
||||
:variable:`CPACK_INNOSETUP_EXTRA_SCRIPTS`, except you don't have to
|
||||
add ``[Code]`` at the top of your file. Never change the current section in
|
||||
a code file. This will result in undefined behavior! Treat them as normal
|
||||
Pascal scripts instead.
|
||||
|
||||
Code files are included at the very bottom of the output script.
|
||||
|
||||
:Mandatory: No
|
||||
@@ -20,6 +20,7 @@ Generators
|
||||
/cpack_gen/dmg
|
||||
/cpack_gen/external
|
||||
/cpack_gen/freebsd
|
||||
/cpack_gen/innosetup
|
||||
/cpack_gen/ifw
|
||||
/cpack_gen/nsis
|
||||
/cpack_gen/nuget
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
cpack-innosetup
|
||||
---------------
|
||||
|
||||
* The :cpack_gen:`CPack Inno Setup Generator` was added to package using
|
||||
Inno Setup.
|
||||
|
||||
The new generator adds:
|
||||
|
||||
* A lot of options to customize the Inno Setup installer (e.g. custom
|
||||
installation rules)
|
||||
* Start menu and desktop shortcuts
|
||||
* Components (and also downloaded components)
|
||||
+17
-7
@@ -262,8 +262,8 @@ installers. The most commonly-used variables are:
|
||||
Lists each of the executables and associated text label to be used to
|
||||
create Start Menu shortcuts. For example, setting this to the list
|
||||
``ccmake;CMake`` will create a shortcut named "CMake" that will execute the
|
||||
installed executable :program:`ccmake`. Not all CPack generators use it (at least
|
||||
NSIS, and WIX do).
|
||||
installed executable :program:`ccmake`. Not all CPack generators use it (at least
|
||||
NSIS, Inno Setup and WIX do).
|
||||
|
||||
.. variable:: CPACK_STRIP_FILES
|
||||
|
||||
@@ -738,14 +738,16 @@ if(NOT CPACK_GENERATOR)
|
||||
)
|
||||
endif()
|
||||
else()
|
||||
option(CPACK_BINARY_7Z "Enable to build 7-Zip packages" OFF)
|
||||
option(CPACK_BINARY_NSIS "Enable to build NSIS packages" ON)
|
||||
option(CPACK_BINARY_NUGET "Enable to build NuGet packages" OFF)
|
||||
option(CPACK_BINARY_WIX "Enable to build WiX packages" OFF)
|
||||
option(CPACK_BINARY_ZIP "Enable to build ZIP packages" OFF)
|
||||
option(CPACK_BINARY_7Z "Enable to build 7-Zip packages" OFF)
|
||||
option(CPACK_BINARY_NSIS "Enable to build NSIS packages" ON)
|
||||
option(CPACK_BINARY_INNOSETUP "Enable to build Inno Setup packages" OFF)
|
||||
option(CPACK_BINARY_NUGET "Enable to build NuGet packages" OFF)
|
||||
option(CPACK_BINARY_WIX "Enable to build WiX packages" OFF)
|
||||
option(CPACK_BINARY_ZIP "Enable to build ZIP packages" OFF)
|
||||
mark_as_advanced(
|
||||
CPACK_BINARY_7Z
|
||||
CPACK_BINARY_NSIS
|
||||
CPACK_BINARY_INNOSETUP
|
||||
CPACK_BINARY_NUGET
|
||||
CPACK_BINARY_WIX
|
||||
CPACK_BINARY_ZIP
|
||||
@@ -762,6 +764,7 @@ if(NOT CPACK_GENERATOR)
|
||||
cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_FREEBSD FREEBSD)
|
||||
cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_IFW IFW)
|
||||
cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_NSIS NSIS)
|
||||
cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_INNOSETUP INNOSETUP)
|
||||
cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_NUGET NuGet)
|
||||
cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_PRODUCTBUILD productbuild)
|
||||
cpack_optional_append(CPACK_GENERATOR CPACK_BINARY_RPM RPM)
|
||||
@@ -869,6 +872,13 @@ if(NOT DEFINED CPACK_DMG_SLA_USE_RESOURCE_FILE_LICENSE
|
||||
unset(_CPack_CMP0133)
|
||||
endif()
|
||||
|
||||
# Inno Setup specific variables
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
_cpack_set_default(CPACK_INNOSETUP_ARCHITECTURE "x86")
|
||||
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
_cpack_set_default(CPACK_INNOSETUP_ARCHITECTURE "x64")
|
||||
endif()
|
||||
|
||||
# WiX specific variables
|
||||
_cpack_set_default(CPACK_WIX_SIZEOF_VOID_P "${CMAKE_SIZEOF_VOID_P}")
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
{ Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. }
|
||||
|
||||
function CPackGetCustomInstallationMessage(Param: String): String;
|
||||
begin
|
||||
Result := SetupMessage(msgCustomInstallation);
|
||||
end;
|
||||
|
||||
{ Downloaded components }
|
||||
#ifdef CPackDownloadCount
|
||||
const
|
||||
NO_PROGRESS_BOX = 4;
|
||||
RESPOND_YES_TO_ALL = 16;
|
||||
var
|
||||
CPackDownloadPage: TDownloadWizardPage;
|
||||
CPackShell: Variant;
|
||||
|
||||
<event('InitializeWizard')>
|
||||
procedure CPackInitializeWizard();
|
||||
begin
|
||||
CPackDownloadPage := CreateDownloadPage(SetupMessage(msgWizardPreparing), SetupMessage(msgPreparingDesc), nil);
|
||||
CPackShell := CreateOleObject('Shell.Application');
|
||||
end;
|
||||
|
||||
<event('NextButtonClick')>
|
||||
function CPackNextButtonClick(CurPageID: Integer): Boolean;
|
||||
begin
|
||||
if CurPageID = wpReady then
|
||||
begin
|
||||
CPackDownloadPage.Clear;
|
||||
CPackDownloadPage.Show;
|
||||
|
||||
#sub AddDownload
|
||||
if WizardIsComponentSelected('{#CPackDownloadComponents[i]}') then
|
||||
#emit "CPackDownloadPage.Add('" + CPackDownloadUrls[i] + "', '" + CPackDownloadArchives[i] + ".zip', '" + CPackDownloadHashes[i] + "');"
|
||||
#endsub
|
||||
#define i
|
||||
#for {i = 0; i < CPackDownloadCount; i++} AddDownload
|
||||
#undef i
|
||||
|
||||
try
|
||||
try
|
||||
CPackDownloadPage.Download;
|
||||
Result := True;
|
||||
except
|
||||
if not CPackDownloadPage.AbortedByUser then
|
||||
SuppressibleMsgBox(AddPeriod(GetExceptionMessage), mbCriticalError, MB_OK, IDOK);
|
||||
|
||||
Result := False;
|
||||
end;
|
||||
finally
|
||||
CPackDownloadPage.Hide;
|
||||
end;
|
||||
end else
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
procedure CPackExtractFile(ArchiveName, FileName: String);
|
||||
var
|
||||
ZipFileName: String;
|
||||
ZipFile: Variant;
|
||||
Item: Variant;
|
||||
TargetFolderName: String;
|
||||
TargetFolder: Variant;
|
||||
begin
|
||||
TargetFolderName := RemoveBackslashUnlessRoot(ExpandConstant('{tmp}\' + ArchiveName + '\' + ExtractFileDir(FileName)));
|
||||
ZipFileName := ExpandConstant('{tmp}\' + ArchiveName + '.zip');
|
||||
|
||||
if not DirExists(TargetFolderName) then
|
||||
if not ForceDirectories(TargetFolderName) then
|
||||
RaiseException(Format('Target path "%s" cannot be created', [TargetFolderName]));
|
||||
|
||||
ZipFile := CPackShell.NameSpace(ZipFileName);
|
||||
if VarIsClear(ZipFile) then
|
||||
RaiseException(Format('Cannot open ZIP file "%s" or does not exist', [ZipFileName]));
|
||||
|
||||
Item := ZipFile.ParseName(FileName);
|
||||
if VarIsClear(Item) then
|
||||
RaiseException(Format('Cannot find "%s" in "%s" ZIP file', [FileName, ZipFileName]));
|
||||
|
||||
TargetFolder := CPackShell.NameSpace(TargetFolderName);
|
||||
if VarIsClear(TargetFolder) then
|
||||
RaiseException(Format('Target path "%s" does not exist', [TargetFolderName]));
|
||||
|
||||
TargetFolder.CopyHere(Item, NO_PROGRESS_BOX or RESPOND_YES_TO_ALL);
|
||||
end;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
; Script generated by the CPack Inno Setup generator.
|
||||
; All changes made in this file will be lost when CPack is run again.
|
||||
|
||||
@CPACK_INNOSETUP_INCLUDES_INTERNAL@
|
||||
|
||||
[Setup]
|
||||
@CPACK_INNOSETUP_SETUP_INTERNAL@
|
||||
|
||||
[Languages]
|
||||
@CPACK_INNOSETUP_LANGUAGES_INTERNAL@
|
||||
|
||||
[Dirs]
|
||||
@CPACK_INNOSETUP_DIRS_INTERNAL@
|
||||
|
||||
[Files]
|
||||
@CPACK_INNOSETUP_FILES_INTERNAL@
|
||||
|
||||
[Types]
|
||||
@CPACK_INNOSETUP_TYPES_INTERNAL@
|
||||
|
||||
[Components]
|
||||
@CPACK_INNOSETUP_COMPONENTS_INTERNAL@
|
||||
|
||||
[Tasks]
|
||||
@CPACK_INNOSETUP_TASKS_INTERNAL@
|
||||
|
||||
[Icons]
|
||||
@CPACK_INNOSETUP_ICONS_INTERNAL@
|
||||
|
||||
[Run]
|
||||
@CPACK_INNOSETUP_RUN_INTERNAL@
|
||||
|
||||
[Code]
|
||||
@CPACK_INNOSETUP_CODE_INTERNAL@
|
||||
@@ -1018,6 +1018,7 @@ add_library(
|
||||
CPack/cmCPackGeneratorFactory.cxx
|
||||
CPack/cmCPackGenerator.cxx
|
||||
CPack/cmCPackLog.cxx
|
||||
CPack/cmCPackInnoSetupGenerator.cxx
|
||||
CPack/cmCPackNSISGenerator.cxx
|
||||
CPack/cmCPackNuGetGenerator.cxx
|
||||
CPack/cmCPackSTGZGenerator.cxx
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "cmCPackDebGenerator.h"
|
||||
#include "cmCPackExternalGenerator.h"
|
||||
#include "cmCPackGenerator.h"
|
||||
#include "cmCPackInnoSetupGenerator.h"
|
||||
#include "cmCPackLog.h"
|
||||
#include "cmCPackNSISGenerator.h"
|
||||
#include "cmCPackNuGetGenerator.h"
|
||||
@@ -60,6 +61,10 @@ cmCPackGeneratorFactory::cmCPackGeneratorFactory()
|
||||
this->RegisterGenerator("STGZ", "Self extracting Tar GZip compression",
|
||||
cmCPackSTGZGenerator::CreateGenerator);
|
||||
}
|
||||
if (cmCPackInnoSetupGenerator::CanGenerate()) {
|
||||
this->RegisterGenerator("INNOSETUP", "Inno Setup packages",
|
||||
cmCPackInnoSetupGenerator::CreateGenerator);
|
||||
}
|
||||
if (cmCPackNSISGenerator::CanGenerate()) {
|
||||
this->RegisterGenerator("NSIS", "Null Soft Installer",
|
||||
cmCPackNSISGenerator::CreateGenerator);
|
||||
|
||||
@@ -0,0 +1,1159 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
|
||||
#include "cmCPackInnoSetupGenerator.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include <ostream>
|
||||
#include <stack>
|
||||
#include <utility>
|
||||
|
||||
#include "cmsys/RegularExpression.hxx"
|
||||
|
||||
#include "cmCPackComponentGroup.h"
|
||||
#include "cmCPackLog.h"
|
||||
#include "cmDuration.h"
|
||||
#include "cmGeneratedFileStream.h"
|
||||
#include "cmList.h"
|
||||
#include "cmStringAlgorithms.h"
|
||||
#include "cmSystemTools.h"
|
||||
|
||||
cmCPackInnoSetupGenerator::cmCPackInnoSetupGenerator() = default;
|
||||
cmCPackInnoSetupGenerator::~cmCPackInnoSetupGenerator() = default;
|
||||
|
||||
bool cmCPackInnoSetupGenerator::CanGenerate()
|
||||
{
|
||||
// Inno Setup is only available for Windows
|
||||
#ifdef _WIN32
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
int cmCPackInnoSetupGenerator::InitializeInternal()
|
||||
{
|
||||
if (cmIsOn(GetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY"))) {
|
||||
cmCPackLogger(cmCPackLog::LOG_WARNING,
|
||||
"Inno Setup Generator cannot work with "
|
||||
"CPACK_INCLUDE_TOPLEVEL_DIRECTORY set. "
|
||||
"This option will be reset to 0 (for this generator only)."
|
||||
<< std::endl);
|
||||
SetOption("CPACK_INCLUDE_TOPLEVEL_DIRECTORY", nullptr);
|
||||
}
|
||||
|
||||
std::vector<std::string> path;
|
||||
|
||||
#ifdef _WIN32
|
||||
path.push_back("C:\\Program Files (x86)\\Inno Setup 5");
|
||||
path.push_back("C:\\Program Files (x86)\\Inno Setup 6");
|
||||
#endif
|
||||
|
||||
SetOptionIfNotSet("CPACK_INNOSETUP_EXECUTABLE", "ISCC");
|
||||
const std::string& isccPath = cmSystemTools::FindProgram(
|
||||
GetOption("CPACK_INNOSETUP_EXECUTABLE"), path, false);
|
||||
|
||||
if (isccPath.empty()) {
|
||||
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
||||
"Cannot find Inno Setup compiler ISCC: "
|
||||
"likely it is not installed, or not in your PATH"
|
||||
<< std::endl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::string isccCmd = cmStrCat(QuotePath(isccPath), "/?");
|
||||
cmCPackLogger(cmCPackLog::LOG_VERBOSE,
|
||||
"Test Inno Setup version: " << isccCmd << std::endl);
|
||||
std::string output;
|
||||
cmSystemTools::RunSingleCommand(isccCmd, &output, &output, nullptr, nullptr,
|
||||
this->GeneratorVerbose, cmDuration::zero());
|
||||
cmsys::RegularExpression vRex("Inno Setup ([0-9]+)");
|
||||
if (!vRex.find(output)) {
|
||||
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
||||
"Problem checking Inno Setup version with command: "
|
||||
<< isccCmd << std::endl
|
||||
<< "Have you downloaded Inno Setup from "
|
||||
"https://jrsoftware.org/isinfo.php?"
|
||||
<< std::endl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int isccVersion = atoi(vRex.match(1).c_str());
|
||||
const int minIsccVersion = 6;
|
||||
cmCPackLogger(cmCPackLog::LOG_DEBUG,
|
||||
"Inno Setup Version: " << isccVersion << std::endl);
|
||||
|
||||
if (isccVersion < minIsccVersion) {
|
||||
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
||||
"CPack requires Inno Setup Version 6 or greater. "
|
||||
"Inno Setup found on the system was: "
|
||||
<< isccVersion << std::endl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SetOption("CPACK_INSTALLER_PROGRAM", isccPath);
|
||||
|
||||
return this->Superclass::InitializeInternal();
|
||||
}
|
||||
|
||||
int cmCPackInnoSetupGenerator::PackageFiles()
|
||||
{
|
||||
// Includes
|
||||
if (IsSet("CPACK_INNOSETUP_EXTRA_SCRIPTS")) {
|
||||
const cmList extraScripts(GetOption("CPACK_INNOSETUP_EXTRA_SCRIPTS"));
|
||||
|
||||
for (const std::string& i : extraScripts) {
|
||||
includeDirectives.push_back(cmStrCat(
|
||||
"#include ", QuotePath(cmSystemTools::CollapseFullPath(i, toplevel))));
|
||||
}
|
||||
}
|
||||
|
||||
// [Languages] section
|
||||
SetOptionIfNotSet("CPACK_INNOSETUP_LANGUAGES", "english");
|
||||
const cmList languages(GetOption("CPACK_INNOSETUP_LANGUAGES"));
|
||||
for (std::string i : languages) {
|
||||
cmCPackInnoSetupKeyValuePairs params;
|
||||
|
||||
params["Name"] = Quote(i);
|
||||
|
||||
if (cmSystemTools::LowerCase(i) == "english") {
|
||||
params["MessagesFile"] = "\"compiler:Default.isl\"";
|
||||
} else {
|
||||
i[0] = static_cast<char>(std::toupper(i[0]));
|
||||
params["MessagesFile"] = cmStrCat("\"compiler:Languages\\", i, ".isl\"");
|
||||
}
|
||||
|
||||
languageInstructions.push_back(ISKeyValueLine(params));
|
||||
}
|
||||
|
||||
if (!Components.empty() && !ProcessComponents()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(ProcessSetupSection() && ProcessFiles())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// [Code] section
|
||||
if (IsSet("CPACK_INNOSETUP_CODE_FILES")) {
|
||||
const cmList codeFiles(GetOption("CPACK_INNOSETUP_CODE_FILES"));
|
||||
|
||||
for (const std::string& i : codeFiles) {
|
||||
codeIncludes.push_back(cmStrCat(
|
||||
"#include ", QuotePath(cmSystemTools::CollapseFullPath(i, toplevel))));
|
||||
}
|
||||
}
|
||||
|
||||
return ConfigureISScript() && Compile();
|
||||
}
|
||||
|
||||
bool cmCPackInnoSetupGenerator::ProcessSetupSection()
|
||||
{
|
||||
if (!RequireOption("CPACK_PACKAGE_INSTALL_REGISTRY_KEY")) {
|
||||
return false;
|
||||
}
|
||||
setupDirectives["AppId"] = GetOption("CPACK_PACKAGE_INSTALL_REGISTRY_KEY");
|
||||
|
||||
if (!RequireOption("CPACK_PACKAGE_NAME")) {
|
||||
return false;
|
||||
}
|
||||
setupDirectives["AppName"] = GetOption("CPACK_PACKAGE_NAME");
|
||||
setupDirectives["UninstallDisplayName"] = GetOption("CPACK_PACKAGE_NAME");
|
||||
|
||||
if (!RequireOption("CPACK_PACKAGE_VERSION")) {
|
||||
return false;
|
||||
}
|
||||
setupDirectives["AppVersion"] = GetOption("CPACK_PACKAGE_VERSION");
|
||||
|
||||
if (!RequireOption("CPACK_PACKAGE_VENDOR")) {
|
||||
return false;
|
||||
}
|
||||
setupDirectives["AppPublisher"] = GetOption("CPACK_PACKAGE_VENDOR");
|
||||
|
||||
if (IsSet("CPACK_PACKAGE_HOMEPAGE_URL")) {
|
||||
setupDirectives["AppPublisherURL"] =
|
||||
GetOption("CPACK_PACKAGE_HOMEPAGE_URL");
|
||||
setupDirectives["AppSupportURL"] = GetOption("CPACK_PACKAGE_HOMEPAGE_URL");
|
||||
setupDirectives["AppUpdatesURL"] = GetOption("CPACK_PACKAGE_HOMEPAGE_URL");
|
||||
}
|
||||
|
||||
SetOptionIfNotSet("CPACK_INNOSETUP_IGNORE_LICENSE_PAGE", "OFF");
|
||||
if (IsSet("CPACK_RESOURCE_FILE_LICENSE") &&
|
||||
!GetOption("CPACK_INNOSETUP_IGNORE_LICENSE_PAGE").IsOn()) {
|
||||
setupDirectives["LicenseFile"] = cmSystemTools::ConvertToWindowsOutputPath(
|
||||
GetOption("CPACK_RESOURCE_FILE_LICENSE"));
|
||||
}
|
||||
|
||||
SetOptionIfNotSet("CPACK_INNOSETUP_IGNORE_README_PAGE", "ON");
|
||||
if (IsSet("CPACK_RESOURCE_FILE_README") &&
|
||||
!GetOption("CPACK_INNOSETUP_IGNORE_README_PAGE").IsOn()) {
|
||||
setupDirectives["InfoBeforeFile"] =
|
||||
cmSystemTools::ConvertToWindowsOutputPath(
|
||||
GetOption("CPACK_RESOURCE_FILE_README"));
|
||||
}
|
||||
|
||||
SetOptionIfNotSet("CPACK_INNOSETUP_USE_MODERN_WIZARD", "OFF");
|
||||
if (GetOption("CPACK_INNOSETUP_USE_MODERN_WIZARD").IsOn()) {
|
||||
setupDirectives["WizardStyle"] = "modern";
|
||||
} else {
|
||||
setupDirectives["WizardStyle"] = "classic";
|
||||
setupDirectives["WizardSmallImageFile"] =
|
||||
"compiler:WizClassicSmallImage.bmp";
|
||||
setupDirectives["WizardImageFile"] = "compiler:WizClassicImage.bmp";
|
||||
setupDirectives["SetupIconFile"] = "compiler:SetupClassicIcon.ico";
|
||||
}
|
||||
|
||||
if (IsSet("CPACK_INNOSETUP_ICON_FILE")) {
|
||||
setupDirectives["SetupIconFile"] =
|
||||
cmSystemTools::ConvertToWindowsOutputPath(
|
||||
GetOption("CPACK_INNOSETUP_ICON_FILE"));
|
||||
}
|
||||
|
||||
if (IsSet("CPACK_PACKAGE_ICON")) {
|
||||
setupDirectives["WizardSmallImageFile"] =
|
||||
cmSystemTools::ConvertToWindowsOutputPath(
|
||||
GetOption("CPACK_PACKAGE_ICON"));
|
||||
}
|
||||
|
||||
if (!RequireOption("CPACK_PACKAGE_INSTALL_DIRECTORY")) {
|
||||
return false;
|
||||
}
|
||||
SetOptionIfNotSet("CPACK_INNOSETUP_INSTALL_ROOT", "{autopf}");
|
||||
setupDirectives["DefaultDirName"] =
|
||||
cmSystemTools::ConvertToWindowsOutputPath(
|
||||
cmStrCat(GetOption("CPACK_INNOSETUP_INSTALL_ROOT"), '\\',
|
||||
GetOption("CPACK_PACKAGE_INSTALL_DIRECTORY")));
|
||||
|
||||
SetOptionIfNotSet("CPACK_INNOSETUP_ALLOW_CUSTOM_DIRECTORY", "ON");
|
||||
if (GetOption("CPACK_INNOSETUP_ALLOW_CUSTOM_DIRECTORY").IsOff()) {
|
||||
setupDirectives["DisableDirPage"] = "yes";
|
||||
}
|
||||
|
||||
SetOptionIfNotSet("CPACK_INNOSETUP_PROGRAM_MENU_FOLDER",
|
||||
GetOption("CPACK_PACKAGE_NAME"));
|
||||
if (GetOption("CPACK_INNOSETUP_PROGRAM_MENU_FOLDER") == ".") {
|
||||
setupDirectives["DisableProgramGroupPage"] = "yes";
|
||||
toplevelProgramFolder = true;
|
||||
} else {
|
||||
setupDirectives["DefaultGroupName"] =
|
||||
GetOption("CPACK_INNOSETUP_PROGRAM_MENU_FOLDER");
|
||||
toplevelProgramFolder = false;
|
||||
}
|
||||
|
||||
if (IsSet("CPACK_INNOSETUP_PASSWORD")) {
|
||||
setupDirectives["Password"] = GetOption("CPACK_INNOSETUP_PASSWORD");
|
||||
setupDirectives["Encryption"] = "yes";
|
||||
}
|
||||
|
||||
/*
|
||||
* These directives can only be modified using the
|
||||
* CPACK_INNOSETUP_SETUP_<directive> variables
|
||||
*/
|
||||
setupDirectives["ShowLanguageDialog"] = "auto";
|
||||
setupDirectives["AllowNoIcons"] = "yes";
|
||||
setupDirectives["Compression"] = "lzma";
|
||||
setupDirectives["SolidCompression"] = "yes";
|
||||
|
||||
// Output file and directory
|
||||
if (!RequireOption("CPACK_PACKAGE_FILE_NAME")) {
|
||||
return false;
|
||||
}
|
||||
setupDirectives["OutputBaseFilename"] = GetOption("CPACK_PACKAGE_FILE_NAME");
|
||||
|
||||
if (!RequireOption("CPACK_TOPLEVEL_DIRECTORY")) {
|
||||
return false;
|
||||
}
|
||||
setupDirectives["OutputDir"] = cmSystemTools::ConvertToWindowsOutputPath(
|
||||
GetOption("CPACK_TOPLEVEL_DIRECTORY"));
|
||||
|
||||
setupDirectives["SourceDir"] =
|
||||
cmSystemTools::ConvertToWindowsOutputPath(toplevel);
|
||||
|
||||
// Target architecture
|
||||
if (!RequireOption("CPACK_INNOSETUP_ARCHITECTURE")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string& architecture = GetOption("CPACK_INNOSETUP_ARCHITECTURE");
|
||||
if (architecture != "x86" && architecture != "x64" &&
|
||||
architecture != "arm64" && architecture != "ia64") {
|
||||
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
||||
"CPACK_INNOSETUP_ARCHITECTURE must be either x86, x64, "
|
||||
"arm64 or ia64"
|
||||
<< std::endl);
|
||||
return false;
|
||||
}
|
||||
|
||||
// The following directives must not be set to target x86
|
||||
if (architecture != "x86") {
|
||||
setupDirectives["ArchitecturesAllowed"] = architecture;
|
||||
setupDirectives["ArchitecturesInstallIn64BitMode"] = architecture;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle custom directives (they have higher priority than other variables,
|
||||
* so they have to be processed after all other variables)
|
||||
*/
|
||||
for (const std::string& i : GetOptions()) {
|
||||
if (cmHasPrefix(i, "CPACK_INNOSETUP_SETUP_")) {
|
||||
const std::string& directive =
|
||||
i.substr(cmStrLen("CPACK_INNOSETUP_SETUP_"));
|
||||
setupDirectives[directive] = GetOption(i);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmCPackInnoSetupGenerator::ProcessFiles()
|
||||
{
|
||||
std::map<std::string, std::string> customFileInstructions;
|
||||
if (IsSet("CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS")) {
|
||||
const cmList instructions(
|
||||
GetOption("CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS"));
|
||||
if (instructions.size() % 2 != 0) {
|
||||
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
||||
"CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS should "
|
||||
"contain pairs of <path> and <instruction>"
|
||||
<< std::endl);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto it = instructions.begin(); it != instructions.end(); ++it) {
|
||||
const std::string& key =
|
||||
QuotePath(cmSystemTools::CollapseFullPath(*it, toplevel));
|
||||
customFileInstructions[key] = *(++it);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& iconsPrefix =
|
||||
toplevelProgramFolder ? "{autoprograms}\\" : "{group}\\";
|
||||
|
||||
std::map<std::string, std::string> icons;
|
||||
if (IsSet("CPACK_PACKAGE_EXECUTABLES")) {
|
||||
const cmList executables(GetOption("CPACK_PACKAGE_EXECUTABLES"));
|
||||
if (executables.size() % 2 != 0) {
|
||||
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
||||
"CPACK_PACKAGE_EXECUTABLES should should contain pairs of "
|
||||
"<executable> and <text label>"
|
||||
<< std::endl);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto it = executables.begin(); it != executables.end(); ++it) {
|
||||
const std::string& key = *it;
|
||||
icons[key] = *(++it);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> desktopIcons;
|
||||
if (IsSet("CPACK_CREATE_DESKTOP_LINKS")) {
|
||||
cmExpandList(GetOption("CPACK_CREATE_DESKTOP_LINKS"), desktopIcons);
|
||||
}
|
||||
|
||||
std::vector<std::string> runExecutables;
|
||||
if (IsSet("CPACK_INNOSETUP_RUN_EXECUTABLES")) {
|
||||
cmExpandList(GetOption("CPACK_INNOSETUP_RUN_EXECUTABLES"), runExecutables);
|
||||
}
|
||||
|
||||
for (const std::string& i : files) {
|
||||
cmCPackInnoSetupKeyValuePairs params;
|
||||
|
||||
std::string toplevelDirectory;
|
||||
std::string outputDir;
|
||||
cmCPackComponent* component = nullptr;
|
||||
std::string componentParam;
|
||||
if (!Components.empty()) {
|
||||
const std::string& fileName = cmSystemTools::RelativePath(toplevel, i);
|
||||
const std::string::size_type pos = fileName.find('/');
|
||||
|
||||
// Use the custom component install directory if we have one
|
||||
if (pos != std::string::npos) {
|
||||
const std::string& componentName = fileName.substr(0, pos);
|
||||
component = &Components[componentName];
|
||||
|
||||
toplevelDirectory =
|
||||
cmSystemTools::CollapseFullPath(componentName, toplevel);
|
||||
outputDir = CustomComponentInstallDirectory(component);
|
||||
componentParam =
|
||||
CreateRecursiveComponentPath(component->Group, component->Name);
|
||||
|
||||
if (component->IsHidden && component->IsDisabledByDefault) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (component->IsHidden) {
|
||||
componentParam.clear();
|
||||
}
|
||||
} else {
|
||||
// Don't install component directories
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
toplevelDirectory = toplevel;
|
||||
outputDir = "{app}";
|
||||
}
|
||||
|
||||
if (!componentParam.empty()) {
|
||||
params["Components"] = componentParam;
|
||||
}
|
||||
|
||||
if (cmSystemTools::FileIsDirectory(i)) {
|
||||
// Custom instructions replace the automatic generated instructions
|
||||
if (customFileInstructions.count(QuotePath(i))) {
|
||||
dirInstructions.push_back(customFileInstructions[QuotePath(i)]);
|
||||
} else {
|
||||
std::string destDir = cmSystemTools::ConvertToWindowsOutputPath(
|
||||
cmStrCat(outputDir, '\\',
|
||||
cmSystemTools::RelativePath(toplevelDirectory, i)));
|
||||
cmStripSuffixIfExists(destDir, '\\');
|
||||
|
||||
params["Name"] = QuotePath(destDir);
|
||||
|
||||
dirInstructions.push_back(ISKeyValueLine(params));
|
||||
}
|
||||
} else {
|
||||
// Custom instructions replace the automatic generated instructions
|
||||
if (customFileInstructions.count(QuotePath(i))) {
|
||||
fileInstructions.push_back(customFileInstructions[QuotePath(i)]);
|
||||
} else {
|
||||
std::string destDir = cmSystemTools::ConvertToWindowsOutputPath(
|
||||
cmStrCat(outputDir, '\\',
|
||||
cmSystemTools::GetParentDirectory(
|
||||
cmSystemTools::RelativePath(toplevelDirectory, i))));
|
||||
cmStripSuffixIfExists(destDir, '\\');
|
||||
|
||||
params["DestDir"] = QuotePath(destDir);
|
||||
|
||||
if (component != nullptr && component->IsDownloaded) {
|
||||
const std::string& archiveName =
|
||||
cmSystemTools::GetFilenameWithoutLastExtension(
|
||||
component->ArchiveFile);
|
||||
const std::string& relativePath =
|
||||
cmSystemTools::RelativePath(toplevelDirectory, i);
|
||||
|
||||
params["Source"] =
|
||||
QuotePath(cmStrCat("{tmp}\\", archiveName, '\\', relativePath));
|
||||
params["ExternalSize"] =
|
||||
std::to_string(cmSystemTools::FileLength(i));
|
||||
params["Flags"] = "external ignoreversion";
|
||||
params["BeforeInstall"] =
|
||||
cmStrCat("CPackExtractFile('", archiveName, "', '",
|
||||
cmRemoveQuotes(cmSystemTools::ConvertToWindowsOutputPath(
|
||||
relativePath)),
|
||||
"')");
|
||||
} else {
|
||||
params["Source"] = QuotePath(i);
|
||||
params["Flags"] = "ignoreversion";
|
||||
}
|
||||
|
||||
fileInstructions.push_back(ISKeyValueLine(params));
|
||||
|
||||
// Icon
|
||||
const std::string& name =
|
||||
cmSystemTools::GetFilenameWithoutLastExtension(i);
|
||||
const std::string& extension =
|
||||
cmSystemTools::GetFilenameLastExtension(i);
|
||||
if ((extension == ".exe" || extension == ".com") && // only .exe, .com
|
||||
icons.count(name)) {
|
||||
cmCPackInnoSetupKeyValuePairs iconParams;
|
||||
|
||||
iconParams["Name"] = QuotePath(cmStrCat(iconsPrefix, icons[name]));
|
||||
iconParams["Filename"] =
|
||||
QuotePath(cmStrCat(destDir, '\\', name, extension));
|
||||
|
||||
if (!componentParam.empty()) {
|
||||
iconParams["Components"] = componentParam;
|
||||
}
|
||||
|
||||
iconInstructions.push_back(ISKeyValueLine(iconParams));
|
||||
|
||||
// Desktop icon
|
||||
if (std::find(desktopIcons.begin(), desktopIcons.end(), name) !=
|
||||
desktopIcons.end()) {
|
||||
iconParams["Name"] =
|
||||
QuotePath(cmStrCat("{autodesktop}\\", icons[name]));
|
||||
iconParams["Tasks"] = "desktopicon";
|
||||
|
||||
if (!componentParam.empty() &&
|
||||
std::find(desktopIconComponents.begin(),
|
||||
desktopIconComponents.end(),
|
||||
componentParam) == desktopIconComponents.end()) {
|
||||
desktopIconComponents.push_back(componentParam);
|
||||
}
|
||||
iconInstructions.push_back(ISKeyValueLine(iconParams));
|
||||
}
|
||||
|
||||
// [Run] section
|
||||
if (std::find(runExecutables.begin(), runExecutables.end(), name) !=
|
||||
runExecutables.end()) {
|
||||
cmCPackInnoSetupKeyValuePairs runParams;
|
||||
|
||||
runParams["Filename"] = iconParams["Filename"];
|
||||
runParams["Description"] = cmStrCat(
|
||||
"\"{cm:LaunchProgram,", PrepareForConstant(icons[name]), "}\"");
|
||||
runParams["Flags"] = "nowait postinstall skipifsilent";
|
||||
|
||||
if (!componentParam.empty()) {
|
||||
runParams["Components"] = componentParam;
|
||||
}
|
||||
|
||||
runInstructions.push_back(ISKeyValueLine(runParams));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Additional icons
|
||||
static cmsys::RegularExpression urlRegex(
|
||||
"^(mailto:|(ftps?|https?|news)://).*$");
|
||||
|
||||
if (IsSet("CPACK_INNOSETUP_MENU_LINKS")) {
|
||||
const cmList menuIcons(GetOption("CPACK_INNOSETUP_MENU_LINKS"));
|
||||
if (menuIcons.size() % 2 != 0) {
|
||||
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
||||
"CPACK_INNOSETUP_MENU_LINKS should "
|
||||
"contain pairs of <shortcut target> and <shortcut label>"
|
||||
<< std::endl);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto it = menuIcons.begin(); it != menuIcons.end(); ++it) {
|
||||
const std::string& target = *it;
|
||||
const std::string& label = *(++it);
|
||||
cmCPackInnoSetupKeyValuePairs params;
|
||||
|
||||
params["Name"] = QuotePath(cmStrCat(iconsPrefix, label));
|
||||
if (urlRegex.find(target)) {
|
||||
params["Filename"] = Quote(target);
|
||||
} else {
|
||||
std::string dir = "{app}";
|
||||
std::string componentName;
|
||||
for (const auto& i : Components) {
|
||||
if (cmSystemTools::FileExists(cmSystemTools::CollapseFullPath(
|
||||
cmStrCat(i.second.Name, '\\', target), toplevel))) {
|
||||
dir = CustomComponentInstallDirectory(&i.second);
|
||||
componentName =
|
||||
CreateRecursiveComponentPath(i.second.Group, i.second.Name);
|
||||
|
||||
if (i.second.IsHidden && i.second.IsDisabledByDefault) {
|
||||
goto continueOuterLoop;
|
||||
} else if (i.second.IsHidden) {
|
||||
componentName.clear();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
params["Filename"] = QuotePath(cmStrCat(dir, '\\', target));
|
||||
|
||||
if (!componentName.empty()) {
|
||||
params["Components"] = componentName;
|
||||
}
|
||||
}
|
||||
|
||||
iconInstructions.push_back(ISKeyValueLine(params));
|
||||
continueOuterLoop:;
|
||||
}
|
||||
}
|
||||
|
||||
SetOptionIfNotSet("CPACK_INNOSETUP_CREATE_UNINSTALL_LINK", "OFF");
|
||||
if (GetOption("CPACK_INNOSETUP_CREATE_UNINSTALL_LINK").IsOn()) {
|
||||
cmCPackInnoSetupKeyValuePairs params;
|
||||
|
||||
params["Name"] = QuotePath(
|
||||
cmStrCat(iconsPrefix, "{cm:UninstallProgram,",
|
||||
PrepareForConstant(GetOption("CPACK_PACKAGE_NAME")), '}'));
|
||||
params["Filename"] = "\"{uninstallexe}\"";
|
||||
|
||||
iconInstructions.push_back(ISKeyValueLine(params));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmCPackInnoSetupGenerator::ProcessComponents()
|
||||
{
|
||||
codeIncludes.push_back("{ The following lines are required by CPack because "
|
||||
"this script uses components }");
|
||||
|
||||
// Installation types
|
||||
bool noTypes = true;
|
||||
std::vector<cmCPackInstallationType*> types(InstallationTypes.size());
|
||||
for (auto& i : InstallationTypes) {
|
||||
noTypes = false;
|
||||
types[i.second.Index - 1] = &i.second;
|
||||
}
|
||||
|
||||
std::vector<std::string> allTypes; // For required components
|
||||
for (cmCPackInstallationType* i : types) {
|
||||
cmCPackInnoSetupKeyValuePairs params;
|
||||
|
||||
params["Name"] = Quote(i->Name);
|
||||
params["Description"] = Quote(i->DisplayName);
|
||||
|
||||
allTypes.push_back(i->Name);
|
||||
typeInstructions.push_back(ISKeyValueLine(params));
|
||||
}
|
||||
|
||||
if (!noTypes) {
|
||||
// Inno Setup requires the "custom" type
|
||||
cmCPackInnoSetupKeyValuePairs params;
|
||||
|
||||
params["Name"] = "\"custom\"";
|
||||
params["Description"] = "\"{code:CPackGetCustomInstallationMessage}\"";
|
||||
params["Flags"] = "iscustom";
|
||||
|
||||
allTypes.push_back("custom");
|
||||
typeInstructions.push_back(ISKeyValueLine(params));
|
||||
}
|
||||
|
||||
// Components
|
||||
std::vector<cmCPackComponent*> downloadedComponents;
|
||||
std::stack<cmCPackComponentGroup*> groups;
|
||||
for (auto& i : Components) {
|
||||
cmCPackInnoSetupKeyValuePairs params;
|
||||
cmCPackComponent* component = &i.second;
|
||||
|
||||
if (component->IsHidden) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CreateRecursiveComponentGroups(component->Group);
|
||||
|
||||
params["Name"] =
|
||||
Quote(CreateRecursiveComponentPath(component->Group, component->Name));
|
||||
params["Description"] = Quote(component->DisplayName);
|
||||
|
||||
if (component->IsRequired) {
|
||||
params["Types"] = cmJoin(allTypes, " ");
|
||||
params["Flags"] = "fixed";
|
||||
} else if (!component->InstallationTypes.empty()) {
|
||||
std::vector<std::string> installationTypes;
|
||||
|
||||
for (cmCPackInstallationType* j : component->InstallationTypes) {
|
||||
installationTypes.push_back(j->Name);
|
||||
}
|
||||
|
||||
params["Types"] = cmJoin(installationTypes, " ");
|
||||
}
|
||||
|
||||
componentInstructions.push_back(ISKeyValueLine(params));
|
||||
|
||||
if (component->IsDownloaded) {
|
||||
downloadedComponents.push_back(component);
|
||||
|
||||
if (component->ArchiveFile.empty()) {
|
||||
// Compute the name of the archive.
|
||||
if (!RequireOption("CPACK_TEMPORARY_DIRECTORY")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string packagesDir =
|
||||
cmStrCat(GetOption("CPACK_TEMPORARY_DIRECTORY"), ".dummy");
|
||||
component->ArchiveFile =
|
||||
cmStrCat(cmSystemTools::GetFilenameWithoutLastExtension(packagesDir),
|
||||
'-', component->Name, ".zip");
|
||||
} else if (!cmHasSuffix(component->ArchiveFile, ".zip")) {
|
||||
component->ArchiveFile = cmStrCat(component->ArchiveFile, ".zip");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Downloaded components
|
||||
if (!downloadedComponents.empty()) {
|
||||
// Create the directory for the upload area
|
||||
cmValue userUploadDirectory = GetOption("CPACK_UPLOAD_DIRECTORY");
|
||||
std::string uploadDirectory;
|
||||
if (cmNonempty(userUploadDirectory)) {
|
||||
uploadDirectory = *userUploadDirectory;
|
||||
} else {
|
||||
if (!RequireOption("CPACK_PACKAGE_DIRECTORY")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uploadDirectory =
|
||||
cmStrCat(GetOption("CPACK_PACKAGE_DIRECTORY"), "/CPackUploads");
|
||||
}
|
||||
|
||||
if (!cmSystemTools::FileExists(uploadDirectory)) {
|
||||
if (!cmSystemTools::MakeDirectory(uploadDirectory)) {
|
||||
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
||||
"Unable to create Inno Setup upload directory "
|
||||
<< uploadDirectory << std::endl);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!RequireOption("CPACK_DOWNLOAD_SITE")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SetOptionIfNotSet("CPACK_INNOSETUP_VERIFY_DOWNLOADS", "ON");
|
||||
const bool verifyDownloads =
|
||||
GetOption("CPACK_INNOSETUP_VERIFY_DOWNLOADS").IsOn();
|
||||
|
||||
const std::string& urlPrefix =
|
||||
cmHasSuffix(GetOption("CPACK_DOWNLOAD_SITE").GetCStr(), '/')
|
||||
? GetOption("CPACK_DOWNLOAD_SITE")
|
||||
: cmStrCat(GetOption("CPACK_DOWNLOAD_SITE"), '/');
|
||||
|
||||
std::vector<std::string> archiveUrls;
|
||||
std::vector<std::string> archiveFiles;
|
||||
std::vector<std::string> archiveHashes;
|
||||
std::vector<std::string> archiveComponents;
|
||||
for (cmCPackComponent* i : downloadedComponents) {
|
||||
std::string hash;
|
||||
if (!BuildDownloadedComponentArchive(
|
||||
i, uploadDirectory, (verifyDownloads ? &hash : nullptr))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
archiveUrls.push_back(Quote(cmStrCat(urlPrefix, i->ArchiveFile)));
|
||||
archiveFiles.push_back(
|
||||
Quote(cmSystemTools::GetFilenameWithoutLastExtension(i->ArchiveFile)));
|
||||
archiveHashes.push_back(Quote(hash));
|
||||
archiveComponents.push_back(
|
||||
Quote(CreateRecursiveComponentPath(i->Group, i->Name)));
|
||||
}
|
||||
|
||||
SetOption("CPACK_INNOSETUP_DOWNLOAD_COUNT_INTERNAL",
|
||||
std::to_string(archiveFiles.size()));
|
||||
SetOption("CPACK_INNOSETUP_DOWNLOAD_URLS_INTERNAL",
|
||||
cmJoin(archiveUrls, ", "));
|
||||
SetOption("CPACK_INNOSETUP_DOWNLOAD_ARCHIVES_INTERNAL",
|
||||
cmJoin(archiveFiles, ", "));
|
||||
SetOption("CPACK_INNOSETUP_DOWNLOAD_HASHES_INTERNAL",
|
||||
cmJoin(archiveHashes, ", "));
|
||||
SetOption("CPACK_INNOSETUP_DOWNLOAD_COMPONENTS_INTERNAL",
|
||||
cmJoin(archiveComponents, ", "));
|
||||
|
||||
static const std::string& downloadLines =
|
||||
"#define protected CPackDownloadCount "
|
||||
"@CPACK_INNOSETUP_DOWNLOAD_COUNT_INTERNAL@\n"
|
||||
"#dim protected CPackDownloadUrls[CPackDownloadCount] "
|
||||
"{@CPACK_INNOSETUP_DOWNLOAD_URLS_INTERNAL@}\n"
|
||||
"#dim protected CPackDownloadArchives[CPackDownloadCount] "
|
||||
"{@CPACK_INNOSETUP_DOWNLOAD_ARCHIVES_INTERNAL@}\n"
|
||||
"#dim protected CPackDownloadHashes[CPackDownloadCount] "
|
||||
"{@CPACK_INNOSETUP_DOWNLOAD_HASHES_INTERNAL@}\n"
|
||||
"#dim protected CPackDownloadComponents[CPackDownloadCount] "
|
||||
"{@CPACK_INNOSETUP_DOWNLOAD_COMPONENTS_INTERNAL@}";
|
||||
|
||||
std::string output;
|
||||
if (!ConfigureString(downloadLines, output)) {
|
||||
return false;
|
||||
}
|
||||
codeIncludes.push_back(output);
|
||||
}
|
||||
|
||||
// Add the required script
|
||||
const std::string& componentsScriptTemplate =
|
||||
FindTemplate("ISComponents.pas");
|
||||
if (componentsScriptTemplate.empty()) {
|
||||
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
||||
"Could not find additional Inno Setup script file."
|
||||
<< std::endl);
|
||||
return false;
|
||||
}
|
||||
|
||||
codeIncludes.push_back("#include " + QuotePath(componentsScriptTemplate) +
|
||||
"\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmCPackInnoSetupGenerator::ConfigureISScript()
|
||||
{
|
||||
const std::string& isScriptTemplate = FindTemplate("ISScript.template.in");
|
||||
const std::string& isScriptFile =
|
||||
cmStrCat(GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/ISScript.iss");
|
||||
|
||||
if (isScriptTemplate.empty()) {
|
||||
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
||||
"Could not find Inno Setup installer template file."
|
||||
<< std::endl);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create internal variables
|
||||
std::vector<std::string> setupSection;
|
||||
for (const auto& i : setupDirectives) {
|
||||
setupSection.push_back(cmStrCat(i.first, '=', TranslateBool(i.second)));
|
||||
}
|
||||
|
||||
// Also create comments if the sections are empty
|
||||
const std::string& defaultMessage =
|
||||
"; CPack didn't find any entries for this section";
|
||||
|
||||
if (IsSet("CPACK_CREATE_DESKTOP_LINKS") &&
|
||||
!GetOption("CPACK_CREATE_DESKTOP_LINKS").Get()->empty()) {
|
||||
cmCPackInnoSetupKeyValuePairs tasks;
|
||||
tasks["Name"] = "\"desktopicon\"";
|
||||
tasks["Description"] = "\"{cm:CreateDesktopIcon}\"";
|
||||
tasks["GroupDescription"] = "\"{cm:AdditionalIcons}\"";
|
||||
tasks["Flags"] = "unchecked";
|
||||
|
||||
if (!desktopIconComponents.empty()) {
|
||||
tasks["Components"] = cmJoin(desktopIconComponents, " ");
|
||||
}
|
||||
|
||||
SetOption("CPACK_INNOSETUP_TASKS_INTERNAL", ISKeyValueLine(tasks));
|
||||
} else {
|
||||
SetOption("CPACK_INNOSETUP_TASKS_INTERNAL", defaultMessage);
|
||||
}
|
||||
|
||||
SetOption("CPACK_INNOSETUP_INCLUDES_INTERNAL",
|
||||
includeDirectives.empty() ? "; No extra script files specified"
|
||||
: cmJoin(includeDirectives, "\n"));
|
||||
SetOption("CPACK_INNOSETUP_SETUP_INTERNAL",
|
||||
setupSection.empty() ? defaultMessage
|
||||
: cmJoin(setupSection, "\n"));
|
||||
SetOption("CPACK_INNOSETUP_LANGUAGES_INTERNAL",
|
||||
languageInstructions.empty() ? defaultMessage
|
||||
: cmJoin(languageInstructions, "\n"));
|
||||
SetOption("CPACK_INNOSETUP_DIRS_INTERNAL",
|
||||
dirInstructions.empty() ? defaultMessage
|
||||
: cmJoin(dirInstructions, "\n"));
|
||||
SetOption("CPACK_INNOSETUP_FILES_INTERNAL",
|
||||
fileInstructions.empty() ? defaultMessage
|
||||
: cmJoin(fileInstructions, "\n"));
|
||||
SetOption("CPACK_INNOSETUP_TYPES_INTERNAL",
|
||||
typeInstructions.empty() ? defaultMessage
|
||||
: cmJoin(typeInstructions, "\n"));
|
||||
SetOption("CPACK_INNOSETUP_COMPONENTS_INTERNAL",
|
||||
componentInstructions.empty()
|
||||
? defaultMessage
|
||||
: cmJoin(componentInstructions, "\n"));
|
||||
SetOption("CPACK_INNOSETUP_ICONS_INTERNAL",
|
||||
iconInstructions.empty() ? defaultMessage
|
||||
: cmJoin(iconInstructions, "\n"));
|
||||
SetOption("CPACK_INNOSETUP_RUN_INTERNAL",
|
||||
runInstructions.empty() ? defaultMessage
|
||||
: cmJoin(runInstructions, "\n"));
|
||||
SetOption("CPACK_INNOSETUP_CODE_INTERNAL",
|
||||
codeIncludes.empty() ? "{ No extra code files specified }"
|
||||
: cmJoin(codeIncludes, "\n"));
|
||||
|
||||
cmCPackLogger(cmCPackLog::LOG_VERBOSE,
|
||||
"Configure file: " << isScriptTemplate << " to "
|
||||
<< isScriptFile << std::endl);
|
||||
|
||||
return ConfigureFile(isScriptTemplate, isScriptFile);
|
||||
}
|
||||
|
||||
bool cmCPackInnoSetupGenerator::Compile()
|
||||
{
|
||||
const std::string& isScriptFile =
|
||||
cmStrCat(GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/ISScript.iss");
|
||||
const std::string& isccLogFile =
|
||||
cmStrCat(GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/ISCCOutput.log");
|
||||
|
||||
std::vector<std::string> isccArgs;
|
||||
|
||||
// Custom defines
|
||||
for (const std::string& i : GetOptions()) {
|
||||
if (cmHasPrefix(i, "CPACK_INNOSETUP_DEFINE_")) {
|
||||
const std::string& name = i.substr(cmStrLen("CPACK_INNOSETUP_DEFINE_"));
|
||||
isccArgs.push_back(
|
||||
cmStrCat("\"/D", name, '=', TranslateBool(GetOption(i)), '"'));
|
||||
}
|
||||
}
|
||||
|
||||
if (IsSet("CPACK_INNOSETUP_EXECUTABLE_ARGUMENTS")) {
|
||||
const cmList args(GetOption("CPACK_INNOSETUP_EXECUTABLE_ARGUMENTS"));
|
||||
|
||||
isccArgs.insert(isccArgs.end(), args.begin(), args.end());
|
||||
}
|
||||
|
||||
const std::string& isccCmd =
|
||||
cmStrCat(QuotePath(GetOption("CPACK_INSTALLER_PROGRAM")), ' ',
|
||||
cmJoin(isccArgs, " "), ' ', QuotePath(isScriptFile));
|
||||
|
||||
cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Execute: " << isccCmd << std::endl);
|
||||
|
||||
std::string output;
|
||||
int retVal = 1;
|
||||
const bool res = cmSystemTools::RunSingleCommand(
|
||||
isccCmd, &output, &output, &retVal, nullptr, this->GeneratorVerbose,
|
||||
cmDuration::zero());
|
||||
|
||||
if (!res || retVal) {
|
||||
cmGeneratedFileStream ofs(isccLogFile);
|
||||
ofs << "# Run command: " << isccCmd << std::endl
|
||||
<< "# Output:" << std::endl
|
||||
<< output << std::endl;
|
||||
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
||||
"Problem running ISCC. Please check "
|
||||
<< isccLogFile << " for errors." << std::endl);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cmCPackInnoSetupGenerator::BuildDownloadedComponentArchive(
|
||||
cmCPackComponent* component, const std::string& uploadDirectory,
|
||||
std::string* hash)
|
||||
{
|
||||
// Remove the old archive, if one exists
|
||||
const std::string& archiveFile =
|
||||
uploadDirectory + '/' + component->ArchiveFile;
|
||||
cmCPackLogger(cmCPackLog::LOG_OUTPUT,
|
||||
"- Building downloaded component archive: " << archiveFile
|
||||
<< std::endl);
|
||||
if (cmSystemTools::FileExists(archiveFile, true)) {
|
||||
if (!cmSystemTools::RemoveFile(archiveFile)) {
|
||||
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
||||
"Unable to remove archive file " << archiveFile
|
||||
<< std::endl);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Find a ZIP program
|
||||
if (!IsSet("ZIP_EXECUTABLE")) {
|
||||
ReadListFile("Internal/CPack/CPackZIP.cmake");
|
||||
|
||||
if (!IsSet("ZIP_EXECUTABLE")) {
|
||||
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
||||
"Unable to find ZIP program" << std::endl);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!RequireOption("CPACK_TOPLEVEL_DIRECTORY") ||
|
||||
!RequireOption("CPACK_TEMPORARY_DIRECTORY") ||
|
||||
!RequireOption("CPACK_ZIP_NEED_QUOTES") ||
|
||||
!RequireOption("CPACK_ZIP_COMMAND")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The directory where this component's files reside
|
||||
const std::string& dirName =
|
||||
cmStrCat(GetOption("CPACK_TEMPORARY_DIRECTORY"), '/', component->Name);
|
||||
|
||||
// Build the list of files to go into this archive
|
||||
const std::string& zipListFileName =
|
||||
cmStrCat(GetOption("CPACK_TEMPORARY_DIRECTORY"), "/winZip.filelist");
|
||||
const bool needQuotesInFile = cmIsOn(GetOption("CPACK_ZIP_NEED_QUOTES"));
|
||||
{ // the scope is needed for cmGeneratedFileStream
|
||||
cmGeneratedFileStream out(zipListFileName);
|
||||
for (const std::string& i : component->Files) {
|
||||
out << (needQuotesInFile ? Quote(i) : i) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Build the archive in the upload area
|
||||
std::string cmd = GetOption("CPACK_ZIP_COMMAND");
|
||||
cmsys::SystemTools::ReplaceString(cmd, "<ARCHIVE>", archiveFile.c_str());
|
||||
cmsys::SystemTools::ReplaceString(cmd, "<FILELIST>",
|
||||
zipListFileName.c_str());
|
||||
std::string output;
|
||||
int retVal = -1;
|
||||
const bool res = cmSystemTools::RunSingleCommand(
|
||||
cmd, &output, &output, &retVal, dirName.c_str(), this->GeneratorVerbose,
|
||||
cmDuration::zero());
|
||||
if (!res || retVal) {
|
||||
std::string tmpFile =
|
||||
cmStrCat(GetOption("CPACK_TOPLEVEL_DIRECTORY"), "/CompressZip.log");
|
||||
cmGeneratedFileStream ofs(tmpFile);
|
||||
ofs << "# Run command: " << cmd << std::endl
|
||||
<< "# Output:" << std::endl
|
||||
<< output << std::endl;
|
||||
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
||||
"Problem running zip command: " << cmd << std::endl
|
||||
<< "Please check " << tmpFile
|
||||
<< " for errors"
|
||||
<< std::endl);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to get the SHA256 hash of the archive file
|
||||
if (hash == nullptr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
const std::string& hashCmd =
|
||||
cmStrCat("certutil -hashfile ", QuotePath(archiveFile), " SHA256");
|
||||
|
||||
std::string hashOutput;
|
||||
int hashRetVal = -1;
|
||||
const bool hashRes = cmSystemTools::RunSingleCommand(
|
||||
hashCmd, &hashOutput, &hashOutput, &hashRetVal, nullptr,
|
||||
this->GeneratorVerbose, cmDuration::zero());
|
||||
if (!hashRes || hashRetVal) {
|
||||
cmCPackLogger(cmCPackLog::LOG_WARNING,
|
||||
"Problem running certutil command: " << hashCmd
|
||||
<< std::endl);
|
||||
}
|
||||
*hash = cmTrimWhitespace(cmTokenize(hashOutput, "\n").at(1));
|
||||
|
||||
if (hash->length() != 64) {
|
||||
cmCPackLogger(cmCPackLog::LOG_WARNING,
|
||||
"Problem parsing certutil output of command: " << hashCmd
|
||||
<< std::endl);
|
||||
hash->clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
cmValue cmCPackInnoSetupGenerator::RequireOption(const std::string& key)
|
||||
{
|
||||
cmValue value = GetOption(key);
|
||||
|
||||
if (!value) {
|
||||
cmCPackLogger(cmCPackLog::LOG_ERROR,
|
||||
"Required variable " << key << " not set" << std::endl);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
std::string cmCPackInnoSetupGenerator::CustomComponentInstallDirectory(
|
||||
const cmCPackComponent* component)
|
||||
{
|
||||
cmValue outputDir = GetOption(
|
||||
cmStrCat("CPACK_INNOSETUP_", component->Name, "_INSTALL_DIRECTORY"));
|
||||
if (outputDir) {
|
||||
std::string destDir = cmSystemTools::ConvertToWindowsOutputPath(outputDir);
|
||||
cmStripSuffixIfExists(destDir, '\\');
|
||||
|
||||
/*
|
||||
* Add a dir instruction for the custom directory
|
||||
* (only once and not for Inno Setup constants ending with '}')
|
||||
*/
|
||||
static std::vector<std::string> customDirectories;
|
||||
if (!cmHasSuffix(destDir, '}') &&
|
||||
std::find(customDirectories.begin(), customDirectories.end(),
|
||||
component->Name) == customDirectories.end()) {
|
||||
cmCPackInnoSetupKeyValuePairs params;
|
||||
params["Name"] = QuotePath(destDir);
|
||||
params["Components"] =
|
||||
CreateRecursiveComponentPath(component->Group, component->Name);
|
||||
|
||||
dirInstructions.push_back(ISKeyValueLine(params));
|
||||
customDirectories.push_back(component->Name);
|
||||
}
|
||||
return destDir;
|
||||
}
|
||||
|
||||
return "{app}";
|
||||
}
|
||||
|
||||
std::string cmCPackInnoSetupGenerator::TranslateBool(const std::string& value)
|
||||
{
|
||||
if (value.empty()) {
|
||||
return value;
|
||||
}
|
||||
|
||||
SetOptionIfNotSet("CPACK_INNOSETUP_USE_CMAKE_BOOL_FORMAT", "ON");
|
||||
if (GetOption("CPACK_INNOSETUP_USE_CMAKE_BOOL_FORMAT").IsOn()) {
|
||||
if (cmIsOn(value)) {
|
||||
return "yes";
|
||||
}
|
||||
if (cmIsOff(value)) {
|
||||
return "no";
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
std::string cmCPackInnoSetupGenerator::ISKeyValueLine(
|
||||
const cmCPackInnoSetupKeyValuePairs& params)
|
||||
{
|
||||
/*
|
||||
* To simplify readability of the generated code, the keys are sorted.
|
||||
* Unknown keys are ignored to avoid errors during compilation.
|
||||
*/
|
||||
static const char* const availableKeys[] = {
|
||||
"Source", "DestDir", "Name", "Filename",
|
||||
"Description", "GroupDescription", "MessagesFile", "Types",
|
||||
"ExternalSize", "BeforeInstall", "Flags", "Components",
|
||||
"Tasks"
|
||||
};
|
||||
|
||||
std::vector<std::string> keys;
|
||||
for (const char* i : availableKeys) {
|
||||
if (params.count(i)) {
|
||||
keys.push_back(cmStrCat(i, ": ", params.at(i)));
|
||||
}
|
||||
}
|
||||
|
||||
return cmJoin(keys, "; ");
|
||||
}
|
||||
|
||||
std::string cmCPackInnoSetupGenerator::CreateRecursiveComponentPath(
|
||||
cmCPackComponentGroup* group, const std::string& path)
|
||||
{
|
||||
if (group == nullptr) {
|
||||
return path;
|
||||
}
|
||||
|
||||
const std::string& newPath =
|
||||
path.empty() ? group->Name : cmStrCat(group->Name, '\\', path);
|
||||
return CreateRecursiveComponentPath(group->ParentGroup, newPath);
|
||||
}
|
||||
|
||||
void cmCPackInnoSetupGenerator::CreateRecursiveComponentGroups(
|
||||
cmCPackComponentGroup* group)
|
||||
{
|
||||
if (group == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
CreateRecursiveComponentGroups(group->ParentGroup);
|
||||
|
||||
static std::vector<cmCPackComponentGroup*> processedGroups;
|
||||
if (std::find(processedGroups.begin(), processedGroups.end(), group) ==
|
||||
processedGroups.end()) {
|
||||
processedGroups.push_back(group);
|
||||
|
||||
cmCPackInnoSetupKeyValuePairs params;
|
||||
|
||||
params["Name"] = Quote(CreateRecursiveComponentPath(group));
|
||||
params["Description"] = Quote(group->DisplayName);
|
||||
|
||||
componentInstructions.push_back(ISKeyValueLine(params));
|
||||
}
|
||||
}
|
||||
|
||||
std::string cmCPackInnoSetupGenerator::Quote(const std::string& string)
|
||||
{
|
||||
if (cmHasPrefix(string, '"') && cmHasSuffix(string, '"')) {
|
||||
return Quote(string.substr(1, string.length() - 2));
|
||||
}
|
||||
|
||||
// Double quote syntax
|
||||
std::string nString = string;
|
||||
cmSystemTools::ReplaceString(nString, "\"", "\"\"");
|
||||
return cmStrCat('"', nString, '"');
|
||||
}
|
||||
|
||||
std::string cmCPackInnoSetupGenerator::QuotePath(const std::string& path)
|
||||
{
|
||||
return Quote(cmSystemTools::ConvertToWindowsOutputPath(path));
|
||||
}
|
||||
|
||||
std::string cmCPackInnoSetupGenerator::PrepareForConstant(
|
||||
const std::string& string)
|
||||
{
|
||||
std::string nString = string;
|
||||
|
||||
cmSystemTools::ReplaceString(nString, "%", "%25"); // First replacement!
|
||||
cmSystemTools::ReplaceString(nString, "\"", "%22");
|
||||
cmSystemTools::ReplaceString(nString, ",", "%2c");
|
||||
cmSystemTools::ReplaceString(nString, "|", "%7c");
|
||||
cmSystemTools::ReplaceString(nString, "}", "%7d");
|
||||
|
||||
return nString;
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file Copyright.txt or https://cmake.org/licensing for details. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cmCPackGenerator.h"
|
||||
#include "cmValue.h"
|
||||
|
||||
using cmCPackInnoSetupKeyValuePairs = std::map<std::string, std::string>;
|
||||
|
||||
class cmCPackComponentGroup;
|
||||
class cmCPackComponent;
|
||||
|
||||
/** \class cmCPackInnoSetupGenerator
|
||||
* \brief A generator for Inno Setup
|
||||
*
|
||||
* https://jrsoftware.org/isinfo.php
|
||||
*/
|
||||
class cmCPackInnoSetupGenerator : public cmCPackGenerator
|
||||
{
|
||||
public:
|
||||
cmCPackTypeMacro(cmCPackInnoSetupGenerator, cmCPackGenerator);
|
||||
|
||||
/**
|
||||
* Construct generator
|
||||
*/
|
||||
cmCPackInnoSetupGenerator();
|
||||
~cmCPackInnoSetupGenerator() override;
|
||||
|
||||
static bool CanGenerate();
|
||||
|
||||
protected:
|
||||
int InitializeInternal() override;
|
||||
int PackageFiles() override;
|
||||
|
||||
inline const char* GetOutputExtension() override { return ".exe"; }
|
||||
|
||||
inline cmCPackGenerator::CPackSetDestdirSupport SupportsSetDestdir()
|
||||
const override
|
||||
{
|
||||
return cmCPackGenerator::SETDESTDIR_UNSUPPORTED;
|
||||
}
|
||||
|
||||
inline bool SupportsAbsoluteDestination() const override { return false; }
|
||||
inline bool SupportsComponentInstallation() const override { return true; }
|
||||
|
||||
private:
|
||||
bool ProcessSetupSection();
|
||||
bool ProcessFiles();
|
||||
bool ProcessComponents();
|
||||
|
||||
bool ConfigureISScript();
|
||||
bool Compile();
|
||||
|
||||
bool BuildDownloadedComponentArchive(cmCPackComponent* component,
|
||||
const std::string& uploadDirectory,
|
||||
std::string* hash);
|
||||
|
||||
/**
|
||||
* Returns the option's value or an empty string if the option isn't set.
|
||||
*/
|
||||
cmValue RequireOption(const std::string& key);
|
||||
|
||||
std::string CustomComponentInstallDirectory(
|
||||
const cmCPackComponent* component);
|
||||
|
||||
/**
|
||||
* Translates boolean expressions into "yes" or "no", as required in
|
||||
* Inno Setup (only if "CPACK_INNOSETUP_USE_CMAKE_BOOL_FORMAT" is on).
|
||||
*/
|
||||
std::string TranslateBool(const std::string& value);
|
||||
|
||||
/**
|
||||
* Creates a typical line of key and value pairs using the given map.
|
||||
*
|
||||
* (e.g.: Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}";
|
||||
* GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked)
|
||||
*/
|
||||
std::string ISKeyValueLine(const cmCPackInnoSetupKeyValuePairs& params);
|
||||
|
||||
std::string CreateRecursiveComponentPath(cmCPackComponentGroup* group,
|
||||
const std::string& path = "");
|
||||
|
||||
void CreateRecursiveComponentGroups(cmCPackComponentGroup* group);
|
||||
|
||||
/**
|
||||
* These functions add quotes if the given value hasn't already quotes.
|
||||
* Paths are converted into the format used by Windows before.
|
||||
*/
|
||||
std::string Quote(const std::string& string);
|
||||
std::string QuotePath(const std::string& path);
|
||||
|
||||
/**
|
||||
* This function replaces the following 5 characters with their %-encoding:
|
||||
* '|' '}' ',' '%' '"'
|
||||
* Required for Inno Setup constants like {cm:...}
|
||||
*/
|
||||
std::string PrepareForConstant(const std::string& string);
|
||||
|
||||
std::vector<std::string> includeDirectives;
|
||||
cmCPackInnoSetupKeyValuePairs setupDirectives;
|
||||
bool toplevelProgramFolder;
|
||||
std::vector<std::string> languageInstructions;
|
||||
std::vector<std::string> fileInstructions;
|
||||
std::vector<std::string> dirInstructions;
|
||||
std::vector<std::string> typeInstructions;
|
||||
std::vector<std::string> componentInstructions;
|
||||
std::vector<std::string> iconInstructions;
|
||||
std::vector<std::string> desktopIconComponents;
|
||||
std::vector<std::string> runInstructions;
|
||||
std::vector<std::string> codeIncludes;
|
||||
};
|
||||
@@ -986,6 +986,30 @@ if(BUILD_TESTING)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# On Windows run the CPackInnoSetupGenerator test
|
||||
if(WIN32 AND CMake_TEST_CPACK_INNOSETUP)
|
||||
add_test(CPackInnoSetupGenerator ${CMAKE_CTEST_COMMAND}
|
||||
-C \${CTEST_CONFIGURATION_TYPE}
|
||||
--build-and-test
|
||||
"${CMake_SOURCE_DIR}/Tests/CPackInnoSetupGenerator"
|
||||
"${CMake_BINARY_DIR}/Tests/CPackInnoSetupGenerator"
|
||||
${build_generator_args}
|
||||
--build-project CPackInnoSetupGenerator
|
||||
--build-options
|
||||
--test-command ${CMAKE_CMAKE_COMMAND}
|
||||
"-DCPackInnoSetupGenerator_BINARY_DIR:PATH=${CMake_BINARY_DIR}/Tests/CPackInnoSetupGenerator"
|
||||
"-Dconfig=\${CTEST_CONFIGURATION_TYPE}"
|
||||
-P "${CMake_SOURCE_DIR}/Tests/CPackInnoSetupGenerator/RunCPackVerifyResult.cmake")
|
||||
|
||||
set_property(TEST CPackInnoSetupGenerator PROPERTY
|
||||
ATTACHED_FILES_ON_FAIL
|
||||
"${CMake_BINARY_DIR}/Tests/CPackInnoSetupGenerator/_CPack_Packages/win32/INNOSETUP/ISCCOutput.log")
|
||||
|
||||
set_property(TEST CPackInnoSetupGenerator PROPERTY
|
||||
ATTACHED_FILES
|
||||
"${CMake_BINARY_DIR}/Tests/CPackInnoSetupGenerator/_CPack_Packages/win32/INNOSETUP/ISScript.iss")
|
||||
endif()
|
||||
|
||||
# On Windows run the CPackNSISGenerator test
|
||||
# if the nsis is available
|
||||
if(WIN32 AND NSIS_MAKENSIS_EXECUTABLE)
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
project(CPackInnoSetupGenerator VERSION 42.0 HOMEPAGE_URL "https://www.example.com")
|
||||
|
||||
add_executable(hello main.c)
|
||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/empty)
|
||||
|
||||
install(TARGETS hello DESTINATION / COMPONENT application)
|
||||
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/empty DESTINATION / COMPONENT extras)
|
||||
install(FILES my_bitmap.bmp DESTINATION awesome COMPONENT extras)
|
||||
install(FILES my_file.txt DESTINATION / COMPONENT hidden_component)
|
||||
install(FILES my_file.txt DESTINATION / COMPONENT hidden_component2)
|
||||
|
||||
set(CPACK_GENERATOR "INNOSETUP")
|
||||
|
||||
set(CPACK_PACKAGE_NAME "Hello, World!") # Test constant escape (like {cm:...}, see code documentation)
|
||||
set(CPACK_PACKAGE_VENDOR "Sheldon Cooper")
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY "hello_world")
|
||||
set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY "hello_world")
|
||||
set(CPACK_PACKAGE_FILE_NAME "hello_world_setup")
|
||||
set(CPACK_SYSTEM_NAME "win32")
|
||||
set(CPACK_PACKAGE_ICON "${CMAKE_CURRENT_SOURCE_DIR}/my_bitmap.bmp")
|
||||
set(CPACK_VERBATIM_VARIABLES ON)
|
||||
set(CPACK_PACKAGE_EXECUTABLES "hello" "Hello, World!")
|
||||
set(CPACK_CREATE_DESKTOP_LINKS hello)
|
||||
|
||||
set(CPACK_INNOSETUP_INSTALL_ROOT "{autopf}\\Sheldon Cooper")
|
||||
set(CPACK_INNOSETUP_PROGRAM_MENU_FOLDER ".")
|
||||
set(CPACK_INNOSETUP_IGNORE_LICENSE_PAGE ON)
|
||||
set(CPACK_INNOSETUP_IGNORE_README_PAGE OFF) # Test if only readme page is shown
|
||||
set(CPACK_INNOSETUP_SETUP_AppComments ON) # Test if CPACK_INNOSETUP_USE_CMAKE_BOOL_FORMAT works
|
||||
set(CPACK_INNOSETUP_CUSTOM_INSTALL_INSTRUCTIONS "extras/empty"
|
||||
"Name: \"{userdocs}\\empty\"\; Check: ReturnTrue\; Components: accessories\\extras")
|
||||
set(CPACK_INNOSETUP_MENU_LINKS "https://www.example.com" "Web"
|
||||
"my_file.txt" "Text")
|
||||
set(CPACK_INNOSETUP_RUN_EXECUTABLES hello)
|
||||
set(CPACK_INNOSETUP_CREATE_UNINSTALL_LINK ON)
|
||||
# Test if this macro is available in the code file below containing the check function
|
||||
set(CPACK_INNOSETUP_DEFINE_PascalMacro "end;")
|
||||
set(CPACK_INNOSETUP_CODE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/Code.pas")
|
||||
set(CPACK_INNOSETUP_EXECUTABLE "ISCC.exe")
|
||||
|
||||
include(CPackComponent)
|
||||
|
||||
cpack_add_install_type(basic DISPLAY_NAME "Basic installation")
|
||||
cpack_add_install_type(full DISPLAY_NAME "\"Large\" installation") # Test double quote syntax
|
||||
cpack_add_component_group(accessories DISPLAY_NAME "Accessories")
|
||||
|
||||
cpack_add_component(application DISPLAY_NAME "Application" INSTALL_TYPES basic full REQUIRED)
|
||||
cpack_add_component(extras DISPLAY_NAME "Additional components" INSTALL_TYPES full GROUP accessories)
|
||||
cpack_add_component(hidden_component HIDDEN)
|
||||
cpack_add_component(hidden_component2 HIDDEN DISABLED)
|
||||
set(CPACK_INNOSETUP_extras_INSTALL_DIRECTORY "{userdocs}")
|
||||
|
||||
include(CPack)
|
||||
@@ -0,0 +1,4 @@
|
||||
function ReturnTrue(): Boolean;
|
||||
begin
|
||||
Result := true;
|
||||
{#PascalMacro}
|
||||
@@ -0,0 +1,136 @@
|
||||
message(STATUS "=============================================================")
|
||||
message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)")
|
||||
message(STATUS "")
|
||||
|
||||
if(NOT CPackInnoSetupGenerator_BINARY_DIR)
|
||||
message(FATAL_ERROR "CPackInnoSetupGenerator_BINARY_DIR not set")
|
||||
endif()
|
||||
|
||||
message(STATUS "CMAKE_COMMAND: ${CMAKE_COMMAND}")
|
||||
message(STATUS "CMAKE_CPACK_COMMAND: ${CMAKE_CPACK_COMMAND}")
|
||||
message(STATUS "CPackInnoSetupGenerator_BINARY_DIR: ${CPackInnoSetupGenerator_BINARY_DIR}")
|
||||
|
||||
if(config)
|
||||
set(_C_config -C ${config})
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND "${CMAKE_CPACK_COMMAND}"
|
||||
${_C_config}
|
||||
RESULT_VARIABLE CPack_result
|
||||
OUTPUT_VARIABLE CPack_output
|
||||
ERROR_VARIABLE CPack_output
|
||||
WORKING_DIRECTORY "${CPackInnoSetupGenerator_BINARY_DIR}")
|
||||
|
||||
if(CPack_result)
|
||||
message(FATAL_ERROR "CPack execution went wrong!, Output: ${CPack_output}")
|
||||
else ()
|
||||
message(STATUS "Output: ${CPack_output}")
|
||||
endif()
|
||||
|
||||
file(GLOB project_file "${CPackInnoSetupGenerator_BINARY_DIR}/_CPack_Packages/win32/INNOSETUP/ISScript.iss")
|
||||
file(GLOB installer_file "${CPackInnoSetupGenerator_BINARY_DIR}/_CPack_Packages/win32/INNOSETUP/hello_world_setup.exe")
|
||||
|
||||
message(STATUS "Project file: '${project_file}'")
|
||||
message(STATUS "Installer file: '${installer_file}'")
|
||||
|
||||
if(NOT project_file)
|
||||
message(FATAL_ERROR "Project file does not exist")
|
||||
endif()
|
||||
|
||||
if(NOT installer_file)
|
||||
message(FATAL_ERROR "Installer file does not exist")
|
||||
endif()
|
||||
|
||||
# Test if the correct registry key is set
|
||||
file(STRINGS "${project_file}" results REGEX "^AppId=hello_world$")
|
||||
if(results STREQUAL "")
|
||||
message(FATAL_ERROR "CPACK_PACKAGE_INSTALL_REGISTRY_KEY doesn't match AppId")
|
||||
endif()
|
||||
|
||||
# Test if only readme page is shown
|
||||
file(STRINGS "${project_file}" results REGEX "^LicenseFile=")
|
||||
file(STRINGS "${project_file}" results2 REGEX "^InfoBeforeFile=")
|
||||
if(NOT results STREQUAL "" OR results2 STREQUAL "")
|
||||
message(FATAL_ERROR "Erroneous output with license and readme files")
|
||||
endif()
|
||||
|
||||
# Test if classic style is used by default
|
||||
file(STRINGS "${project_file}" results REGEX "compiler:SetupClassicIcon\\.ico")
|
||||
file(STRINGS "${project_file}" results2 REGEX "compiler:WizClassicImage\\.bmp")
|
||||
if(results STREQUAL "" OR results2 STREQUAL "")
|
||||
message(FATAL_ERROR "Images of classic style not used")
|
||||
endif()
|
||||
|
||||
# Test if the top-level start menu folder is used
|
||||
file(STRINGS "${project_file}" results REGEX "{autoprograms}")
|
||||
file(STRINGS "${project_file}" results2 REGEX "{group}")
|
||||
if(results STREQUAL "" OR NOT results2 STREQUAL "")
|
||||
message(FATAL_ERROR "Top-level start menu folder not used")
|
||||
endif()
|
||||
|
||||
# Test CPACK_INNOSETUP_USE_CMAKE_BOOL_FORMAT
|
||||
file(STRINGS "${project_file}" results REGEX "^AppComments=yes$")
|
||||
if(results STREQUAL "")
|
||||
message(FATAL_ERROR "CPACK_INNOSETUP_USE_CMAKE_BOOL_FORMAT doesn't convert booleans")
|
||||
endif()
|
||||
|
||||
# Test the custom installation rule
|
||||
file(STRINGS "${project_file}" results REGEX "^Name: \"{userdocs}\\\\empty\"; Check: ReturnTrue; Components: accessories\\\\extras$")
|
||||
if(results STREQUAL "")
|
||||
message(FATAL_ERROR "Custom installation rule not found or incomplete")
|
||||
endif()
|
||||
|
||||
# Test if an uninstall shortcut has been created
|
||||
file(STRINGS "${project_file}" results REGEX "{uninstallexe}")
|
||||
if(results STREQUAL "")
|
||||
message(FATAL_ERROR "No uninstall shortcut created")
|
||||
endif()
|
||||
|
||||
# Test CPACK_INNOSETUP_<compName>_INSTALL_DIRECTORY
|
||||
file(STRINGS "${project_file}" results REGEX "{app}.*Components: accessories\\\\extras")
|
||||
if(NOT results STREQUAL "")
|
||||
message(FATAL_ERROR "Component not in custom install directory")
|
||||
endif()
|
||||
|
||||
# Test if component names are nested correctly
|
||||
file(STRINGS "${project_file}" results REGEX "Components:.* extras")
|
||||
if(NOT results STREQUAL "")
|
||||
message(FATAL_ERROR "Component names must contain their parent groups according to the documentation")
|
||||
endif()
|
||||
|
||||
# Test if custom installation type exists
|
||||
file(STRINGS "${project_file}" results REGEX "Flags: .*iscustom")
|
||||
if(results STREQUAL "")
|
||||
message(FATAL_ERROR "Custom installation type doesn't exist")
|
||||
endif()
|
||||
|
||||
# Test if hidden components are processed but not displayed
|
||||
file(STRINGS "${project_file}" results REGEX "Source:.+hidden_component\\\\my_file\\.txt")
|
||||
file(STRINGS "${project_file}" results2 REGEX "Name: \"hidden_component\"")
|
||||
if(results STREQUAL "" OR NOT results2 STREQUAL "")
|
||||
message(FATAL_ERROR "Hidden component displayed or one of its files ignored")
|
||||
endif()
|
||||
|
||||
# Test if disabled and hidden components are ignored at all
|
||||
file(STRINGS "${project_file}" results REGEX "Source:.+hidden_component2\\\\my_file\\.txt")
|
||||
if(NOT results STREQUAL "")
|
||||
message(FATAL_ERROR "Disabled and hidden component not ignored")
|
||||
endif()
|
||||
|
||||
# Test if required components ignore their installation types
|
||||
file(STRINGS "${project_file}" results REGEX "Types: (basic|full|custom|basic full|full basic|basic custom|full custom); Flags: fixed")
|
||||
if(NOT results STREQUAL "")
|
||||
message(FATAL_ERROR "Required components don't ignore their installation types")
|
||||
endif()
|
||||
|
||||
# Test constant escape (should contain Hello%2c World!)
|
||||
file(STRINGS "${project_file}" results REGEX "Hello%2c World!")
|
||||
if(results STREQUAL "")
|
||||
message(FATAL_ERROR "The comma character isn't escaped to %2c")
|
||||
endif()
|
||||
|
||||
# Test double quote syntax
|
||||
file(STRINGS "${project_file}" results REGEX "\"\"Large\"\"")
|
||||
if(results STREQUAL "")
|
||||
message(FATAL_ERROR "The quote character isn't escaped correctly")
|
||||
endif()
|
||||
@@ -0,0 +1,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("Hello, World!\n");
|
||||
return 42;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 9.1 KiB |
@@ -0,0 +1 @@
|
||||
Hello, World!
|
||||
Reference in New Issue
Block a user