Upgrade Ebuild EAPIs HOWTO

Introduction

Gentoo ebuilds have upgraded the API that they have available over time to include new features and fix bugs in existing behavior. In order to guarantee that ebuilds written yesterday continue to work with package managers of tomorrow, the API available to ebuilds has been formalized in the Package Manager Spec (PMS). The short summary is that ebuilds declare the version of the API that they've been written for by setting the EAPI variable at the top of the ebuild, and the spec guarantees that behavioral changes will only occur in newer versions.

You might encounter ebuilds using older EAPIs. We'll provide a quick guide to cover the common issues you see when upgrading to the latest version. At this time, that is EAPI 5, but our focus has been on EAPI 4 or newer. This is because the functionality new to EAPI 5 is not significant enough to warrant forcing an upgrade and few ebuilds would even utilize it.

Note that while the convention thus far has been to use numbers in the official spec (like 0, 1, 2, etc...), the EAPI setting is a string, not an integer.

Common Changes

EAPI Setting

First, if your ebuild doesn't even have an EAPI setting at the top, then it defaults to the oldest version of 0. If it does contain a setting, then you should make sure it is 4 or 5.

# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
# Distributed under the terms of the GNU General Public License v2

EAPI=4

This is what the header of your ebuild should look like. The only thing that comes before the EAPI line is the file's comment block which declares copyright & licensing (the year & license may vary), then a blank line, then the EAPI setting.

Default Source Directory Setting

In older EAPI versions, the variable S would default to ${WORKDIR}/${P}. But if ${P} did not exist, the ebuild would silently fall back to the work directory (${WORKDIR}). For some ebuilds, this wasn't a problem because they only installed files out of ${FILESDIR} or ${SYSROOT}

Newer EAPI versions no longer do this automatic fallback to ${WORKDIR}. If you get errors like "The source directory '...' doesn't exist", then you're hitting this problem (i.e. relying on the older silent fallback behavior).

The easy answer is usually to set S to ${WORKDIR}.This might not be the right answer (maybe your source lives somewhere else), but frequently this is OK. So after the DEPEND/RDEPEND variables and before any of the src_* or pkg_* functions, add:

S=${WORKDIR}

New Function Phases

In EAPI versions starting with 2, some source functions were split up to better reflect the overall build process. So if you're upgrading from those, here's what you need to know:

  • If you declare a src_unpack function, move all source patching/hacking (like running `sed`) to a new src_prepare. This often means that src_unpack is deleted entirely as the default of unpacking all archives in SRC_URI is sufficient.
  • If you declare a src_compile function, move all configure steps (like `econf` or `./configure`) to a new src_configure. This often means that src_compile is deleted entirely as the default of just running `emake` is sufficient.

Here is an example of splitting src_unpack into src_unpack and src_prepare:

# This is the old (pre-EAPI 4) version.
src_unpack() {
    unpack ${A}
    cd "${S}"
    epatch "${FILESDIR}"/${P}-a-fix.patch
    sed -i 's:old:new:' configure.ac || die
    eautoreconf
}
# This is the new (EAPI 4+) version.
# Note that there is no src_unpack at all because the default is `unpack ${A}`.
# If you needed to unpack things in a specific way, you can add your own
# src_unpack function and do just that.
src_prepare() {
    epatch "${FILESDIR}"/${P}-a-fix.patch
    sed -i 's:old:new:' configure.ac || die
    eautoreconf
}

Here is an example of splitting src_compile into src_configure and src_compile:

# This is the old (pre-EAPI 4) version.
src_compile() {
    econf \
        --enable-foo \
        $(use_enable bluetooth) \
        || die
    emake || die
}
# This is the new (EAPI 4+) version.
# Note that there is no src_compile at all because the default is `emake`.
# If you passed additional flags to `emake`, then you can add your own
# src_compile function and do just that.
src_configure() {
    econf \
        --enable-foo \
        $(use_enable bluetooth)
}

Implicit Die Commands

Starting with EAPI 4, all of the helper commands (like emake and doins and dobin and ...) were updated to automatically call `die` when they failed. This means you no longer have to (and in fact you should avoid doing so). This does not apply to other commands like `mv` or `sed` or `cp` -- if you run those, you should still call `die`.

Here's an example of converting to these newer EAPIs:

# This is the old (pre-EAPI 4) version.
src_compile() {
    emake USE_EXTRA=1 || die "emake failed"
}
src_install() {
    emake install install-man USE_EXTRA=1 DESTDIR="${D}" || die "emake install failed"
    dodoc *.txt || die "dodoc failed"
    insinto /etc/init
    newins "${FILESDIR}"/package.init package || die "doins failed"
}
# This is the new (EAPI 4+) version.
src_compile() {
    emake USE_EXTRA=1
}
src_install() {
    emake install install-man USE_EXTRA=1 DESTDIR="${D}"
    dodoc *.txt
    insinto /etc/init
    newins "${FILESDIR}"/package.init package
}

On the rare occasion you expect a command to fail and want to handle it yourself, you can use the new `nonfatal` helper like so:

src_install() {
    if ! nonfatal doins some.bin; then
        # Handle the failed install yourself.
    fi
}

The `default` Function

There is now a nifty helper function called default that let's you execute the default commands that a function would do. This saves a bit of code while letting you still do a bit of additional things. It most commonly comes up in the src_install function when packages use `emake install DESTDIR="${D}"`. If you need to pass additional flags to emake though, then this won't help.

# This is the old (pre-EAPI 4) version.
src_install() {
    emake install DESTDIR="${D}" || die
    doman man/*.1 || die
    insinto /etc
    doins "${FILESDIR}"/some.conf || die
}
# This is the new (EAPI 4+) version.
src_install() {
    default
    doman man/*.1
    insinto /etc
    doins "${FILESDIR}"/some.conf
}
Comments