Basic guide to write Gentoo Ebuilds

From Gentoo Wiki
Jump to: navigation, search
This page contains changes which are not marked for translation.


Article status
This article has some todo items:

This article contains instructions for beginners on ebuilds development.

Portage, the heart of Gentoo, uses ebuilds!

An ebuild file is a text file, used by Gentoo package managers, which identifies a specific software package and how the Gentoo package manager should handle it. It uses a bash-like syntax style and is standardized through the EAPI version.

Gentoo Linux uses ebuilds as the package management format for individual software titles. These ebuilds contain metadata about the software (the name and version of the software, which license the software uses, and the home page), dependency information (both build-time as well as run-time dependencies), and instructions on how to deal with the software (configure, build, install, test ...).

Ebuilds, where do they live?

The location of ebuilds from the Gentoo repository (available in the snapshot) are usually at /var/db/repos/gentoo[1] but may also be in /usr/portage for older installs. The location is determined by the repos.conf file. Custom ebuilds are recommended to be placed in a custom repository, say /var/db/repos/larry.

How to create an ebuild

Users of app-editors/vim get the basic skeleton automatically (provided by app-vim/gentoo-syntax):

root #vim ./foobar.ebuild
FILE foobar.ebuildvim starts from the template
# Copyright 1999-2019 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
 
EAPI=7
 
DESCRIPTION=""
HOMEPAGE=""
SRC_URI=""
 
LICENSE=""
SLOT="0"
KEYWORDS="~amd64 ~x86"
IUSE=""
 
DEPEND=""
RDEPEND="${DEPEND}"
BDEPEND=""

A similar tool is available for users of GNU Emacs or XEmacs (provided by app-emacs/ebuild-mode or app-xemacs/ebuild-mode, respectively).

Users of other editors manually copy from the header.txt:

root #cp /var/db/repos/gentoo/header.txt ./foobar.ebuild

Essential information of the new package should be known and added to the ebuild-defined variables DESCRIPTION, HOMEPAGE, SRC_URI, LICENSE.

Example for a given source tarball

An ebuild for scrub, version 2.6.1 (if it didn't already exist) might read:

root #mkdir -p /var/db/repos/larry/app-misc/scrub
root #cd $_
root #vim ./scrub-2.6.1.ebuild
FILE scrub-2.6.1.ebuildvim starts from the template
# Copyright 1999-2019 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
 
EAPI=7
 
DESCRIPTION="Some words here"
HOMEPAGE="https://github.com/chaos/scrub"
SRC_URI="https://github.com/chaos/scrub/releases/download/2.6.1/scrub-2.6.1.tar.gz"
 
LICENSE="GPL-2"
SLOT="0"
KEYWORDS="~amd64 ~x86"
IUSE=""
 
DEPEND=""
RDEPEND="${DEPEND}"
BDEPEND=""

The SRC_URI is usually written with variables instead of hard coded.

CODE SRC_URI using variables
SRC_URI="https://github.com/chaos/${PN}/releases/download/${PV}/${P}.tar.gz"

It can be tested using the ebuild command like:

root #ebuild ./scrub-2.6.1.ebuild clean unpack
Appending /var/db/repos/larry to PORTDIR_OVERLAY...
>>> Downloading 'https://ftp.halifax.rwth-aachen.de/gentoo/distfiles/scrub-2.6.1.tar.gz'
--2019-06-03 16:42:57--  https://ftp.halifax.rwth-aachen.de/gentoo/distfiles/scrub-2.6.1.tar.gz
Resolving ftp.halifax.rwth-aachen.de... 137.226.34.46, 2a00:8a60:e012:a00::21
Connecting to ftp.halifax.rwth-aachen.de|137.226.34.46|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 362536 (354K) [application/octet-stream]
Saving to: '/usr/portage/distfiles/scrub-2.6.1.tar.gz.__download__'

/usr/portage/distfiles/scrub-2.6.1.tar.gz.__download__             100%[==============================================================================================================================================================>] 354.04K  --.-KB/s    in 0.08s   

2019-06-03 16:42:58 (4.24 MB/s) - '/usr/portage/distfiles/scrub-2.6.1.tar.gz.__download__' saved [362536/362536]

 * scrub-2.6.1.tar.gz BLAKE2B SHA512 size ;-) ...                                                                                                                                                                                                                  [ ok ]
>>> Unpacking source...
>>> Unpacking scrub-2.6.1.tar.gz to /var/tmp/portage/app-misc/scrub-2.6.1/work
>>> Source unpacked in /var/tmp/portage/app-misc/scrub-2.6.1/work

This should download and unpack the source tarball. In some rare cases the package should work and no further adjustments is needed in the ebuild.

Using the PATCHES array

If patches need to be applied to the source code an array called PATCHES can be declared.

CODE Patches will be applied during src_prepare
PATCHES=(
	"${FILESDIR}"/${P}-foo.patch
	"${FILESDIR}"/${P}-bar.patch
)

