jasonwryan.com

Miscellaneous ephemera…

Hacking PKGBUILDs

I posted a couple of weeks ago about Building Vim and how, using ABS and makepkg it is possible to customize packages in the repositories to suit your individual requirements, in that case with a specific feature set.

One of Arch’s real strengths is in the flexibility that makepkg and PKGBUILDs provide the community; the ability to adapt official packages—or unofficial ones in the AUR—as you see fit. As PKGBUILDs are just shell scripts, the entry level to start playing around with them is quite low1.

A fairly standard, and simple, example of the type of customization that I might make is with dmenu, the suckless dynamic menu, where the standard package in the Arch repositories is not patched for Xft support. There is a patch for this on the suckless wiki, so it is just a case of making the requisite changes in the PKGBUILD from ABS and building it.

As you can see from the diff below, there is not a lot involved in this exercize; essentially, adding libxft as a dependency, sourcing the patch from the suckless site (and including the hash for it), and then in the build function ensuring that the patch is applied and the Makefile updated with the new library:

--- PKGBUILD   2013-05-18 09:33:07.156328812 +1200
+++ PKGBUILD   2012-11-14 09:25:15.915335588 +1300
@@ -11,16 +6,22 @@
 pkgdesc="A generic menu for X"
 url="http://tools.suckless.org/dmenu/"
 arch=('i686' 'x86_64')
+groups=('modified')
 license=('MIT')
