When making your custom scripts or software available to someone else, it’s a good idea to make that content as easy to extract and install as possible. You could just create a compressed archive, but then the end user has to manually extract the archive and decide where to place the files. Another option is creating packages (
.rpm, etc) for the user to install, but then you’re more locked into a specific distribution. A solution that I like to use is to create a self-extracting archive file with the
makeself.sh script. This type of archive can be treated as a shell script and will extract itself, running a scripted set of installation tasks when it’s executed. The reason this works is that the archive is essentially a binary payload with a script stub at the beginning. This stub handles the archive verification and extraction process and then runs any predefined commands via a script specified at the time the archive is created. This model offers you a lot of flexibility, and can be used not only for installing scripts and software but also for things like documentation.
makeself.sh script is itself packaged as a self-extracting archive when you download it. You can extract the script and its support files by running the
makeself.run installer with a Bourne compatible shell (Listing 1).
$ sh makeself.run Creating directory makeself-2.1.5 Verifying archive integrity... All good. Uncompressing Makeself 2.1.5........ Makeself has extracted itself. $ ls makeself* makeself.run makeself-2.1.5: COPYING makeself.1 makeself-header.sh makeself.lsm makeself.sh README TODO
You can see from the output that I’m working with version 2.1.5 of
makeself.sh for this post. To make things easier, you can install
makeself.sh in your
~/bin directory, and then make sure
$HOME/bin is in your
PATH environment variable. You need to ensure that
makeself-header.sh are in the directory together unless you’re going to specify the location of
makeself-header.sh with the
--header option (Listing 3).
Listing 2 shows the usage syntax for
makeself.sh [OPTIONS] archive_dir file_name label startup_script [SCRIPT_ARGS]
OPTIONS, you need to supply the path and name of the directory that you want to include in the archive. The next argument is the file name of the self-extracting archive that will be created. You can choose any name you want, but for consistency and clarity it’s recommended that the file have a
.sh file name extension. Next, you can specify a label that will act as a short description of the archive and will be displayed during extraction. The final argument to
makeself.sh is the name of the script that you want to have run after extraction is complete. In turn, this script can have arguments passed to it that are represented by
[SCRIPT_ARGS] in Listing 2. It’s important not to get the arguments to the startup script confused with the arguments to
Listing 3 shows some of the options for use with
makeself.sh. You can find a comprehensive list on the
makeself.sh webpage, but in my own experience I’m usually only concerned with the options listed here.
--gzip : Use gzip for compression (default setting) --bzip2 : Use bzip2 for better compression. Use the '.bz2.run' file name extension to avoid confusion on the compression type. --header : By default it's assumed that the "makeself-header.sh" header script is stored in the same location as makeself.sh. This option can be used to specify a different location if it's stored somewhere else. --nocomp : Do not use any compression, which results in an uncompressed TAR file. --nomd5 : Disable the creation of an MD5 checksum for the archive which speeds up the extraction process if you don't need integrity checking. --nocrc : Same as --nomd5 but disables the CRC checksum instead.
In addition to the options passed to
makeself.sh when creating the archive, there are options that you can pass to the archive itself to influence what happens during and after the extraction process. Listing 4 shows some of these options, but again please have a look at the
makeself.sh webpage for a full list.
--keep : Do not automatically delete any files that were extracted to a temporary directory. --target DIR : Set the directory (DIR) to extract the archive to. --info : Print general information about the archive without extracting it. --list : List the files in the archive. --check : Check the archive for integrity. --noexec : Do not run the embedded script after extraction.
Let’s go through a practical example using some of the information above. If you had a directory named
myprogram within your home directory and you wanted to package it, you could create the archive with the command line at the top of Listing 5.
$ makeself.sh --bzip2 myprogram/ myprogram.bz2.run "The Installer For myprogram" ./post_extract.sh Header is 402 lines long About to compress 20 KB of data... Adding files to archive named "myprogram.bz2.run"... ./ ./myprogram.c ./post_extract.sh ./myprogram CRC: 955035546 MD5: 7b74c31f31589ee236dea535cbc11fe4 Self-extractible archive "myprogram.bz2.run" successfully created.
Notice that I used bzip2 compression via the
--bzip2 option rather than using the default of gzip. I couple this with setting the file name extension to
.bz2.run so that the end user will have a way of knowing that I used bzip2 compression. After the compression option, I pass an argument requesting that the
myprogram directory, which contains a simple C program also called
myprogram, be added to the archive. After the file name specification (with the
.bz2.run extension), we come to the description label for the archive. This can be a string of your choosing and will be displayed with the output from the extraction process. The last argument is the “startup script” that will be run when the archive is extracted. Listing 6 shows the contents of my simple startup script (
post_extract.sh) that installs the
myprogram binary in the user’s
bin directory, but only if they have one.
#!/bin/sh #Install to ~/bin if it exists if [ -d $HOME/bin ] then cp myprogram $HOME/bin/ fi
Notice that when specifying the startup script, I used the path of
./ which points to the current directory. This is a reference to the directory after the extraction, not the directory where the script resides when you’re creating the archive. Your startup script should be inside the directory that you’re adding to the archive. One other thing to note about the startup script is that you will need to set its execute bit before creating the archive. Otherwise you’ll get a
Permission denied error when the makeself-header script stub tries to execute the script.
Now we transition to the end user viewpoint, where the self-extracting archive has been downloaded and we’re getting ready to run it. You can set the execute bit of the archive and run it directly, or execute it with a Bourne compatible shell the way the
makeself.run installer was:
sh makeself.run . Before we extract the archive though, lets verify its integrity and have a look the contents (Figure 7).
$ sh myprogram.bz2.run --check Verifying archive integrity... MD5 checksums are OK. All good. $ $ sh myprogram.bz2.run --list Target directory: myprogram drwxr-xr-x jwright/jwright 0 2011-12-20 13:49 ./ -rw-r--r-- jwright/jwright 66 2011-12-20 11:45 ./myprogram.c -rw-r--r-- jwright/jwright 99 2011-12-20 11:49 ./post_extract.sh -rwxr-xr-x jwright/jwright 7135 2011-12-20 11:45 ./myprogram
We can see from the first command that the archive is intact and that there are no errors. The second command shows us that the archive contains 3 files. The first is the source file
myprogram.c which I left in the archive directory so that I could have the option of giving the user the source code. The next file is the startup script that will be run after extraction. The last file of course is the binary that our end user is wanting to install. Lets go ahead and install
myprogram by using the execute bit on the archive (Listing 8).
$ chmod u+x myprogram.bz2.run $ ./myprogram.bz2.run Verifying archive integrity... All good. Uncompressing The Installer For myprogram....
Now to test that the installation worked, we can try to run myprogram (Figure 9).
$ myprogram Hello world!
I can see that the program is present and did exactly what I expected it to do. Keep in mind that if
~/bin is not in your
PATH variable you’ll have to supply the full path to the
This has been a quick overview of what
makeself.sh can do. I’ve found it to be a very useful script that is also very dependable and easy to use. Through the use of the startup script, along with the full complement of options,
makeself.sh offers you a lot of flexibility when creating installers. You can create this type of self-extracting archive manually, but
makeself.sh makes it much easier and adds great features like checksum validation.
Please feel free to leave any comments or questions below, and have a look at innovationsts.com for other projects, tips, how-tos, and service offerings available from Innovations Technology Solutions. Thanks for reading.