src_prepare() {
    default
    ...
}

Example: Package for a file that echoes "hello world!"

So, let's create us a minimal ebuild; to keep it simple I will assume you run under root privileges, you can always use sudo if you feel like.

root #mkdir -p /usr/local/portage/app-misc/hello-world
root #cd $_

We recursively create the directories and cd into it ($_ recalls the last argument), then we create an ebuild out of the ebuild header which is a necessity if you want it added to the Gentoo repository.

This won't run yet, it requires us to define a minimal amount of variables, so let's add the following code inside the ebuild:

CODE The minimum code you need to put inside an ebuild
DESCRIPTION="A classical example to use when starting on something new"
SLOT="0"

Just two variables? Exactly, it is required that we have a one-line DESCRIPTION of our package, and that we explicitly state that we won't use SLOTs, which is what "0" means. Save this file as hello-world-1.0.ebuild.

Ensure that it and you are in /usr/local/portage/app-misc/hello-world/ (if you are in the wrong directory, you will get an error starting "!!! Repository 'x-local' is missing masters attribute"). We can now install the package to the system by running:

root #ebuild hello-world-1.0.ebuild manifest clean merge

This will manifest (create hashes, to avoid corruption), clean any present temporary work directories and (e)merge the ebuild.

Good, you have just made and tested your first ebuild, it doesn't really do much but it's a good start!

Adding more useful variables

If you take a look at /usr/portage/skel.ebuild you see a skeleton with a lot of documentation, we will be adding some of these variables and functions to our ebuild as we proceed; so, it seems wise to read over this file as we go. Add the following code blocks to our hello-world-1.0.ebuild:

CODE The council suggests to use the latest ebuild API
EAPI=7
Important
The above variable must be listed first after the header! So, add it above the variables we already have.

More information about the EAPI can be found here.

CODE The homepage which the package was found on, for developer reference
HOMEPAGE="https://wiki.gentoo.org/index.php?title=Basic_guide_to_write_Gentoo_Ebuilds"
CODE The source code which we will download, hosted by the developer who wrote this documentation
SRC_URI="https://dev.gentoo.org/~tomwij/files/wiki/hello-world-1.0.tar.gz"

This is a simple tarball which contains a hello-world shell script which echoes "Hello world!".

Next, we need to specify a license. I hereby tell you I am licensing it under the MIT license so let us specify that.

CODE This package is licensed under the MIT license
LICENSE="MIT"

We already did the SLOT, so we can move on to KEYWORDS. The KEYWORDS variable tells you on which architectures a package works and also tells you whether it is masked (not listed or explicitly listed with -), untested (~) or stable (listed, but with no character in front of it). Since we can't stabilize ourselves (bugs are to be filed for that), the best we can do for now is list all the architectures as untested. All the architectures, because they can all run shell scripts.

CODE We hereby confirm that our package runs on all architectures, but might not be stable yet
KEYWORDS="~alpha ~amd64 ~arm ~hppa ~ia64 ~ppc ~ppc64 ~s390 ~sh ~sparc ~x86"

The other variables define some more specific things (check them out in skel.ebuild) but we won't need them for now; you also see there are functions, but let us see what the ebuild already does by now.

CODE The ebuild should look like this
# Copyright 1999-2019 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
 
EAPI=7
 
DESCRIPTION="A classical example to use when starting on something new"
HOMEPAGE="https://wiki.gentoo.org/index.php?title=Basic_guide_to_write_Gentoo_Ebuilds"
SRC_URI="https://dev.gentoo.org/~tomwij/files/wiki/hello-world-1.0.tar.gz"
 
LICENSE="MIT"
SLOT="0"
KEYWORDS="~alpha ~amd64 ~arm ~hppa ~ia64 ~ppc ~ppc64 ~s390 ~sh ~sparc ~x86"
root #ebuild hello-world-1.0.ebuild manifest clean merge

We see that it first tries to download our file from a mirror, but since it is not on the Gentoo mirrors it will download it from the SRC_URI value that was specified.

Then, when it has the file it can create a manifest, this contains a hash of our ebuild and that downloaded file to ensure integrity such that corruption will yield errors.

Then, the emerge process kicks in, the integrity is first checked. Then, we can see the archive we downloaded is automatically unpacked, this is really useful as we don't have to implement this anymore. We can change this behavior by overriding its function (src_unpack), setting some variables or using eclasses whom define such behavior; but we don't need to do that in this case.

As we read further, we see that it tries to prepare, configure, compile and install. In the prepare phase, patches will typically be applied. In the configure and compile phases, the typical build process is done, by default in runs econf (a wrapper for ./configure) and emake (a wrapper for make) when it finds files to handle; but since we use a shell script, we won't need to adjust these phases.

Now, the last step doesn't look quite right; it doesn't install our file yet...

Telling the ebuild where to install our shell script.

In our development manual we can find a page about the phase functions, src_install seems useful for what we want to do. If you click on the src_install link you will see what it does by default for each EAPI as well as some examples. As the default doesn't look good, we'll define our own src_install function. In our function we will be calling other functions to do installation work for us, an overview for them is install functions.

