!!!!! OUTDATED !!!!!!!!!


Instructions on building Windows installers
===========================================

Required tools:

- Python (last version used 2.4.1)

- InstallShield Developer Studio 9 (newer versions may work)

    -- or -- 
    
- InstallShield clean build tools (if you aren't going to edit the projects)

- cygwin* 

- unzip 

- Microsoft Visual C++ 6.0 sp 5 or greater

- Microsoft .NET 2003

- Microsoft Visual Studio 2005 

- JDK supported by Ice.

*Cygwin
-------

Cygwin is required for 'links' to convert some html to text and bash for
some scripts to update the InstallShield projects and component lists.

Setting up the environment 
--------------------------

You can find two batch files in the ice/install/windows directory.
env_example.bat is a sample batch files that you can make copies of and
edit to match your personal environment. You will probably want to
create a batch file for each target compiler (e.g. 6env.bat is for
Visual C++ 6.0). Please make a copy of the example batch file before
editing it so spurious CVS commits do not overwrite your environment
specific configuration.

The purpose of the batch file is to setup several environment variables
that are used by the makewindist.py script.  Most of the environment
variables indicate the location of third party libraries that are used
to create the installers.

Another batch file, named buildenv.bat, verifies the environment and
sets up a few additional environment variables that are common to all
target compilers. buildenv.bat differs from the compiler specific batch
files as its settings are reversible through another batch file,
resetenv.bat. Most importantly buildenv sets the INCLUDE and LIB
environment variables required by the compiler to locate the third party
libraries. The installer construction process does *NOT* use the
include/library settings you specified in Tools|Options in your
Developer Studio configuration. 

The important environment variables are:

STLPORT_HOME - location of built STLPort distribution (VC 6 only)
OPENSSL_HOME - location of built OpenSSL distribution 
BZIP2_HOME - location of built bzip2 distribution
DB_HOME - location of built Berkeley DB distribution

JGOODIES_HOME - location of JGoodies jars.
JGOODIES_FORMS - location of JGoodies Forms source distribution.
JGOODIES_LOOKS - location of JGoodies Looks source distribution.
PYTHON_HOME - location where Python is installed 
PHP_SRC_HOME - PHP source distribution (not required for VC 6)
PHP_BIN_HOME - PHP binary distribution (not required for VC 6)
SOURCES - location of Ice source distributions
BUILD_DIR - location where the Ice source distrbutions will be unzipped and built

Once your environment is set you are ready to build the third party
libraries for you target compiler.

Building the third party libraries
----------------------------------

  NOTE: You should consider grouping all of your third party libraries
  used to create an installer for a given compiler in a separate
  directory.  This will help to avoid mixups with third party libraries
  built for other compilers, testing reasons, etc. 

There are several third party libraries that are required for all Windows
installers, regardless of compiler target. Since we produce third party
installers for each compiler target, you will need builds of the third party
libraries for each compiler target you wish to create installers for. The
third party libraries used for all compiler targets are:

 - OpenSSL
 - Expat
 - bzip2
 - Berkeley DB

  - Building OpenSSL -

We use MASM builds of OpenSSL on Windows.  MASM comes bundled with
Visual Studio .NET 2004 and Visual Studio 2005 but not Visual C++ 6.0.
To build OpenSSL for VC 6.0, append the location of the ml.exe
executable to your PATH. This step should not be necessary if you are building for the other targets.

To configure and build OpenSSL, simply follow the instructions for building a MASM NT DLL version of OpenSSL.

  - Building Expat -

XXX

  - Building bzip2 -

The bzip2 source distribution doesn't include support for creating DLLs.
We've included a patch and a modified makefile in
ice/install/thirdparty/bzip2. Copy the patch and makefile to the bzip2
source directory and install the patch on bzlib.h, and run nmake /f makefile.

  - Berkeley DB -

There are no special requirement for building Berkeley DB at this time.
Built it as you normally would.

Building the Windows installers
-------------------------------

Open a console window and setup the environment for the desired installation
target. You can use the files mentioned in "Setting up the Environment" as
templates for creating batch files to customize your environment. Change to the
ice/install/common subdirectory and run makewindist.py, specifying which
compiler you wish to target. For example:

  makewindist.py --vc60

or,

  makewindist.py --vc71 

If you are targetting Visual C++ 6.0 then all that is left is to wait. In the
case of VC 7.1 and VC 8.0, the process will stop after the third party
installer with an error that the All.sln file cannot be found. This 'snag' has
not been resolved since there currently is no way to automatically  convert
projects from VC 6.0 to VC 7.1 or 8.0.  You must go to where you indicated the
sources to be staged (see "Setting up the Environment") and manually load and
convert the workspaces in Ice and the Ice demo tree, IcePy and IcePHP. After
the workspaces have been converted to solutions, simply run the makewindist.py
command again and things should proceed normally. If the process was
successful, the installers will be deposited in a target specific directory
under the ice/install directory. For example:

    ice/install/vc60/install # for VC60
    ice/install/vc71/install # for VC71

Getting files into the installers
---------------------------------

The installers are organized into installable 'components' (not to be confused
with InstallShield components, which will be discussed later). A component is a
collection of file lists and destinations. The current component definitions
are defined in ice/install/common/components/components.ini. The file lists
that are used by the component definitions are in the
ice/install/common/components directory also. 

The python source that reads and interprets the components.ini file is found in
ice/install/common/components.py

 -- Anatomy of the component definition file --

The component definition file is similar to the Windows .INI file format. The
reason for using this format is primarily convenience. The Python standard
library contains a ConfigParser module that manages information in this format
and the format itself is very easy to modify with a text editor. 

The components are grouped into two 'macro' groups, ice and packages. Ice lists
the components that will be included in the Ice installer and packages lists
the components that will be included in the third party installers. The reason
for the names 'ice' and 'packages' is that they map to directories where the
InstallShield projects expect to find staged files (it is also partly
historical, the InstallShield projects could be changed to pick up these files
from a different location and the name changed to something morning meaningful,
such as changing 'packages' to 'third-party'). The component maps in these
macro groups also map the the individual components to directories.  For
example, 

    [ice]
    ice-common=ice common

This will cause the component definition 'ice common' to be mapped into
ice/common in the Ice installer staging directory.  The fact that ice-common
and ice common is coincidental. It could as well be:

    ice-common=foo bar

Only the first part is signficant for the purpose of mapping the destination of
the component files.

A component definition is made up of several parts. First is the 'section name'
that identifies the component definition. It is the first part of the component
definition and is enclosed in square brackets ([]). For example:

    [ice common]

The consituent parts are an entry that specifies the number of 'elements' in
the component, whether the component is 'active' or not, and the element
definitions themselves. If the component is 'inactive' (i.e. active=0), then
the component elements will not be processed and the files not included in the
installer. A component 'element' actually requires at least 3 parts, a
'source(n)' which identifies where the files can be found, a 'filelist(n)' (n
is the element number) which enumerates the files that should be copied from
the 'source(n)', and a 'dest(n)' for the destination where the files will be
copied to. The 'dest(n)' is relative to the path that the component is mapped
into.  An element may also have a 'filetemplate(n)' value that can be used in
conjunction with a file list to ma strings to filenames. This allows some lists
to be reused. For example, DLLs and import libraries only differ by extension
and debug and release versions only differ by the 'd' suffix at the end fo the
debug libraries base filename.

An component definition example:

[ice runtime]
elements=7
active=1

;;
;; DLL files that are installed as part of the runtime. 
;;
source1=%(BUILD_DIR)s/Ice-%(version)s/src
filelist1=ice.runtime.dlls
filetemplate1=f,%(name)s/Release/%(name)s%(dllversion)s.dll
dest1=bin
;;
;; EXE files that are installed as part of the runtime.
;;
source2=%(BUILD_DIR)s/Ice-%(version)s/src
filelist2=ice.runtime.exes
filetemplate2=%(name)s.exe
dest2=bin
;;
;; Slice files
;;
source3=%(BUILD_DIR)s/Ice-%(version)s/slice
filelist3=ice.slice
filetemplate3=%(name)s.ice
dest3=slice
;;
;; Certs
;;
source4=%(BUILD_DIR)s/Ice-%(version)s/certs
filelist4=ice.runtime.certs
dest4=certs

source5=%(BUILD_DIR)s/Ice-%(version)s/src
filelist5=ice.runtime.icestormservice
dest5=bin

source6=%(BUILD_DIR)s/IceJ-%(version)s/lib
filelist6=icegridgui
dest6=bin

source7=%(BUILD_DIR)s/Ice-%(version)s/config
filelist7=ice.config.files
dest7=config

Chances are that file additions for existing components will simply involve
adding an appropriate entry to an exisiting file list. However, large changes
may require more pervasive modifications involving adding file lists, changes
to the makewindist.py script and the InstallShield projects.

Filelists themselves can simply be a list of filenames or a list of wildcards.
Wildcards are not recommended as they are a 'best effort' mechanism for
selecting files and may result in unwanted files being included in the
installer or no files at all. Discovery of the error usually doesn't occur
until the installer itself is tested.

Filelist entries may be prefixed with an "f" followed by a command then the
path to the file. This causes the file copy operation to 'flatten' the
directory, allowing files from diverse directories to easily be collected into
a single location.

Maintaining filelists may be difficult as there can be a lot of files. There
are some bash script files in the ice/install/components directory for creating
the demo file lists. The resultant demo file lists actually include the
instructions for regenerating the file so if the scripts are lost, the commands
are still around. 

Getting ready for a release
---------------------------

There are a few steps in updating the installer projects in preparation
for a release:

1. Updating codes - MSI installers contain a PackageCode and an
UpdateCode which are UUID type values that uniquely identify the product
being installed. To avoid clashing with other installations of Ice, you
need to change these values. 

2. Update strings in projects -  the Ice version number appears in a few
different places, the ProductName and ProductVersion properties as well
as the MSIPackageFileName and installation directories.

3. Check file lists - this may not be necessary, but you may be aware of
specific files that have been added. Now's a good time to add them to
the appropriate file list.

4. Add policy assemblies - if this is a patch release, chances are good
that there are policy assemblies that need to be installed for backwards
compatability.

There are example scripts in ice/install/windows that you can use to
modify the XML formatted .ism files. The script is currently only for
convenience and documenting the changes that are required. These
currently aren't part of the automated processes because these changes
only need to occur once prior to release. It should be noted that the
scripts currently are not authoritative either. It is currently quite
easily to modify the InstallShield projects in away that interferes with
the scripts operation.

InstallShield hints
-------------------

  NOTE: If you are going to do a lot of work with InstallShield
  projects, reading the InstallShield and Windows Installer
  documentation is highly recommended. Not for their literary value, but
  the details often tend to be rather arcane and arguably non-intuitive.

- Merge Modules -

Next to the MSI files themselves, merge modules are the 'largest'
reusable 'component' for constructing installers. Creating merge modules
is similar to creating installers but cannot be installed by themselves.
We have been using modules to group release and debug versions of third
 
- Components and Features -

Installations are organized into components and features to facilitate
'custom' installation or conditional installation of components. 

- Redistributables -

Appendix

Example batch files
-------------------
 -- env_example.bat -- 
@echo off
::
:: Things are a little easier if you group all your third party
:: libraries for a specific target compiler in a single parent
:: directory.
::  
set base=c:\src\third_party


::
:: STLPORT_HOME is only required for the VC 6 target.
::
set STLPORT_HOME=%base%\STLport-4.6.2

::
:: OPENSSL_HOME, EXPAT_HOME, DB_HOME, JGOODIES_HOME, JGOODIES_FORMS,
:: JGOODIES_LOOKS, SOURCES and BUILD_DIR are required for all target
:: compilers.
::
set OPENSSL_HOME=%base%\openssl-0.9.8a
set EXPAT_HOME=%base%\expat-1.95.8
set BZIP2_HOME=%base%\bzip2-1.0.3
set DB_HOME=%base%\db-4.3.29.NC
set JGOODIES_HOME=y:\java
set JGOODIES_FORMS=c:\src\forms-1.0.5
set JGOODIES_LOOKS=c:\src\looks-1.3.2

::
:: PYTHON_HOME, PHP_SRC_HOME and PHP_BIN_HOME are only required for
:: building installers that will include components of IcePy and IcePHP.
::
set PYTHON_HOME=c:\Python24
set PHP_SRC_HOME=c:\src\vc71\php-5.0.5
set PHP_BIN_HOME=c:\src\vc71\php-5.0.5-win32

::
:: SOURCES is the location fo the zip archives for the current release.
:: Windows installers must be constructed from source distributions.
::
set SOURCES=y:\sources

::
:: Its a good idea to have separate build directories for each target
:: compiler. The makewindist.py script unpacks the archives found in
:: SOURCES into this location and proceeds to build the distributions in
:: place.
::
set BUILD_DIR=c:\src\vc60\stage

::
:: XXX- Not sure why this is required.
::
set CLASSPATH=%JGOODIES_HOME%\looks-1.3.2.jar;%JGOODIES_HOME%\forms-1.0.5.jar;%db_home%\build_win32\release\db.jar

::
:: You might want to set some visual indication that this environment
:: has been configured. Alternatives might include changing the command
:: prompt.
::
TITLE VC60 distribution environment

 -- buildenv.bat --
@echo off

if not "%PRE_ICE_BUILD_ENV%" == "" GOTO alreadyset

if "%OPENSSL_HOME%" == "" GOTO NO_OPENSSL
if "%STLPORT_HOME%" == "" GOTO NO_STLPORT
:WHATEV
if "%EXPAT_HOME%" == "" GOTO NO_EXPAT
if "%BZIP2_HOME%" == "" GOTO NO_BZIP2
if "%DB_HOME%" == "" GOTO NO_DB

set PRE_ICE_BUILD_ENV=1
set OLD_LIB=%LIB%
set OLD_INCLUDE=%INCLUDE%

set LIB=%OPENSSL_HOME%\out32dll;%EXPAT_HOME%\lib\Release;%EXPAT_HOME%\lib\Release-w;%BZIP2_HOME%;%STLPORT_HOME%\lib;%DB_HOME%\build_win32\Debug;%DB_HOME%\build_win32\Release;%JAVA_HOME%\lib;%LIB%
set INCLUDE=%STLPORT_HOME%\stlport;%BZIP2_HOME%;%OPENSSL_HOME%\inc32;%EXPAT_HOME%\lib;%DB_HOME%\build_win32;%JAVA_HOME%\include;%JAVA_HOME%\include\win32;%INCLUDE%

set JGOODIES_HOME=y:\java
set INSTALLSHIELD_HOME=C:\Progra~1\Instal~2\DevStu~1\System

goto end

:alreadyset
echo environment is already set.
goto end

:NO_OPENSSL
echo Set OPENSSL_HOME. Exiting...
goto end

:NO_STLPORT
echo No STLPORT_HOME. Assuming VC 7, if not, you are in trouble...
goto WHATEV

:NO_EXPAT
echo Set EXPAT_HOME. Exiting...
goto end

:NO_BZIP2
echo Set BZIP2_HOME. Exiting...
goto end

:NO_DB
echo Set DB_HOME. Exiting...
goto end

:end