-depends=('sh' 'libxinerama')
-source=(http://dl.suckless.org/tools/$pkgname-$pkgver.tar.gz)
-md5sums=('9c46169ed703732ec52ed946c27d84b4')
+depends=('sh' 'libxinerama' 'libxft')
+source=(http://dl.suckless.org/tools/$pkgname-$pkgver.tar.gz
+http://tools.suckless.org/dmenu/patches/$pkgname-$pkgver-xft.diff)
+md5sums=('9c46169ed703732ec52ed946c27d84b4'
+         'd448ec9120718b0aedbdb338f4fa69ba')

 build(){
   cd $srcdir/$pkgname-$pkgver
+  patch -p1 < ../$pkgname-$pkgver-xft.diff
+  sed -i 's:-I/usr/local/include/freetype2:-I/usr/include/freetype2:' config.mk
+
   make \

Running makepkg -i will build and install dmenu with Xft support. This is the most straightforward approach. I also, primarily by way of experimentation and in an effort to try an understand how this actually works, have slightly more convoluted examples. msmtp, the SMTP client has a couple of makedepends in libgnome-keyring and texlive-core; the former I have zero use for and the latter is only installed on my desktop, so I have no wish to install it on my laptop just to be able to send emails…

In this case, I modified the PKGBUILD to completely remove the libgnome-keyring dependency and to only build the msmtp documentation in .pdf and .html if texlive-core was already installed on the machine. Unfortunately, I wasn’t able to test for the presence of texlive-core with the standard utilities like type or which, so—as it is installed on all my boxes—I went with expac (pacman -Q would also work):

--- PKGBUILD    2013-05-18 09:32:07.393095131 +1200
+++ PKGBUILD    2013-05-18 09:31:55.449986364 +1200
@@ -1,7 +1,8 @@
 arch=('i686' 'x86_64')
+groups=('modified')
 license=('GPL3')
 url="http://msmtp.sourceforge.net"
-makedepends=('texlive-core' 'gsasl' 'libgnome-keyring')
+makedepends=('gsasl')
 source=(http://download.sourceforge.net/sourceforge/msmtp/${pkgbase}-${pkgver}.tar.bz2)
 sha1sums=('c0edce1e1951968853f15209c8509699ff9e9ab5')

@@ -12,19 +13,24 @@

 build() {
   cd ${pkgbase}-${pkgver}
-  ./configure --prefix=/usr --sysconfdir=/etc --with-ssl=gnutls
+  ./configure --prefix=/usr --sysconfdir=/etc --with-ssl=gnutls --without-gnome-keyring
   make
-  make -C doc html pdf
+  if [[ -n $(expac -Q '%n' texlive-core) ]]; then
+      make -C doc html pdf
+  fi
 }

 package_msmtp() {
   pkgdesc="A mini smtp client"
-  depends=('gsasl' 'libgnome-keyring')
+  depends=('gsasl')
   install=msmtp.install

   cd ${pkgbase}-${pkgver}
   make DESTDIR="${pkgdir}" install
+
+  if [[ -n $(expac -Q '%n' texlive-core) ]]; then
   make DESTDIR="${pkgdir}" -C doc install-html install-pdf
+  fi

 # Installing example configs and scripts to /usr/share/doc/msmtp

It isn’t necessarily an attractive solution, but it works for me… On the subject of unattractive solutions, as of pacman 4.1, released last month, the packaging standards for VCS PKGBUILDs have been changed, principally around how sources and versioning is handled. For the couple of VCS packages I maintain in the AUR2, I have been experimenting with how to capture the pkgver in a way that conforms to the standards and provides people with a meaningful version number.

By default, the version number for these projects from their git repos is not that helpful:

git describe --always
4861046

After looking through the git logs, and playing around with awk to filter the results, I came up with this:

pkgver() {
  cd "$_gitname"
  printf '%s\n' "$(awk '/^ / {print $2}' <(git log --grep=version -1))_\
  $(git describe --always)"
}

This prints a more, for me anyway, intelligble package version: vimprobable2-git 1.2.1_c5936cc-1 that relates back to the last stable release and appends the current commit. I’m sure that this could be improved upon; suggestions are welcome.

The other change to note in all of these PKGBUILDs is the inclusion of the groups variable. By adding all of the modified packages from the official repositories to the—imaginatively titled—modified group, I can then add a line to /etc/pacman.conf that prevents those packages from being overwritten on upgrade3:

IgnoreGroup = modified

Issuing pacman -Syu, or running checkupdates from a cron job, will notify you that the packages have had a version bump and that they need to be rebuilt. The PKGBUILDs for all of these packages can be found in my bitbucket repo.

Notes

  1. As my experiments attest…
  2. Vimprobable2-git, Surfraw-git and ruby-build-git.
  3. All credit to ataraxia for this idea.

Creative Commons image on Flickr by Wells P. Wilson

AUR Helpers

Or, “Why you should uninstall Yaourt and embrace makepkg…”

The release of Pacman 4.1 saw the same flurry of posts on the boards, in IRC and the mailing lists about people being “unable” to upgrade or, worse, claiming that pacman was “broken” because their upgrade was failing due to unsatisfied dependencies, that pretty much every pacman upgrade ocassions. How is it possible that so many people can run an operating system designed for competent users without having even a basic understanding of how the package manager—one of the single most critical components of the distribution—works?

Even a cursory perusal of the resulting threads on the boards will quickly identify the common denominator in these cases:

resolving dependencies…
looking for inter-conflicts…
error: failed to prepare transaction (could not satisfy dependencies)
:: package-query: requires pacman<4.1

package-query is required by yaourt; so these upgrades have been stymied by a package that is in the (unsupported) AUR? There are a multitude of AUR helpers, but yaourt is most commonly used by people who are new to Arch1 for two reasons. First, it is one of the most “featureful” and secondly, and more to the point of my argument, it can be installed by simply adding an unsupported repo to pacman.conf; thereby effectively bypassing the need for the hapless user ever having to use or understand makepkg.

Consequently, over time, people who are habitually using yaourt -Syu --aur to update both the packages in the supported repositories and those they have installed from the AUR lose the conceptual distinction between the two. yaourt obscures this from them and—if they are completely reliant upon it, as these threads attest they are—they have abnegated responsibility for managing those unsupported packages and in doing so have found themselves incapable of understanding the bind they are in.

This sort of obscuring of fundamental operating principles in the pursuit of “convenience” is anathema to Arch and is precisely the reason I moved away from using yaourt (and indeed from using Ubuntu when I jumped from that sinking ship). Any convenience is purely illusory, in reality it just fosters learned helplessness.

I understand that the yaourt developer(s) was scratching their own itch, and this post is not about maligning the project; but there are significant unintended consequences of giving people a tool that abstracts such a fundamental element of the distribution away from the user, especially for a distribution where you are expected to have complete control and responsbility over your system.

To be clear, I don’t have a complaint with the concept of AUR helpers. I used yaourt initially before switching to aurget and then alighting on cower, or more particularly, a partial wrapper for cower:

cowerd
#!/bin/sh
# install AUR packages with cower

cd $HOME/Build && cower -d "$1"
builddir="$_"
cd "$builddir" && ${EDITOR:-vi} PKGBUILD

makepkg -si && cd - &>/dev/null

read -p "Remove Build directory? [Y/n]? " yn
if [ "$yn" = "y" ]; then
    printf "\n%s\n" "Removing build directory..."
    rm -rf "$builddir"
else
    printf "%s\n" "Build completed."
fi

This provides me the minimum level of automation I require—essentially only around downloading and installing a package. It doesn’t automatically handle dependencies, nor manage updating the packages; that remains, rightly in my view, my responsibility.

If I were to look to a more fully featured wrapper, I would undoubtedly choose meat, however as on my desktop machine, I only have ~30 AUR packages installed, I don’t really need anything more sophisticated.

So by all means, use an AUR helper. But recognize that it is intended to help you, not preclude you from being able to accomplish the most simple and critical task of system maintenance, updating your package manager. Uninstall yaourt if you are using it and familiarize yourself with makepkg; once you do understand the relationship between the official repositories and the AUR, download cower or meat, they are both much better solutions.

Notes

  1. Myself included

Creative Commons image of crutches by net_efekt on Flickr.

Building Vim

Apart from a brief, but nevertheless instructive, flirtation with Emacs1 I have been a consistent Vim user over the last three or four years. Like most Vim users, I have made some progress over that time in spite of Vim’s notorious learning curve and have now reached the point where, belatedly, I think I understand it just enough to really grasp how little I actually know. It’s a milestone that speaks more to necessity than gratification, granted.

In any event, as part of confronting my Vim shortcomings (no golfing for me), I have been able to land on the features of Vim that I require to be enabled so that I am moderately productive (in my own, admittedly cloistered, working environment). That, you will probably not be surprised to read, does not include needing support for Arabic or Farsi to be built into Vim.

Part of the beauty of Vim is that, unlike it’s operating system counterpart Emacs, you can choose how much functionality you wish to enable at compile-time. You do want support for Farsi? Then the --with-features=big option is what you are looking for. If, on the other hand, you just want the barest of bones, editor-wise, you could opt for the austere minimalism that is --with-features=tiny and find yourself happily transported back in time to Bill Joy’s lab in 1976.

You can peruse all of the various features available to Vim using the :help version command.2 There is also this table where the various features are listed against the respective feature flags (tiny, small, normal, big & huge).

After this bug report late last year, the default Arch PKGBUILD ships with huge as the feature set. Make what you will of that, but for my purposes it is overkill. With all the magic of ABS and makepkg, however, it is simple enough to build a Vim package that is tailored to exactly your requirements. For me, that means this set of simplified configure options:

  ./configure \
    --prefix=/usr \
    --localstatedir=/var/lib/vim \
    --with-features=normal \
    --with-compiledby=Arch:jwr \
    --with-x=yes \
    --enable-acl \
    --disable-gui \
    --disable-signs \
    --disable-netbeans \
    --enable-multibyte

With these options, I have the minimum amount of functionality I comfortably require (including the ability to access the system clipboard, --with-x=yes) but without the other bloat.

In addition to these changes to the config options, I also strip out all of the gvim-related stuff from the PKGBUILD as I do not require it. Even though it is a split package, just building vim still includes options superfluous to my needs. As a result, I get Vim with just the features I need, without the dependencies of ruby and lua and god knows what else.

I’m not operating under any illusions about the fact that this is really saving a huge amount of space or, for that matter, drastically reducing the number of dependencies I have installed. It is partly about understanding how Vim works at another level while also catering for the obsessive-compulsive drive to micro-control what is and isn’t installed on my systems. If you want to scratch either of the same itches, you can see the full PKGBUILD in Bitbucket.

Notes

  1. Still visible in some of my early Arch screenshots on Flickr
  2. The official documentation for the features is also online.