Warning
Ebuilds should never directly install to the live file system, therefore we do not use typical commands like mv, cp, and rm. Moreover we do not use absolute paths. We use the above command and work against ${D} which is the destination directory.

So, we can proceed by adding the following function to our ebuild:

CODE call to src_install is required for our hello-world shell script to later be placed in /usr/bin and made executable
src_install() {
    dobin hello-world
}

That dobin call will copy hello-world to a temporary build directory (${D}/usr/bin/), make it executable; later on it will be checked by Portage and copied to the live file systems.

Let us try again...

root #ebuild hello-world-1.0.ebuild manifest clean merge

Ah, we see ">>> /usr/bin/hello-world", that looks good!

Let us try...

user $hello-world

And there we have it, we just installed a package that echoes "Hello world!".

New example: Package compiled in C ++ that echoes "Hello World , Again!"

This example is similar to the previous one. However, it was written in C++, has a Makefile, but does not have configure. It is the same idea, but the package will be compiled hello-world-2.0.ebuild:

CODE File tree
hello-world-2.0/
├── Makefile
└── src
    ├── helloworld.cpp
    ├── helloworld.hh
    └── main.cpp
 
1 directory, 4 files


The code of the files and the Makefile

FILE helloworld.hh
#ifndef EXAMPLE_HELLOWORD_H
#define EXAMPLE_HELLOWORD_H
 
#include <iostream>
 
class HelloWorld {
	public:
		HelloWorld();
		virtual ~HelloWorld();
                void run();
 
	protected:
		virtual void my_world();	
 
};
 
#endif
FILE helloworld.cpp
#include "helloworld.hh"
#include <iostream>
 
HelloWorld::HelloWorld(){
	std::cout << "Hello";
}
 
HelloWorld::~HelloWorld(){ }
 
void HelloWorld::my_world(){
	std::cout << " World " ;
}
 
void HelloWorld::run(){
	my_world();
	std::cout << ", Again!" << std::endl;
}
FILE main.cpp
#include "helloworld.hh"
 
int main(int argc, char *argv[]){
 
	HelloWorld helloworld;
	helloworld.run();
 
	return 0;
}
FILE Makefile
TARGET=hello-world
CC=g++
DEBUG=-g
OPT=-O0
WARN=-Wall
PTHREAD=-pthread
CCFLAGS=$(DEBUG) $(OPT) $(WARN) $(PTHREAD) -pipe
LD=g++
LDFLAGS=$(PTHREAD) -export-dynamic
OBJS= main.o helloworld.o
all: $(OBJS)
	$(LD) -o $(TARGET) $(OBJS) $(LDFLAGS)
 
main.o: src/main.cpp
	$(CC) -c $(CCFLAGS) src/main.cpp -o main.o
 
helloworld.o: src/helloworld.cpp
	$(CC) -c $(CCFLAGS) src/helloworld.cpp  -o helloworld.o
 
clean:
	rm -f *.o


The end result of the new ebuild:

FILE hello-world-2.0.ebuild
# Copyright 2019 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
 
EAPI=7
 
DESCRIPTION="A classical example to use when starting on something to compile."
HOMEPAGE="https://wiki.gentoo.org/wiki/Basic_guide_to_write_Gentoo_Ebuilds"
SRC_URI="https://terminalroot.com.br/downs/hello-world-2.0.tar.gz"
 
LICENSE="MIT"
SLOT="0"
KEYWORDS="~amd64 ~x86"
 
src_install() {
	dobin hello-world
}

To create the archive necessary, run:

user $tar zcvf hello-world-2.0.tar.gz hello-world-2.0/

Next, prepare the package Manifest signatures, run:

user $ebuild hello-world-2.0.ebuild manifest

Finally, install the package with:

root #emerge --ask hello-world

To be continued!

New sections will get added as new examples get produced...

Here are some ideas for more examples if anyone wants to help writing this article:

  • Expand on the hello world ebuild by adding a src_prepare function where we will patch the package such that the shell script asks for the user's name and uses it instead of world.
  • Usage of variables like P, PN, PV, and PF to ease the maintenance (assume a new version of the package was released).
  • Installation of optional documentation (via IUSE="doc").
  • Usage of autotools, cmake, and other useful eclasses; in easy to use examples.
  • How to ensure QA, deal with QA warnings and errors and set up FEATURES for more reliable ebuild writing.
  • Explain how to contribute and how to become a developer.
Important
This article is meant to be a "hands-on introduction", its scope is therefore limited and it is not intended to replace the development manual.

Adding support for user patches to ebuilds

Since EAPI 6, the support for user patches is provided by eapply_user. This can be done by putting default on top in the src_prepare function:

CODE sample src_prepare
src_prepare() {
    default
    ...
}

EAPI versions prior to EAPI 6 should not be used for new ebuilds.

See also

External resources

References