Skip to content

Commit

Permalink
Added Inno Setup packaging method
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
anthonygego committed Sep 2, 2014
1 parent f443d13 commit 0410de8
Show file tree
Hide file tree
Showing 10 changed files with 384 additions and 1 deletion.
33 changes: 33 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -111,5 +111,38 @@ set(CPACK_RPM_PACKAGE_ARCHITECTURE "${MOZART_PROP_PLATFORM_ARCH}")
set(CPACK_RPM_PACKAGE_REQUIRES "tcl >= 8.5, tk >= 8.5, emacs")
set(CPACK_RPM_PACKAGE_GROUP "Development/Languages")

# Configuration of Inno Setup files

if(WIN32)
find_program(ISS_COMPILER NAMES iscc ISCC
HINTS "C:/Program Files (x86)/Inno Setup 5" "C:/Program Files/Inno Setup 5")

if(NOT ISS_COMPILER)
message(WARNING "Inno Setup Compiler not found. You won't be able to build setup files.")
else()
message(STATUS "Using Inno Setup Compiler from: ${ISS_COMPILER}")
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/distrib/windows"
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/distrib")

# Compute Tcl/Tk install path
get_filename_component(ISS_TCL_EXEC_PARENT "${ISS_TCL_EXEC}" DIRECTORY)
get_filename_component(ISS_TCL_PATH "${ISS_TCL_EXEC_PARENT}" DIRECTORY)

# Compute emacs install path
get_filename_component(ISS_EMACS_EXEC_PARENT "${ISS_EMACS_EXEC}" DIRECTORY)
get_filename_component(ISS_EMACS_PATH "${ISS_EMACS_EXEC_PARENT}" DIRECTORY)

# Parse Inno Setup config file
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/distrib/windows/MozartConfig.iss"
"${CMAKE_CURRENT_BINARY_DIR}/distrib/windows/MozartConfig.iss")

# Add installer target
add_custom_target(installer
COMMAND ${CMAKE_MAKE_PROGRAM} install
COMMAND ${ISS_COMPILER} "${CMAKE_CURRENT_BINARY_DIR}/distrib/windows/MozartSetup.iss"
VERBATIM)
endif()
endif()

