Writing A SlackBuild Script
Introduction
Originally written by Florian Mueller jjdm@jjdm.org Substantial cleanup and enhancement by Robby Workman (rworkman) Those that really know what they are doing are unlikely to need to read this document; as a noob I've read through and successfully created a slackbuild and package.Some of the text needs updating,which i will have a go at in the knowledge that it should be able to be reversed via the history data. I will update from the perspective that a noob is reading and they may need some spoon feeding!
If you use slackware as your main operating system, you have probably wanted to install quite a few applications which are not available in the official slackware.com or even third-party repositories like pkgs.org, or perhaps you just don't like using third-party packages. In this situation, you have several options on how to install the application:
* ./configure && make && make install * use checkinstall * use installwatch * compile and use makepkg by hand * write a SlackBuild script
I will go through the last option: writing SlackBuild Scripts (which combines the best qualities of all the other aforementioned methods). With a SlackBuild script, you have the build process automated, which will allow you to easily do later upgrades or patches to the package. SlackBuild scripts are also the method by which Patrick Volkerding builds all of the official packages for Slackware. If you look at the various scripts from different sources, you will notice that there is generally an application-independent portion of a script and an application-specific portion of the script.
I cannot teach you how to build the "perfect" package, as reaching that goal requires fairly in-depth knowledge of the Slackware operating system. You must consider the interactions of your proposed package with all of the other packages within the distribution; they must be integrated seamlessly. What I can teach you is how to build a package that works and which stays true to the "Slackware Way."
"But it takes so much time!"
It will take approximately thirty minutes to go through this tutorial and about fifteen minutes to create each package (actual compile process not included), but the time you save in the future (you want to create a newer version of the package) makes the initial time expenditure worth it.
The Slackware package structure
See Packages#Slackware Package Layout
Setting up your build environment
See Build_Environment for examples of how various users do this.
Getting Started
Hopefully, everything is now clear about Slackware package structure, and you have set up a clean build environment, so we'll begin the process of building a package with a SlackBuild script.
For this example, we'll create a package of latex2html - I made my homepage with that tool.
First, you have to create a directory named <build_environment>/latex2html/. Get the most recent source code release of latex2html place it in this directory. Note that use of wget below to obtain the most recent source code is optional - you can just as well use your favorite web browser to download it, and then move it into the correct directory.
$ cd <build_environment> $ mkdir latex2html $ cd latex2html $ wget -O latex2html-2019.2.tar.gz https://github.com/latex2html/latex2html/archive/v2019.2.tar.gz #6 th June 2019 release
Next, we'll create some other needed files with touch. If you're not familiar with touch, see:
man touch
Note that the *.SlackBuild file will always contain the name of the application for which it's written; for example, gaim would have gaim.SlackBuild.
$ touch latex2html.SlackBuild $ touch slack-desc
Extract the source code of the application, because we'll need to look at the configure script later on to determine what options we need to pass to it.
$ tar xvzf latex2html-2019.2.tar.gz || exit 1
x -extract v -verbose f -file z -basically ungzip
Writing the slack-desc file
See this Slack-desc page on SlackWiki.org for instructions on how to write a proper slack-desc file.
Writing the SlackBuild script
This is the section which takes the most time, and I'll go through it with you step by step. When you build more packages, you'll probably be able to just copy an existing SlackBuild script and customize it. First, you need to understand that you can write your SlackBuild script in any manner you choose so long as it creates a working package; the method described here is more or less the way Pat Volkerding [[1]] does it, but even Pat has several different styles for writing the official SlackBuild scripts. Therefore, if you see something you would do a different way, feel free to do it that way - it's okay.
Initial Setup
Open the file latex2html.SlackBuild with your favourite editor. What follows below is a piece by piece walk-through of a working SlackBuild script. You may certainly paste the exact contents of those pieces, but in the author's opinion, you have a better chance of understanding it if you write everything yourself.
First, you'll need to set your shell interpreter. This should be /bin/sh, as *every* Slackware system is guaranteed to have this shell installed, and you want maximum portability. For this same reason, be careful not to use any extensions and/or syntax that is customized for your particular shell (bash, zsh, or whatever), as it won't be interpreted correctly. The '-e' flag tells the shell to exit on any error; this helps with both debugging your script as well as ensuring your script does not proceed in an unknown state.
#!/bin/sh -e
You might want to include a license of some sort with your SlackBuild script (preferably a GPL or BSD-style license.For the sake of brevity an example has been put on discussion page ), but at a minimum, you'll want something like this:
#<your name> revision date yyyy/mm/dd
With the next few lines, we set some variables that will be used throughout the script. First is the "CWD" variable; in our case, CWD will be <build_environment>/latex2html/. We also test if the TMP variable is set, and if not, we set it to /tmp.
#Set initial variables: CWD=$(pwd) if [ "$TMP" = "" ]; then TMP=/tmp fi
Some people like to build in a subdirectory of /tmp (such as /tmp/build), but that's up to you.
# The version which appears in the application's filename VERSION=${VERSION:-2019-2} # If the version conflicts with the Slackware package standard # The dash character ("-") is not allowed in the VERSION string # You can set the PKG_VERSION to something else than VERSION PKG_VERSION=2002.2.1 # the version which appears in the package name.
# Automatically determine the architecture we're building on: if [ -z "$ARCH" ]; then case "$( uname -m )" in i?86) ARCH=i486 ;; arm*) ARCH=arm ;; # Unless $ARCH is already set, use uname -m for all other archs: *) ARCH=$( uname -m ) ;; esac fi
# First digit is the build number, which specifies how many times it has been built. # Second string is the short form of the authors name, typical three initials:w BUILD=${BUILD:-1_rlw} # The application's name APP=latex2html # The installation directory of the package (where its actual directory # structure will be created) PKG=$TMP/package-$APP
Set SLKCFLAGS (which will be used for both CFLAGS and CXXFLAGS). If you are building on a system with an earlier version of gcc than 3.4.x, then you'll need to use "-mcpu" instead of "-mtune" below.
if [ "$ARCH" = "i486" ]; then SLKCFLAGS="-O2 -march=i486 -mtune=i686" LIBDIRSUFFIX="" elif [ "$ARCH" = "i686" ]; then SLKCFLAGS="-O2 -march=i686 -mtune=i686" LIBDIRSUFFIX="" elif [ "$ARCH" = "x86_64" ]; then SLKCFLAGS="-O2 -fPIC" LIBDIRSUFFIX="64" else SLKCFLAGS="-O2" LIBDIRSUFFIX="" fi
The section just finished sets up a few application-specific variables. When you want to create a package of some other application, you can usually just change the variables, and most of the further steps will work automatically.
Extract Sources
# Delete the leftover directories if they exist (due to a previous build) # and (re)create the packaging directory rm -rf $PKG mkdir -p $TMP $PKG rm -rf $TMP/$APP-$VERSION # Change to the TMP directory cd $TMP || exit 1 # Extract the application source in TMP # Note: if your application comes as a tar.bz2, you need tar -jxvf tar -zxvf $CWD/$APP-$VERSION.tar.gz || exit 1 # Change to the application source directory cd $APP-$VERSION || exit 1 # Change ownership and permissions if necessary # This may not be needed in some source tarballs, but it never hurts chown -R root:root . chmod -R u+w,go+r-w,a-s .
Configure and Compile Sources
# Set configure options # If your app is written in C++, you'll also need to add a line for CXXFLAGS CFLAGS="$SLKCFLAGS" \ ./configure \ --prefix=/usr \ --sysconfdir=/etc \ --localstatedir=/var \ --with-perl=/usr/bin/perl \ --enable-eps \ --enable-gif \ --enable-png \ --build=$ARCH-slackware-linux \ --host=$ARCH-slackware-linux # compile the source, but exit if anything goes wrong make || exit # Install everything into the package directory, but exit if anything goes wrong make install DESTDIR=$PKG || exit
There are three configure options I always set:
- --prefix=/usr
- --sysconfdir=/etc
- --localstatedir=/var
This makes configuration files go to /etc, state files (such as log files) go to /var, and the rest goes to /usr. That's the usual Slackware way, but it's your system, so you can certainly install everything in /usr/local or some other location. See the Unix Filesystem Hierarchy Standard [[2]] for more information on "correct" locations of various filetypes.
You notice that there were several other options passed to the configure script, and for each application you compile, you have to figure those out for yourself - that's why you were told to extract the sources earlier in this process. You simply cd into the source directory and run:
./configure --help
This will produce a page or two (sometimes more, though) of information about various options that are specific to the application. Read through this information and figure out what you need (I like to pipe that command through lpr to get a printed copy, but you can certainly use some sort of pager as well:
./configure --help | lpr ./configure --help | less
The DESTDIR variable is very important in this script because it specifies the directory in which the files should be installed. This should always be our package directory ($PKG). Unfortunately, some applications' Makefiles will not support the DESTDIR variable, so you can't use it for those apps. A simple line like this:
grep DESTDIR Makefile*
while inside the source directory should tell you whether it supports DESTDIR or not. If you get some lines of output with $DESTDIR in them, you're in good shape. If the command returns no output, then the Makefile does not support the DESTDIR variable.
Here's a piece of advice: ALWAYS go through the ./configure && make && make install DESTDIR=/somedir process manually and as a NORMAL USER account BEFORE you run your SlackBuild script. There are quite a few applications out there which try to do "funny stuff" during the installation phase.
For example, apcupsd will attempt to patch your /etc/rc.d/rc.6 init script Yes, it's possible to avoid this with a configure option, but it's not obvious that you would need to do so until you look at all of the Makefiles for apcupsd (or watch the install process)
Anyway, if you go through the process as a normal user, you will get "Permission Denied" errors and such if the install process tries to write anywhere it's not allowed to do so.
Install Documentation
# Create a directory for documentation mkdir -p $PKG/usr/doc/$APP-$VERSION # Copy documentation to the docs directory and fix permissions cp -a BUGS Changes FAQ INSTALL LICENSE MANIFEST README TODO docs/ $PKG/usr/doc/$APP-$VERSION find $PKG/usr/doc/$APP-$VERSION -type f -exec chmod 644 {} \;
I (rworkman) also like to place a copy of my SlackBuild script in this directory
cat $CWD/$APP.SlackBuild > $PKG/usr/doc/$APP-$VERSION/$APP.SlackBuild
Make sure you look inside the actual source archive of the application, because some applications won't have all of the documentation files specified above, and some applications will have additional files. In other words, don't just copy/paste what you see above into your SlackBuild script - you *must* customize this section for each individual application.
Final Touches
# Create the ./install directory and copy the slack-desc into it mkdir -p $PKG/install cat $CWD/slack-desc > $PKG/install/slack-desc
NOTE: In some cases, you will have some sort of command or setup that needs to run after the package contents are installed - for this, you would add a file to $CWD called "doinst.sh" which contains the needed commands, and then compress that file with gzip. The SlackBuild script will zcat (which means to gunzip and cat its contents) that file and write the output to a doinst.sh file in the $PKG/install directory.
# Add doinst.sh to package (if it exists) if [ -e $CWD/doinst.sh.gz ]; then zcat $CWD/doinst.sh.gz > $PKG/install/doinst.sh fi
Let's conserve space if we can; strip libraries and binaries and compress man pages with gzip Note that you might be able to use "make install-strip" instead of "make install" above instead to accomplish the same purpose
# Strip some libraries and binaries ( cd $PKG find . | xargs file | grep "executable" | grep ELF | cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null find . | xargs file | grep "shared object" | grep ELF | cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null ) # Compress man pages if they exist if [ -d $PKG/usr/man ]; then ( cd $PKG/usr/man find . -type f -exec gzip -9 {} \; for i in $(find . -type l) ; do ln -s $(readlink $i).gz $i.gz ; rm $i ; done ) fi # Compress info pages if they exist (and remove the dir file) if [ -d $PKG/usr/info ]; then gzip -9 $PKG/usr/info/*.info rm -f $PKG/usr/info/dir fi
Build the Package
# Build the package cd $PKG /sbin/makepkg -l y -c n $TMP/$APP-$PKG_VERSION-$ARCH-$BUILD.tgz
Other Concerns
DESTDIR Option Not Available
As mentioned above, there are quite a few applications whose Makefiles do not support the DESTDIR option for make install. On some applications the DESTDIR Makefile variable has another name. For example, some Qt applications use the variable INSTALL_ROOT for the same purpose. If you can understand Makefiles, it is probably worth your time to take a look at its contents and try to find out which actions are performed in the install rule. Sometimes there will be no DESTDIR equivalent at all. The best thing you can do in this situation is write a patch for the Makefile.in or equivalent, and submit it to the developer(s) for inclusion in the source, but I realize that everyone doesn't have the ability to do that. The second best thing you can do it write to the developer(s) and ask them to include that functionality in future releases. In the meantime, here are some thoughts on the subject...
Example 1:
Configure the build with:
./configure --prefix=$PKG/usr
along with your other configure options. This will install *all* of the package contents in that directory. If the package creates $PKG/usr/etc and $PKG/usr/var directories (or any other directories that should be elsewhere), you can probably just move them to their correct location within the package directory tree and everything will be fine. You might also try this along with your other configure options.
./configure --prefix=$PKG/usr \ --sysconfdir=$PKG/etc \ --localstatedir=$PKG/var
There are some applications, however, which "hard-code" configuration files based on configure/Makefile parameters. In those cases, you'll have to figure out a way to patch the config file prior to packaging it, or in worst-case scenario, include instructions for the end user on how to make the necessary changes.
Example 2:
This example makes use of the ability to override any Makefile variable, which is called a macro in the Makefile terminology, on the command line and not have to worry about patching the Makefile to include a DESTDIR macro in the Makefile. This approach makes it a bit easier for those not familiar with Makefiles.
If the Makefile does not honor DESTDIR for the 'make install' command, you can change the prefix macro, instead:
make prefix=$PKG/usr install
This will override the $(prefix) variable inside the Makefile and install to the location you supplied on the command line. Therefore, you can configure with the standard ./configure --prefix=/usr (or ./configure --prefix=/usr/local) syntax, yet install to a different location as if you supplied a DESTDIR=$PKG/usr for the 'make install' command.
IMPORTANT NOTE: Macro names are case-sensitive (at least for GNU make). Some Makefiles may use a "PREFIX =" macro instead of the usual "prefix =", so the 'make install' command would look like this:
make PREFIX=$PKG/usr install
Therefore, it's necessary to look inside the Makefile to be sure which form was used for the prefix. For large, complex makefiles, the easiest way is to 'grep' the Makefile, like so:
grep -i '^prefix \?=' Makefile{,.in}
The -i option makes the search case-insensitive and the {,.in} part at the end will search "Makefile" or "Makefile.in" files, the second one being a template for the "configure" script. Grep's search term is a basic regular expression, so the escaped question mark after the space (\?) means there may or may not be a space in between when searching.
Once in a while, there may be a "PREFIX =" in a Makefile that is not defined which you are to edit and supply the location. Use the usual /usr (or /usr/local), in this case, and then use 'make PREFIX=$PKG/usr install' to install to the package's build location.
Patching the Sources
Sooner or later, there will be some reason to patch the source code prior to building a package, and you'll want to be able to do this automatically.
Obtaining the Patch
In most cases, the patch will be provided by the author of the source code, so we're not going to discuss patch *creation* here. Download the patch and place it in the same directory as the SlackBuild script, slack-desc file, and other related files (in $CWD from above).
$ wget http://someapplication.org/files/patches/bigsecuritypatch.diff
It's not necessary to do the next step, but because developers generally want to conserve space if possible, it's conventional to do this:
$ gzip -9 bigsecuritypatch.diff
This will result in a new file called bigsecuritypatch.diff.gz -- we'll use that in the SlackBuild script in just a moment.
Applying the Patch
You will now need to edit your <application>.SlackBuild script so that it applies the patch before it runs configure, make, and make install. To do this, you'll want something like this to run before the configure script, but after extracting the sources:
zcat $CWD/bigsecuritypatch.diff.gz | patch -p1 || exit
Depending on how the patch was created, you might use a different patchlevel on that line, as in:
zcat $CWD/bigsecuritypatch.diff.gz | patch -p0 || exit
It's a bit beyond the scope of this HOWTO, but essentially, the -p# specifies the number of trailing directories to skip when looking for the file to patch. You'll often need to skip the top-level directory, but not always (hence the -p0).
See Also
- SlackBuild_Scripts
- Different_Approach_To_Buildscripts
- Building_A_Package
- Slack-desc
- Checkinstall
- Compiling