Beginner's guide to MSI creation
msitools provides a compiler called wixl that is able to construct MSI file from a wxs file, written in XML.
The wxs format is shared with WiX (http://wixtoolset.org), so you can follow a tutorial to learn how to edit such file: http://wix.tramontana.co.hu/ .
Here is a short wxs file:
<?xml version='1.0' encoding='windows-1252'?> <Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'> <Product Name='Foobar 1.0' Id='ABCDDCBA-86C7-4D14-AEC0-86416A69ABDE' UpgradeCode='ABCDDCBA-7349-453F-94F6-BCB5110BA4FD' Language='1033' Codepage='1252' Version='1.0.0' Manufacturer='Acme Ltd.'> <Package Id='*' Keywords='Installer' Description="Acme's Foobar 1.0 Installer" Comments='Foobar is a registered trademark of Acme Ltd.' Manufacturer='Acme Ltd.' InstallerVersion='100' Languages='1033' Compressed='yes' SummaryCodepage='1252' /> <Media Id='1' Cabinet='Sample.cab' EmbedCab='yes' DiskPrompt="CD-ROM #1" /> <Property Id='DiskPrompt' Value="Acme's Foobar 1.0 Installation [1]" /> <Directory Id='TARGETDIR' Name='SourceDir'> <Directory Id='ProgramFilesFolder' Name='PFiles'> <Directory Id='Acme' Name='Acme'> <Directory Id='INSTALLDIR' Name='Foobar 1.0'> <Component Id='MainExecutable' Guid='ABCDDCBA-83F1-4F22-985B-FDB3C8ABD471'> <File Id='FoobarEXE' Name='FoobarAppl10.exe' DiskId='1' Source='FoobarAppl10.exe' KeyPath='yes'/> </Component> </Directory> </Directory> </Directory> </Directory> <Feature Id='Complete' Level='1'> <ComponentRef Id='MainExecutable' /> </Feature> </Product> </Wix>
wixl uses a single command to build. (WiX uses "heat" and "candle", see also this diagram).
Let's build the MSI:
# create a fake file $ touch FoobarAppl10.exe # build $ wixl -v sample.wxs Loading sample.wxs... Building sample.msi... Writing sample.msi...
You can then inspect MSI files with msidump and msiextract.
$ msiextract -l sample.msi Program Files/Acme/Foobar 1.0/FoobarAppl10.exe $ msidump sample.msi Exporting table _SummaryInformation... Exporting table _ForceCodepage... Exporting table AdminExecuteSequence... Exporting table AdvtExecuteSequence... Exporting table Component... Exporting table FeatureComponents... Exporting table CreateFolder... Exporting table AppSearch... Exporting table Property... Exporting table File... Exporting table ServiceInstall... Exporting table Error... Exporting table InstallExecuteSequence... Exporting table InstallUISequence... Exporting table RegLocator... Exporting table Feature... Exporting table CustomAction... Exporting table Icon... Exporting table Upgrade... Exporting table RemoveFile... Exporting table Shortcut... Exporting table Directory... Exporting table AdminUISequence... Exporting table Registry... Exporting table LaunchCondition... Exporting table Media... Exporting table Binary... Exporting table ServiceControl... Exporting table Signature... Exporting table MsiFileHash... $ cat File.idt File Component_ FileName FileSize Version Language Attributes Sequence s72 s72 l255 i4 S72 S20 I2 i4 File File FoobarEXE MainExecutable FoobarAppl10.exe 1 512 1
To compare two MSIs, use msidiff. It can be handy to find bugs or missing features comparing WiX MSI build and wixl build for the same input.
Generating component groups
wixl-heat can help you to generate the list of files for your project and its dependencies. It takes the list of files as an input, either listed manually, or with ls, find or rpm -ql for instance:
echo /usr/i686-w64-mingw32/sys-root/mingw/bin/zlib1.dll | wixl-heat -p /usr/i686-w64-mingw32/sys-root/mingw/ --component-group CG.zlib --var var.SourceDir <?xml version="1.0" encoding="utf-8"?> <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> <Fragment> <DirectoryRef Id="TARGETDIR"> <Directory Id="dir9A5D56716D566997FA290054D161AF96" Name="bin"> <Component Id="cmp9FA4766702C1F85ABA6E04DE3B061A12" Guid="*"> <File Id="filE110AAB4803C5CC567BBCF8AD3BB7C08" KeyPath="yes" Source="$(var.SourceDir)/bin/zlib1.dll"/> </Component> </Directory> </DirectoryRef> </Fragment> <Fragment> <ComponentGroup Id="CG.zlib"> <ComponentRef Id="cmp9FA4766702C1F85ABA6E04DE3B061A12"/> </ComponentGroup> </Fragment> </Wix> <!-- generated with msitools 0.93.40-6aec --> <!-- wixl-heat -p /usr/i686-w64-mingw32/sys-root/mingw/ -component-group CG.zlib -var var.SourceDir -->
You can see an example how to automate the build process for a complex project in the virt-viewer source code, https://git.fedorahosted.org/cgit/virt-viewer.git/tree/data/Makefile.am:
# install project in temporary directory $(AM_V_GEN)DESTDIR=`mktemp -d` && \ make -C $(top_builddir) install DESTDIR=$$DESTDIR >/dev/null && \ # generate a wxs with all the files in CG.virt-viewer component group find $$DESTDIR | wixl-heat -p $$DESTDIR$(prefix)/ \ --component-group CG.virt-viewer --var var.DESTDIR \ --directory-ref=INSTALLDIR > virt-viewer-files.wxs && \ # build the MSI MANUFACTURER="$(MANUFACTURER)" wixl -D SourceDir=$(prefix) \ -D DESTDIR=$$DESTDIR$(prefix) \ --arch $(WIXL_ARCH) \ -o $@ \ $< virt-viewer-files.wxs && \ # remove temporary files rm -rf $$DESTDIR virt-viewer-files.wxs
Notes
Many features supported by WiX are not implemented in wixl, such as the installer UI support