What are the prerequisite subjects related to program installers? - operating-system

I never needed to add an installer to my programs but I always wondered about Microsoft Installer (.msi or .exe installers). What tasks do they do?
They make the life easier for the user, but that's not all to it. I know they also deal with the Operating System in several aspects.
But before learning about installers themselves. I feel there's a gap on my knowledge on some prerequisite subjects related to this.
So, which subjects would they be? And where can I learn them? (Books, articles, videos, courses, ...)
And to be clear I'm not asking about how to create an installer (I can do it with Visual Studio or tools like Install Shield). But I'm more concerned about the prerequisite subjects I need to learn to proper understand and handle installers. Specially in what areas do they deal with the Operating System?

Installers are nothing special. They give this impression because they do a bunch of weird things that don't seem accessible to other apps. The .msi and .exe installers will self extract (take a portion of the file itself and copy it to another file) or they will download other files from a server. The .exe and .msi files are thus normal executables that the OS recognizes due to their file extension as files that it should execute.
Each file extension has a default app to open them. When you open a file, its default app is started and the path to that file is passed as a string to the main function of the app. That way, the app can parse the file and show the content of it to you (similarly to compiling a program).
Other things like creating desktop icons are available with some dlls native to Windows and some other libraries that call in those dlls for higher level languages like C#. Quite simply, you create an average window like any other, you extract the app being installed from the same file to Program Files and you're good minus some other minor details. The apps available are really just to make your life easier.

Related

Where GTK finds icon names to use with gtk_image_new_from_icon_name()?