# Finally include CPack
include(CPack)
14 changes: 14 additions & 0 deletions README.Windows.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Download and install the following tools:
* Python (required for building LLVM)
* Git for Windows
* CMake >= 2.8.6
* [Inno Setup](http://www.jrsoftware.org/isdl.php) (with preprocessor, required for building setup files)
* 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.

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>`.
Expand Down Expand Up @@ -118,3 +119,16 @@ For Mozart to run properly, you need to ensure :

* Tcl/Tk is in your PATH or its `lib` and `bin` subfolders are merged with Mozart ones
* An environment variable `OZEMACS` is set to `<emacs>\bin\runemacs.exe`

## Making Mozart 2 packages

If you want to build setup files for Mozart, just type in your terminal :

C:> mingw32-make installer

The new setup file will be located in your build directory. Two more CMake options are then available :

* `-DISS_INCLUDE_EMACS=ON` will include your Emacs files in the package.
* `-DISS_INCLUDE_TCL=ON` will include your Tcl/Tk files in the package.

Please note that ActiveTcl is not redistributable without an OEM license.
185 changes: 185 additions & 0 deletions distrib/windows/ModifyPath.iss
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
[Code]
// Version log:
// 03/31/2003: Initial release (thv(at)lr.dk)
const
// Modification method
pmAddToBeginning = $1; // Add dir to beginning of Path
pmAddToEnd = $2; // Add dir to end of Path
pmAddAllways = $4; // Add also if specified dir is already included in existing path
pmAddOnlyIfDirExists = $8; // Add only if specified dir actually exists
pmRemove = $10; // Remove dir from path
pmRemoveSubdirsAlso = $20; // Remove dir and all subdirs from path
// Scope
psCurrentUser = 1; // Modify path for current user
psAllUsers = 2; // Modify path for all users
// Error results
mpOK = 0; // No errors
mpMissingRights = -1; // User has insufficient rights
mpAutoexecNoWriteacc = -2; // Autoexec can not be written (may be readonly)
mpBothAddAndRemove = -3; // User has specified that dir should both be removed from and added to path
{ Helper function: Split a path environment variable into individual dirnames }
function SplitPath(Path: string): TStringList ;
var
Pos: Integer;
S: string;
begin
Result := TStringList.Create;
S := '';
for Pos :=1 to Length(Path) do
begin
if Path[Pos] <> ';' then
S := S + Path[Pos];
if (Path[Pos] = ';') or (Pos = Length(Path)) then
begin
S := Trim(s);
S := RemoveQuotes(s);
S := Trim(s);
if S <> '' then
Result.Add(S);
S := '';
end;
end;
end; // function SplitPath
{ Helper procedure: Concatenate individual dirnames into a path environment variable }
function ConcatPath(Dirs: TStringList; Quotes: Boolean): string;
var
Index, MaxIndex: Integer;
S: string;
begin
MaxIndex := Dirs.Count-1;
Result := '';
for Index := 0 to MaxIndex do
begin
S := Dirs.Strings[Index];
if Quotes and (pos(' ', S) > 0) then
S := AddQuotes(S);
Result := Result + S;
if Index < MaxIndex then
Result := Result + ';'
end;
end; // function ConcatPath
{ Helper function: Modifies path environment string }
function ModifyPathString(OldPath: string; DirName: string; Method: Integer; Quotes: Boolean): string;
var
Dirs: TStringList;
DirNotInPath: Boolean;
I: Integer;
begin
// Remove quotes form DirName
DirName := Trim(DirName);
DirName := RemoveQuotes(DirName);
DirName := Trim(DirName);
// Split old path in individual directory names
Dirs := SplitPath(OldPath);
// Check if dir is already in path
DirNotInPath := True;
for I:=0 to Dirs.Count-1 do
begin
if AnsiUpperCase(Dirs.Strings[I]) = AnsiUpperCase(DirName) then
DirNotInPath := False;
end;
// Should dir be removed from existing Path?
if (Method and (pmRemove or pmRemoveSubdirsAlso)) > 0 then
begin
for I:=0 to Dirs.Count-1 do
begin
if (((Method and pmRemoveSubdirsAlso) > 0) and (pos(AnsiUpperCase(DirName) + '', AnsiUpperCase(Dirs.Strings[I])) = 1)) or
(((Method and (pmRemove) or (pmRemoveSubdirsAlso)) > 0) and (AnsiUpperCase(DirName) = AnsiUpperCase(Dirs.Strings[I])))
then
Dirs.Delete(I);
end;
end;
// Should dir be added to existing Path?
if (Method and (pmAddToBeginning or pmAddToEnd)) > 0 then
begin
// Add dir to path
if ((Method and pmAddAllways) > 0) or DirNotInPath then
begin
// Dir is not in path already or should be added anyway
if ((Method and pmAddOnlyIfDirExists) = 0) or DirExists(DirName) then
begin
// Dir actually exists or should be added anyway
if (Method and pmAddToBeginning) > 0 then
Dirs.Insert(0, DirName)
else
Dirs.Append(DirName);
end;
end;
end;
// Concatenate directory names into one single path variable
Result := ConcatPath(Dirs, Quotes);
// Finally free Dirs object
Dirs.Free;
end; // function ModifyPathString
{ Main function: Modify path }
function ModifyPath(Path: string; Method: Integer; Scope: Integer): Integer;
var
RegRootKey: Integer;
RegSubKeyName: string;
RegValueName: string;
OldPath, ResultPath: string;
OK: Boolean;
begin
// Check if both add and remove has been specified (= error!)
if (Method and (pmAddToBeginning or pmAddToEnd) and (pmRemove or pmRemoveSubdirsAlso)) > 0 then
begin
Result := mpBothAddAndRemove;
Exit;
end;
// Perform directory constant expansion
Path := ExpandConstantEx(Path, ' ', ' ');
// Initialize registry key and value names to reflect if changes should be global or local to current user only
case Scope of
psCurrentUser:
begin
RegRootKey := HKEY_CURRENT_USER;
RegSubKeyName := 'Environment';
RegValueName := 'Path';
end;
psAllUsers:
begin
RegRootKey := HKEY_LOCAL_MACHINE;
RegSubKeyName := 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
RegValueName := 'Path';
end;
end;
// Read current path value from registry
OK := RegQueryStringValue(RegRootKey, RegSubKeyName, RegValueName, OldPath);
if not OK and (Scope = psAllUsers) then
begin
Result := mpMissingRights;
Exit;
end;
// Modify path
ResultPath := ModifyPathString(OldPath, Path, Method, False);
// Write new path value to registry
if not RegWriteStringValue(RegRootKey, RegSubKeyName, RegValueName, ResultPath) then
begin
Result := mpMissingRights;
Exit;
end;
// Expect everything to be OK
Result := mpOK;
end; // ModifyPath
19 changes: 19 additions & 0 deletions distrib/windows/MozartConfig.iss
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
; This configuration file was generated by CMake
#define OutputFilename "${CPACK_PACKAGE_FILE_NAME}"

; Mozart config
#define MozartFolder "${CMAKE_INSTALL_PREFIX}"
#define MozartVersion "${MOZART_PROP_OZ_VERSION}"
#define LicenseFile "${CMAKE_SOURCE_DIR}/LICENSE.txt"

; Tcl/Tk config
#define NeededTclVersion "'${ISS_TCL_VERSION}'"
#define TclFolder "${ISS_TCL_PATH}"
#define TclIncluded "${ISS_INCLUDE_TCL}"

; Emacs config
#define EmacsFolder "${ISS_EMACS_PATH}"
#define EmacsIncluded "${ISS_INCLUDE_EMACS}"

; Target architecture can be x86 and/or x64
#define TargetArch "${MOZART_PROP_PLATFORM_ARCH}"
115 changes: 115 additions & 0 deletions distrib/windows/MozartSetup.iss
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#include "MozartConfig.iss"

[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{992C8269-AE73-4377-88BE-D92459001279}
AppName=Mozart
AppVersion={#MozartVersion}
AppPublisher=Universite catholique de Louvain
AppPublisherURL=http://mozart.github.io/
AppSupportURL=http://mozart.github.io/
AppUpdatesURL=http://mozart.github.io/
DefaultDirName={pf}\Mozart
DefaultGroupName=Mozart
AllowNoIcons=yes
LicenseFile={#LicenseFile}
OutputDir=..\..
OutputBaseFilename={#OutputFilename}
Compression=lzma
SolidCompression=yes
WizardImageFile=mozartside.bmp
WizardSmallImageFile=mozartsmall.bmp
ChangesEnvironment=yes
#if TargetArch == "x86_64"
ArchitecturesAllowed=x64
ArchitecturesInstallIn64BitMode=x64
#endif

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"


[Components]
Name: "main"; Description: "Oz engine"; Types: full compact custom; Flags: fixed
#if EmacsIncluded == "ON"
Name: "emacs"; Description: "Emacs editor (for interactive Oz)"; Types: full
#endif


[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked

[Files]
Source: "{#MozartFolder}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: main
#if TclIncluded == "ON"
Source: "{#TclFolder}\bin\*"; DestDir: "{app}\bin"; Flags: ignoreversion recursesubdirs; Components: main
Source: "{#TclFolder}\lib\*"; DestDir: "{app}\lib"; Flags: ignoreversion recursesubdirs; Components: main
#else
Source: "TclVer.bat"; Flags: dontcopy
#endif
#if EmacsIncluded == "ON"
Source: "{#EmacsFolder}\*"; DestDir: "{app}\opt"; Flags: ignoreversion recursesubdirs; Components: emacs
#endif

[Icons]
Name: "{group}\Mozart Programming Interface"; Filename: "{app}\bin\oz.exe"; IconFilename: "{app}\bin\oz.exe"
Name: "{group}\{cm:UninstallProgram,Mozart}"; Filename: "{uninstallexe}"
Name: "{commondesktop}\Mozart Programming Interface"; Filename: "{app}\bin\oz.exe"; Tasks: desktopicon; IconFilename: "{app}\bin\oz.exe"

[Registry]
#if EmacsIncluded == "ON"
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: string; ValueName: "OZEMACS"; ValueData: "{app}\opt\bin\runemacs.exe"; Flags: uninsdeletevalue; Components:emacs
#endif
Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: string; ValueName: "OZHOME"; ValueData: "{app}"; Flags: uninsdeletevalue

[Code]
#include "ModifyPath.iss"
procedure CurStepChanged(CurStep: TSetupStep);
begin
case CurStep of
ssPostInstall:
begin
if IsAdminLoggedOn then
ModifyPath('{app}\bin', pmAddToEnd, psAllUsers)
else
ModifyPath('{app}\bin', pmAddToEnd, psCurrentUser);
end;
end;
end;
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
case CurUninstallStep of
usPostUninstall:
begin
if IsAdminLoggedOn then
ModifyPath('{app}\bin', pmRemove, psAllUsers)
else
ModifyPath('{app}\bin', pmRemove, psCurrentUser);
end;
end;
end;
#if !(TclIncluded == "ON")
function PrepareToInstall(var NeedsRestart: Boolean): String;
var
TmpFileName, ExecStdout: string;
ResultCode: integer;
Version : string;
begin
ExtractTemporaryFile('TclVer.bat');
TmpFileName := ExpandConstant('{tmp}') + '\tclver.txt';
Exec(ExpandConstant('{tmp}') + '\TclVer.bat', '> "' + TmpFileName + '"', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
LoadStringFromFile(TmpFileName, ExecStdout);
Version := Trim(ExecStdout);
if Version = '0.0' then
MsgBox('Tcl/Tk ' + {#NeededTclVersion} + ' seems not to be installed or not to be in your PATH. Mozart may not work properly.', mbError, MB_OK)
else if not (Version = {#NeededTclVersion}) then
MsgBox('Tcl/Tk ' + Version + ' was found, but version ' + {#NeededTclVersion} + ' is required. Mozart may not work properly.', mbError, MB_OK);
DeleteFile(TmpFileName);
Result := '';
end;
#endif
8 changes: 8 additions & 0 deletions distrib/windows/TclVer.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
@echo off
set PATH=%PATH%;%Systemdrive%\Tcl\bin
set CMD=tclsh

where %CMD% 1>NUL 2>NUL
if %ERRORLEVEL% neq 0 (
echo 0.0
) else echo puts $tcl_version;exit 0 | %CMD% 2>NUL
Binary file added distrib/windows/mozartside.bmp
Binary file not shown.
Binary file added distrib/windows/mozartsmall.bmp
Binary file not shown.
Loading

0 comments on commit 0410de8

Please sign in to comment.