Skip to content

Commit 0410de8

Browse files
committed
Added Inno Setup packaging method
* Retrieved ModifyPath.iss from Mozart 1 repo and updated it * Added Inno Setup scripts with batch file to check Tcl version * Modified CMakeLists to compute Inno Setup configuration * Added make installer target on Windows to launch the process * Updated Windows README to include setup making notice
1 parent f443d13 commit 0410de8

File tree

10 files changed

+384
-1
lines changed

10 files changed

+384
-1
lines changed

CMakeLists.txt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,5 +111,38 @@ set(CPACK_RPM_PACKAGE_ARCHITECTURE "${MOZART_PROP_PLATFORM_ARCH}")
111111
set(CPACK_RPM_PACKAGE_REQUIRES "tcl >= 8.5, tk >= 8.5, emacs")
112112
set(CPACK_RPM_PACKAGE_GROUP "Development/Languages")
113113

114+
# Configuration of Inno Setup files
115+
116+
if(WIN32)
117+
find_program(ISS_COMPILER NAMES iscc ISCC
118+
HINTS "C:/Program Files (x86)/Inno Setup 5" "C:/Program Files/Inno Setup 5")
119+
120+
if(NOT ISS_COMPILER)
121+
message(WARNING "Inno Setup Compiler not found. You won't be able to build setup files.")
122+
else()
123+
message(STATUS "Using Inno Setup Compiler from: ${ISS_COMPILER}")
124+
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/distrib/windows"
125+
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/distrib")
126+
127+
# Compute Tcl/Tk install path
128+
get_filename_component(ISS_TCL_EXEC_PARENT "${ISS_TCL_EXEC}" DIRECTORY)
129+
get_filename_component(ISS_TCL_PATH "${ISS_TCL_EXEC_PARENT}" DIRECTORY)
130+
131+
# Compute emacs install path
132+
get_filename_component(ISS_EMACS_EXEC_PARENT "${ISS_EMACS_EXEC}" DIRECTORY)
133+
get_filename_component(ISS_EMACS_PATH "${ISS_EMACS_EXEC_PARENT}" DIRECTORY)
134+
135+
# Parse Inno Setup config file
136+
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/distrib/windows/MozartConfig.iss"
137+
"${CMAKE_CURRENT_BINARY_DIR}/distrib/windows/MozartConfig.iss")
138+
139+
# Add installer target
140+
add_custom_target(installer
141+
COMMAND ${CMAKE_MAKE_PROGRAM} install
142+
COMMAND ${ISS_COMPILER} "${CMAKE_CURRENT_BINARY_DIR}/distrib/windows/MozartSetup.iss"
143+
VERBATIM)
144+
endif()
145+
endif()
146+
114147
# Finally include CPack
115148
include(CPack)