GTK can construct images by name of the "icon from current icon theme". For example:
#!/usr/bin/env python
import gtk; wnd=gtk.Window(); img=gtk.Image();
img.set_from_icon_name( "go-jump", gtk.ICON_SIZE_BUTTON );
wnd.add( img ); img.show(); wnd.show(); gtk.main()
This will display a window with a pretty arrow inside it. But - only on ubuntu. On Windows or OSX it will display window with a "no image" icon inside :(. So my questions is - where GTK keeps icon names like "go-jump"? Is it some list or specification available like for stock icons? Maybe it's some GTK API i can use to list such icons?
The names are in the Icon Naming Specification. If this doesn't work on Windows or OSX, then report it as a bug - GTK needs at least one icon theme installed in order to work properly.
Better late than never !
Here are two little Python scripts showing all existing icons sorted by their name:
http://dl.0xdeadc0de.fr/misc/gtkiconview_freedesktop.py for those in the Icon Naming Specification.
http://dl.0xdeadc0de.fr/misc/gtkiconview_local.py for those included in packages such as 'gnome-icon-theme-symbolic'.
Developing on Debian but wanting cross-platform support, I've recently installed gtkmm and co on both Windows and OS X, via MSYS2 and Homebrew respectively. As an aside, gtkmm, MSYS2, and Homebrew are excellent projects and well worth a look (I have no affiliation blah blah).
In that time, I think I've gained a decent understanding of why this happens and how to 'fix' it.
Why
This is not a bug in GTK+, as the accepted answer suggests. It's a fact of life when using a library tailored to Linux on another platform, via an environment that creates a Linux-like picture.
On Linux, you have a single environment with a standardised filesystem - via the FHS and FreeDesktop specs - with icons always in /usr/share/icons.
In contrast, on other platforms, you install Linux-like environments for compilation and sometimes runtime, each with its own virtual filesystem - which is difficult to track by other programs, without doing dangerous things to the end-user's PATH, especially if you're trying multiple such environments... You get the idea. The end result is that your program, by default, doesn't necessary have any awareness of where your environment's virtual root resides.
How
The solution, I've found, is to copy all required resources to the same folder as your executable - i.e. the directory you'll eventually redistribute, or if you're writing OSS, do this in your makefile or such. This is because, as far as I can tell, a program - looking for GTK+ resources, DLLs, etc. - checks its own directory before the (probably not helpful) PATH. A little opposite to how shells do things, but handy!
So, you copy the relevant icon themes, as installed by your package manager, into a new folder within said directory. At a minimum, do this for the standard theme: copy it to $YOURDIR/share/icons/Adwaita. Then restart your program. If you're anything like me, now all the icons work perfectly.
The same applies for pretty much any other resource that you need to redistribute with your application.
Notably, I'd suggest doing the same thing with all DLLs needed by your binary. These may or may not work for you out-of-the-box and depending on how you invoke your binary - but you really can't afford to speculate about whether your end-users already have the right set of DLLs installed somewhere in their PATH, of the right version compiled by the right compiler.

The Science of Installation

I have minimal exposure to RPM, Windows installer mechanics, and WIX. That said, I'm interested in making a cross-platform installer tool (Linux, Windows) that supports upgrading and downgrading (versiona and patches) of my own product. I don't believe this is a topic to be approached lightly; I would like to learn the science of the art (or the art of the science). If I succeed, and build a minimally successful installer tool, it would have these features:
does not depend on a platform-specific tool (such as Windows Installer).
reads XML or a declarative syntax to fulfill installation requirements.
attempts to minimize steps to upgrade or downgrade one of my products (rather than requiring a complete uninstall and re-install).
does not require knowledge of interim product versions, in order to jump versions (i.e. can upgrade one of my products from version 1 to version 3, without passing through version 2).
I'm convinced that "the key" to achieving this goal is by seeing versions as a "point A to point B" problem, which implies that A and B are described by two XML "version" documents that hold info about all the parts and actions (files, or platform specifics such as registry entries). My installer tool would "join" or compare the two documents and determine a minimal set of changes to transform A into B. To some extent, I believe this is precisely what Windows Installer does.
Of course there are further complexities, but that is the point of this post. Where is "the bible" of information on this topic? Remember, I want to make my own installer - not use a platform-specific one. For those who care, my products are usually written in C++ or C#.
Or perhaps I should study something like Steam which is cross-platform and has "automated game updates" as part of its capabilities. In my case, the problem of online deployment is already handled. It is just the final installation step I'm examining. Does Steam use native installers (such as an MSI)? If yes, then that is not what I'm looking for.
In short, what path should I pursue to become somewhat competent on the science of this topic?
I'm not an expert and others can give you better answers but...
Don't declaratively list steps required to install your product - You'll end up making assumptions which will eventually prove wrong. Instead, you should be looking at defining the final state of the installation and let the installer worry about how to make that happen.
Another consideration is that being downgradable may involve huge complications depending on your product - Would it have to down-grade database schemas / file formats / ??? In short, every version of your app will need to be both fully forwards- and backwards-compatible (or at least fail gracefully). Also consider the scenario where V1 of your app stores settings in a file. V2 comes along and adds more settings. You downgrade to V1 - What should it do when changing settings? preserve the V2 settings? dump them? Do some of the V2 settings change the impact/meaning of the V1 settings? Are these decisions to be made by your app or your installer?
Anyway, all that aside, I'd say you need at the least:
A central server/farm with complete files for every version of your App and some API/Web Service which allows the installer to retrieve files/filesets/??? as appropriate (You may be able to tie this into a source control system like svn)
Some way of specifying the desired post-install state of the system in an environment-agnostic way (Think install paths - /usr/??? - should the map to C:\Users\??? or C:\Program Files on windows? Also don't forget it might be a 64-bit machine so it could be C:\Program Files (x86).
A very clever installer written for multiple platforms with as much code re-use as possible (Java, Mono, ???)
The installer should do (simply):
Determine the desired version of the product.
Download/read the appropriate manifest.
Compare the desired situation with the current situation (NB: What is currently on the local system, NOT what should be on the system according to the current version's manifest)
Generate a list of steps to reconcile the two, taking into account any dependencies (can't set file permissions before you copy the file). You can make use of checksums/hashing/similar to compare existing files with desired files - thus only downloading the files actually required.
Possibly take complete backups
Download/unpack required files.
Download/unpack 3rd party dependencies - Later .Net Framework Version/Similar
Perform install steps in atomic a manner as possible (at the very least keeping a record of steps taken so they can be undone)
Potentially apply any version-jump specific changes (up/down-grade db, config files, etc.)
verify installation as much as possible (checksums again)
None of this addresses the question of what to do when the installer itself needs upgrading.
A technique I've used on Windows is that the installer executable itself is little more than a wrapper with some interfaces which loads the actual installer dynamically at runtime - thus I can move files about/unload/reload assemblies, etc... from within a fixed process that almost never changes.
As I said above, I am definitely not an expert, just a novice who's done some of this myself. I sure you can get more complete answers from others but I hope this helped a little

What's the prime advantage to having an MSI installation package?

I thought this would be somewhere on the Web, but I couldn't Google it:
Given the complexity involved in creating an MSI package (compared to NSIS, InnoSetup, etc.), what would be a compelling reason to go through all the mess (using MSVS's crappy setup project wizard, learn a whole new langauge/ecosystem just to make the installer (WiX), or pay heavy license fees (InstallShield)) for the sake of making an MSI installer?
Would be nice to have real world opinions or experience (even to prove that MSI is really worthless) other than the obvious MSDN page, for instance :)
I don't think there is one prime advantage for all situations. Here are some things I like about it, vs other kinds of installers:
Install logic and code is contained in a database, which is in an accessible format.
I like this a lot when I'm debugging. Rather than rebuilding your installer, you can directly edit the database with a tool like Orca (free database editing download from MS), then run the install again to test your changes. Update your custom code, temporarily condition something out, change the order of operations, whatever you need to do.
Patching. The Installer service and its corresponding tools know how to create patches containing deltas of updated files, rather than complete files. It allows maintenance sizes to remain reasonable.
Administrative Images. The installer can create an administrative image. If you've generated patches, you can apply the patches to the administrative image, and new installations can then be run from the administrative image rather than the original installer. Like slipstreaming patches in OS images. If you're pushing your app out to a large number of machines, it's pretty cool to not need to push a bunch of patches out post-install.
Other interesting features include transforms, run from source, detect and repair, component sharing, and so on.
Take a look at this:
https://serverfault.com/questions/11670/advantages-of-using-msi-files
MSI (or ClickOnce) was required to obtain the Windows Vista Logo Program (Microsoft official certification). I believe this requirement was removed with Windows 7, but it's still easier to get certification with MSI (see here).
You don't need to buy any expensive 3rd party installer package though. If you're going for MSI, I suggest you use WIX and learn it. Once you're familiar with it, it works pretty well.
Another good read is:
Windows Installer: Benefits and Implementation for System Administrators
I've been a full time setup developer for 14 years. My first 7 years were InstallScript Setup.exe style projects and my last 7 years have been MSI based. At first I resisted MSI and then after 6 months of using it I became a true believer in how much better it is.
I'm pretty certain that there are enterprises that require MSI formats to remote bulk install an application on thousands of machines. However I don't deal with such organizations so don't know for certain.

How to distribute native perl scripts without custom module overhead?

How can someone distribute native (non-"compiled/perl2exe/...") Perl scripts without forcing users to be aware of the custom (non-CPAN) modules that the scripts needs in order to run?
The problem is users will inevitably copy the script somewhere else on the system and take the script out of its native environment and then it can no longer find the modules it needs to run.
I've sometimes settled with just copying the module into the actual script, but I'd prefer a cleaner solution.
Update: I better clarify. I distribute a bunch of scripts which happen to use similar modules in the backend. The users understand how to run Perl scripts, but rather than relying on telling them "no don't move the script" I'd prefer to simply allow them to move the files. The path of least resistence.
The right way is to tell them "Don't do that!" I would hope that they wouldn't expect to move an exe file and have the program continue to work. This is no different.
That said, there are a couple of alternatives. One is replacing the script with a wrapper (e.g. pl2bat) that knows the full path to the real script. Another is to use PAR, but that would require PAR and/or parl (from PAR::Packer) to be installed.
If a script that your prepared for a client needs "custom" modules, simply pack your modules as if you were trying to upload them to cpan. Then give the package to the client and he can use the cpan utility to install the script and the modules.
Distribute an installer along with the script. The installer will need to be run with root privileges and it will put the custom modules into the standard system location (/usr/local/lib/perl5/site_perl or whatever).
I've not tried this, but Module::Install looks helpful in this regard. It's described as a:
Standalone, extensible Perl module installer
As a variant of the "put your modules all in one place and make your applications aware of it" that will even work across multiple computers and networks, maybe you should check out PAR::Repository and respectively PAR::Repository::Client. You'd just provide a single binary client executable that connects to the repository (via file system or https) and executes any of the arbitrary number of programs (using an arbitrary set of modules) provided by the repository that the user asks for.
If there are many users, this also has a benefit for maintenance: Simply update the software provided by the repository and the users will start using the updated code for their system when they next start the programs.
It would be really nice if you could just use a NeXTSTEP style application bundle. Since you probably aren't developing for a platform that uses bundles, you'll have to make do.
Put all support files in a known location, and point your executable at those files for access to settings and libraries. The easiest way to do this is with a simple installer.
For example, with an app called foo, put all your required files in /opt/xlyd_apps/foo, libraries in /opt/xlyd_apps/foo/lib, configuration in/opt/xlyd_apps/foo/etc, and so on. Put the executable in /opt/xlyd_apps/foo/bin.
The important thing is to make sure the executable knows to look in /opt/xlyd_apps/foo for all its goodies, so if the customer/client move the foo script to a new location the install still works.
So, while you can't make the whole thing self contained and relocatable, you have made the actual calling script relocatable.
I've actually come up with my own solution, and I'm kind of curious what kind of reception it will have.
I've written a script that reads a perl script and looks for "use/require" statements. Upon finding them it checks if the module is part of the standard library (looks at module path for /perl5/\d+.\d+[\d.]+/) and then rewrites the use/require line in two different ways depending on usage.
If require is found:
{
... inline the entire module here...
}
If use is found:
BEGIN {
... inline the entire module here...
}
If use has imports, immediately follow above with:
BEGIN { import Module ...imports seen... }
I understand this doesn't work with modules that use XS, but I was fine with this. Mostly I need to support only pure perl modules.

Solution deployment, CM, InstallShield

People,
We have 4 or 5 utilities that work in conjunction with our application. These utilities are either .bat files, or VB apps, PowerBuilder, etc. I am trying to manage these utils in source control, and am trying to figure out a better way to assign versions to them. Right now, the developers use the version control's meta-data -- specifically label -- to store the version number of the tool.
My goal is to have individual InstallShield packages for each utility, and an easy means to manage and assign version numbers to these packages.
Would you recommend a separate .ini file with the info, or store the info in InstallShield .ism file itself, or just use the meta-data info from version control tool?
UPDATE:
I like the idea Orion. I have one concern though. The script that increments the version number... it can not be intelligent enough to increment Major number etc. right. e.g. if one of the utils has version 1.2.3 and we are at a point where the new version is 2.0.0. The script may not be able to handle this.
I think this has to do a lot with our branching techniques -- we don't have any. The folks thought since the utils are so small, the source may not need branches.
PowerBuilder in particular has a nice trick you can do to incorporate the build number from an ini file into the compiled application.
Details here: http://www.pbdr.com/pbtips/ex/autorev.htm
We have ini file inside source control that stores the build number and its value is used in our build scripts to determine what label to apply to the source tree after a successful build. Works very nicely for our needs. When we branch, we do have to manually kick the file to increment the proper number though.
I managed our build system at my last job, which seemed to have some parallels to what you're asking.
There were ~30 C++ projects which needed compiling, and various .NET/Java things, and the odd perl script.
This was all built on our build machine using NAnt - If I were doing it today I'd use rake, but the idea is the same.
We basically had an auto-incrementing build number which was stored in a version.txt file in the root of the repository.
Each time we did a build (automatically done each night, or also on-demand if neccessary) the script would increment this number and check the file back into source control.
All the other apps referenced this file for their version number, or for things which didn't support working like this, the script would set environment variables or perform other workarounds
I'm pretty sure that our installshield programs referenced an environment variable for their version number, but we deprecated them in favour of wix as installshield really did suck
in the case of visual studio, grep/replace the number within the .csproj files, and check them back in
Hope this gives you some ideas
Using the meta data from your version control system should keep things simpler. It's how your developers already use the system. There is no additional file to maintain. My personal experience has taught me to version the satellite applications with the same as version as the main app. K.I.S.S