README.Windows.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Download and install the following tools:
1111
* Python (required for building LLVM)
1212
* Git for Windows
1313
* CMake >= 2.8.6
14+
* [Inno Setup](http://www.jrsoftware.org/isdl.php) (with preprocessor, required for building setup files)
1415
* A recent 32-bit (i686) or 64-bit (x86_64) targeting [MinGW-64 distro](http://mingw-w64.sourceforge.net/download.php#mingw-builds) with gcc >= 4.7.1.
1516

1617
These tools won't be needed at run time. We will refer to the installation directory of MinGW (in which the first `bin` subdirectory is found) by `<mingw>`.
@@ -118,3 +119,16 @@ For Mozart to run properly, you need to ensure :
118119

119120
* Tcl/Tk is in your PATH or its `lib` and `bin` subfolders are merged with Mozart ones
120121
* An environment variable `OZEMACS` is set to `<emacs>\bin\runemacs.exe`
122+
123+
## Making Mozart 2 packages
124+
125+
If you want to build setup files for Mozart, just type in your terminal :
126+
127+
C:> mingw32-make installer
128+
129+
The new setup file will be located in your build directory. Two more CMake options are then available :
130+
131+
* `-DISS_INCLUDE_EMACS=ON` will include your Emacs files in the package.
132+
* `-DISS_INCLUDE_TCL=ON` will include your Tcl/Tk files in the package.
133+
134+
Please note that ActiveTcl is not redistributable without an OEM license.

distrib/windows/ModifyPath.iss

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
[Code]
2+
3+
// Version log:
4+
// 03/31/2003: Initial release (thv(at)lr.dk)
5+
6+
const
7+
// Modification method
8+
pmAddToBeginning = $1; // Add dir to beginning of Path
9+
pmAddToEnd = $2; // Add dir to end of Path
10+
pmAddAllways = $4; // Add also if specified dir is already included in existing path
11+
pmAddOnlyIfDirExists = $8; // Add only if specified dir actually exists
12+
pmRemove = $10; // Remove dir from path
13+
pmRemoveSubdirsAlso = $20; // Remove dir and all subdirs from path
14+
15+
// Scope
16+
psCurrentUser = 1; // Modify path for current user
17+
psAllUsers = 2; // Modify path for all users
18+
19+
// Error results
20+
mpOK = 0; // No errors
21+
mpMissingRights = -1; // User has insufficient rights
22+
mpAutoexecNoWriteacc = -2; // Autoexec can not be written (may be readonly)
23+
mpBothAddAndRemove = -3; // User has specified that dir should both be removed from and added to path
24+
25+
26+
{ Helper function: Split a path environment variable into individual dirnames }
27+
function SplitPath(Path: string): TStringList ;
28+
var
29+
Pos: Integer;
30+
S: string;
31+
begin
32+
Result := TStringList.Create;
33+
S := '';
34+
for Pos :=1 to Length(Path) do
35+
begin
36+
if Path[Pos] <> ';' then
37+
S := S + Path[Pos];
38+
if (Path[Pos] = ';') or (Pos = Length(Path)) then
39+
begin
40+
S := Trim(s);
41+
S := RemoveQuotes(s);
42+
S := Trim(s);
43+
if S <> '' then
44+
Result.Add(S);
45+
S := '';
46+
end;
47+
end;
48+
end; // function SplitPath
49+
50+
51+
{ Helper procedure: Concatenate individual dirnames into a path environment variable }
52+
function ConcatPath(Dirs: TStringList; Quotes: Boolean): string;
53+
var
54+
Index, MaxIndex: Integer;
55+
S: string;
56+
begin
57+
MaxIndex := Dirs.Count-1;
58+
Result := '';
59+
for Index := 0 to MaxIndex do
60+
begin
61+
S := Dirs.Strings[Index];
62+
if Quotes and (pos(' ', S) > 0) then
63+
S := AddQuotes(S);
64+
Result := Result + S;
65+
if Index < MaxIndex then
66+
Result := Result + ';'
67+
end;
68+
end; // function ConcatPath
69+
70+
71+
{ Helper function: Modifies path environment string }
72+
function ModifyPathString(OldPath: string; DirName: string; Method: Integer; Quotes: Boolean): string;
73+
var
74+
Dirs: TStringList;
75+
DirNotInPath: Boolean;
76+
I: Integer;
77+
begin
78+
// Remove quotes form DirName
79+
DirName := Trim(DirName);
80+
DirName := RemoveQuotes(DirName);
81+
DirName := Trim(DirName);
82+
83+
// Split old path in individual directory names
84+
Dirs := SplitPath(OldPath);
85+
86+
// Check if dir is already in path
87+
DirNotInPath := True;
88+
for I:=0 to Dirs.Count-1 do
89+
begin
90+
if AnsiUpperCase(Dirs.Strings[I]) = AnsiUpperCase(DirName) then
91+
DirNotInPath := False;
92+
end;
93+
94+
// Should dir be removed from existing Path?
95+
if (Method and (pmRemove or pmRemoveSubdirsAlso)) > 0 then
96+
begin
97+
for I:=0 to Dirs.Count-1 do
98+
begin
99+
if (((Method and pmRemoveSubdirsAlso) > 0) and (pos(AnsiUpperCase(DirName) + '', AnsiUpperCase(Dirs.Strings[I])) = 1)) or
100+
(((Method and (pmRemove) or (pmRemoveSubdirsAlso)) > 0) and (AnsiUpperCase(DirName) = AnsiUpperCase(Dirs.Strings[I])))
101+
then
102+
Dirs.Delete(I);
103+
end;
104+
end;
105+
106+
// Should dir be added to existing Path?
107+
if (Method and (pmAddToBeginning or pmAddToEnd)) > 0 then
108+
begin
109+
// Add dir to path
110+
if ((Method and pmAddAllways) > 0) or DirNotInPath then
111+
begin
112+
// Dir is not in path already or should be added anyway
113+
if ((Method and pmAddOnlyIfDirExists) = 0) or DirExists(DirName) then
114+
begin
115+
// Dir actually exists or should be added anyway
116+
if (Method and pmAddToBeginning) > 0 then
117+
Dirs.Insert(0, DirName)
118+
else
119+
Dirs.Append(DirName);
120+
end;
121+
end;
122+
end;
123+
124+
// Concatenate directory names into one single path variable
125+
Result := ConcatPath(Dirs, Quotes);
126+
// Finally free Dirs object
127+
Dirs.Free;
128+
end; // function ModifyPathString
129+
130+
{ Main function: Modify path }
131+
function ModifyPath(Path: string; Method: Integer; Scope: Integer): Integer;
132+
var
133+
RegRootKey: Integer;
134+
RegSubKeyName: string;
135+
RegValueName: string;
136+
OldPath, ResultPath: string;
137+
OK: Boolean;
138+
begin
139+
// Check if both add and remove has been specified (= error!)
140+
if (Method and (pmAddToBeginning or pmAddToEnd) and (pmRemove or pmRemoveSubdirsAlso)) > 0 then
141+
begin
142+
Result := mpBothAddAndRemove;
143+
Exit;
144+
end;
145+
146+
// Perform directory constant expansion
147+
Path := ExpandConstantEx(Path, ' ', ' ');
148+
149+
// Initialize registry key and value names to reflect if changes should be global or local to current user only
150+
case Scope of
151+
psCurrentUser:
152+
begin
153+
RegRootKey := HKEY_CURRENT_USER;
154+
RegSubKeyName := 'Environment';
155+
RegValueName := 'Path';
156+
end;
157+
psAllUsers:
158+
begin
159+
RegRootKey := HKEY_LOCAL_MACHINE;
160+
RegSubKeyName := 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
161+
RegValueName := 'Path';
162+
end;
163+
end;
164+
165+
// Read current path value from registry
166+
OK := RegQueryStringValue(RegRootKey, RegSubKeyName, RegValueName, OldPath);
167+
if not OK and (Scope = psAllUsers) then
168+
begin
169+
Result := mpMissingRights;
170+
Exit;
171+
end;
172+
173+
// Modify path
174+
ResultPath := ModifyPathString(OldPath, Path, Method, False);
175+
176+
// Write new path value to registry
177+
if not RegWriteStringValue(RegRootKey, RegSubKeyName, RegValueName, ResultPath) then
178+
begin
179+
Result := mpMissingRights;
180+
Exit;
181+
end;
182+
183+
// Expect everything to be OK
184+
Result := mpOK;
185+
end; // ModifyPath

distrib/windows/MozartConfig.iss

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
; This configuration file was generated by CMake
2+
#define OutputFilename "${CPACK_PACKAGE_FILE_NAME}"
3+
4+
; Mozart config
5+
#define MozartFolder "${CMAKE_INSTALL_PREFIX}"
6+
#define MozartVersion "${MOZART_PROP_OZ_VERSION}"
7+
#define LicenseFile "${CMAKE_SOURCE_DIR}/LICENSE.txt"
8+
9+
; Tcl/Tk config
10+
#define NeededTclVersion "'${ISS_TCL_VERSION}'"
11+
#define TclFolder "${ISS_TCL_PATH}"
12+
#define TclIncluded "${ISS_INCLUDE_TCL}"
13+
14+
; Emacs config
15+
#define EmacsFolder "${ISS_EMACS_PATH}"
16+
#define EmacsIncluded "${ISS_INCLUDE_EMACS}"
17+
18+
; Target architecture can be x86 and/or x64
19+
#define TargetArch "${MOZART_PROP_PLATFORM_ARCH}"

distrib/windows/MozartSetup.iss

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#include "MozartConfig.iss"
2+
3+
[Setup]
4+
; NOTE: The value of AppId uniquely identifies this application.
5+
; Do not use the same AppId value in installers for other applications.
6+
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
7+
AppId={{992C8269-AE73-4377-88BE-D92459001279}
8+
AppName=Mozart
9+
AppVersion={#MozartVersion}
10+
AppPublisher=Universite catholique de Louvain
11+
AppPublisherURL=http://mozart.github.io/
12+
AppSupportURL=http://mozart.github.io/
13+
AppUpdatesURL=http://mozart.github.io/
14+
DefaultDirName={pf}\Mozart
15+
DefaultGroupName=Mozart
16+
AllowNoIcons=yes
17+
LicenseFile={#LicenseFile}
18+
OutputDir=..\..
19+
OutputBaseFilename={#OutputFilename}
20+
Compression=lzma
21+
SolidCompression=yes
22+
WizardImageFile=mozartside.bmp
23+
WizardSmallImageFile=mozartsmall.bmp
24+
ChangesEnvironment=yes
25+
#if TargetArch == "x86_64"
26+
ArchitecturesAllowed=x64
27+
ArchitecturesInstallIn64BitMode=x64
28+
#endif
29+
30+
[Languages]
31+
Name: "english"; MessagesFile: "compiler:Default.isl"
32+
33+
34+
[Components]
35+
Name: "main"; Description: "Oz engine"; Types: full compact custom; Flags: fixed
36+
#if EmacsIncluded == "ON"
37+
Name: "emacs"; Description: "Emacs editor (for interactive Oz)"; Types: full
38+
#endif
39+
40+
41+
[Tasks]
42+
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
43+
44+
[Files]
45+
Source: "{#MozartFolder}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: main
46+
#if TclIncluded == "ON"
47+
Source: "{#TclFolder}\bin\*"; DestDir: "{app}\bin"; Flags: ignoreversion recursesubdirs; Components: main
48+
Source: "{#TclFolder}\lib\*"; DestDir: "{app}\lib"; Flags: ignoreversion recursesubdirs; Components: main
49+
#else
50+
Source: "TclVer.bat"; Flags: dontcopy
51+
#endif
52+
#if EmacsIncluded == "ON"
53+
Source: "{#EmacsFolder}\*"; DestDir: "{app}\opt"; Flags: ignoreversion recursesubdirs; Components: emacs
54+
#endif
55+
56+
[Icons]
57+
Name: "{group}\Mozart Programming Interface"; Filename: "{app}\bin\oz.exe"; IconFilename: "{app}\bin\oz.exe"
58+
Name: "{group}\{cm:UninstallProgram,Mozart}"; Filename: "{uninstallexe}"
59+
Name: "{commondesktop}\Mozart Programming Interface"; Filename: "{app}\bin\oz.exe"; Tasks: desktopicon; IconFilename: "{app}\bin\oz.exe"
60+
61+
[Registry]
62+
#if EmacsIncluded == "ON"
63+
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: string; ValueName: "OZEMACS"; ValueData: "{app}\opt\bin\runemacs.exe"; Flags: uninsdeletevalue; Components:emacs
64+
#endif
65+
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: string; ValueName: "OZHOME"; ValueData: "{app}"; Flags: uninsdeletevalue
66+
67+
[Code]
68+
#include "ModifyPath.iss"
69+
70+
procedure CurStepChanged(CurStep: TSetupStep);
71+
begin
72+
case CurStep of
73+
ssPostInstall:
74+
begin
75+
if IsAdminLoggedOn then
76+
ModifyPath('{app}\bin', pmAddToEnd, psAllUsers)
77+
else
78+
ModifyPath('{app}\bin', pmAddToEnd, psCurrentUser);
79+
end;
80+
end;
81+
end;
82+
83+
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
84+
begin
85+
case CurUninstallStep of
86+
usPostUninstall:
87+
begin
88+
if IsAdminLoggedOn then
89+
ModifyPath('{app}\bin', pmRemove, psAllUsers)
90+
else
91+
ModifyPath('{app}\bin', pmRemove, psCurrentUser);
92+
end;
93+
end;
94+
end;
95+
96+
#if !(TclIncluded == "ON")
97+
function PrepareToInstall(var NeedsRestart: Boolean): String;
98+
var
99+
TmpFileName, ExecStdout: string;
100+
ResultCode: integer;
101+
Version : string;
102+
begin
103+
ExtractTemporaryFile('TclVer.bat');
104+
TmpFileName := ExpandConstant('{tmp}') + '\tclver.txt';
105+
Exec(ExpandConstant('{tmp}') + '\TclVer.bat', '> "' + TmpFileName + '"', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
106+
LoadStringFromFile(TmpFileName, ExecStdout);
107+
Version := Trim(ExecStdout);
108+
if Version = '0.0' then
109+
MsgBox('Tcl/Tk ' + {#NeededTclVersion} + ' seems not to be installed or not to be in your PATH. Mozart may not work properly.', mbError, MB_OK)
110+
else if not (Version = {#NeededTclVersion}) then
111+
MsgBox('Tcl/Tk ' + Version + ' was found, but version ' + {#NeededTclVersion} + ' is required. Mozart may not work properly.', mbError, MB_OK);
112+
DeleteFile(TmpFileName);
113+
Result := '';
114+
end;
115+
#endif

distrib/windows/TclVer.bat

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@echo off
2+
set PATH=%PATH%;%Systemdrive%\Tcl\bin
3+
set CMD=tclsh
4+
5+
where %CMD% 1>NUL 2>NUL
6+
if %ERRORLEVEL% neq 0 (
7+
echo 0.0
8+
) else echo puts $tcl_version;exit 0 | %CMD% 2>NUL

distrib/windows/mozartside.bmp

151 KB
Binary file not shown.

distrib/windows/mozartsmall.bmp

9.57 KB
Binary file not shown.

0 commit comments

Comments
 (0)