en it es

RBuild Development Quickstart

This page provides a very brief introduction to rbuild writing. It does not attempt to cover many of the details or problems that will be encountered by developers — rather, it gives some trivial examples which may be of use when trying to grasp the basic idea of how rbuilds work.

For proper coverage of all the ins and outs, see Rbuild Writing. The General Concepts chapter will also be of use.

Note that the examples used here, whilst based upon real tree rbuilds, have had several parts chopped out, changed and simplified.

First rbuild

We’ll start with an rbuild for the Exuberant Ctags utility, a source code indexing tool.

ctags.rbuild:

maintainer 'meh. <meh@paranoici.org>'

name 'ctags'
tags 'application', 'development', 'utility'

description 'Exuberant ctags generates tags files for quick source navigation.'
homepage    'http://ctags.sourceforge.net'
license     'GPL-2'

source 'sourceforge://ctags/ctags/#{package.version}/ctags-#{package.version}'

before :configure do |conf|
	conf.enable 'tmpdir', '/tmp'

	conf.disable ['etags']
	conf.with    ['posix-regex']
	conf.without ['readlib']
end

after :install do |conf|
	package.do.doc 'FAQ', 'NEWS', 'README'
	package.do.html 'EXTENDING.html', 'ctags.html'
end

ctags-5.8.rbuild

version '5.8'

arch     'x86', 'x86_64'
kernel   'linux', 'windows'
compiler 'gcc'
libc     'glibc'

Basic format

As you can see, rbuilds are just Ruby scripts that are executed within packo’s library. It’s suggested to know at least the basics of Ruby, if you don’t know it this is a good chance to learn something new.

Usually you have at least two rbuilds, one that’s general (ctags.rbuild) and one for the version (ctags-5.8.rbuild), the latter inherits all the stuff from the former, you could put everything in the same rbuild, but with more versions you’d have tons of repeated stuff without a good reason.

The version can (and should) be omitted in rbuilds that go in the tree, this is because the version is implicitly defined by the file name. If you’re writing a single rbuild with a random name you should define the version, otherwise it wouldn’t know what to build.

Rbuilds are indented using two spaces. See Rbuild file format.

From now on the version specific rbuild won’t be added if there’s no good reason, just remember that a version specific rbuild is always there with definitions about what it is compatible with.

Information variables

Next, there are a series of variables. These tell Packø various things about the rbuild and package in question.

The description variable is set to a short description of the package and its purpose.

The homepage is a link to the package’s homepage (remember to include the http:// part).

The license is the license used by the package source, in this case it’s GPL-2 (the GNU General Public License version 2).

The maintainer variable tells who to talk with in case of bugs in the rbuild.

The source tells Packø the address to use for downloading the source. Here sourceforge:// is a special notation meaning “use the sourceforge fetcher”, stuff between #{} will be interpolated at the right time, so #{package.version} will become 5.8 when interpolated. Remember not to use the literal notation that gets interpolated when defined, check a Ruby reference to know which ones get interpolated.

Callbacks

Next, we register a callback to be called before :configure, Packø will call this callback before executing the configure stage. The passed conf variable is a Configuration object defined by the Building::Autotools module.

You can stop the whole callback dispatching by calling skip in the callback, in this way you can override the default configure execution with something different.

./configure, make and make install are called appropiately by the Building::Autotools module, all you have to do is set what’s need in the conf object and when needed it will be converted to something readable by the configure script.

The do.doc and do.html are helper functions for installing files into the relevant part of /usr/share/doc.

Rbuilds can use other modules and callbacks (see Rbuild Modules). In all cases, Packø provides a reasonable default implementation which quite often does the right thing. There was no need to do weird stuff for :unpack, for example you may need to cd into the right directory if the name of the directory inside the archive isn’t called like the archive.

Rbuild with files

Sometimes rbuilds need some files, may it be for configurations, init scripts or whatever.

Packø has two ways to store files, one is by adding a directory called data in the same directory of the rbuild, the other way is to embed the files in the rbuild.

If the files are small, like patches or short configuration examples it’s suggested to use the embedding facilities rather than having a data directory floating around.

maintainer 'meh. <meh@paranoici.org>'

name 'sandbox'
tags 'application', 'system'

description "Gentoo's sandbox utility for more secure package building"
homepage    'http://www.gentoo.org/'
license     'GPL-2'

source 'http://dev.gentoo.org/~vapier/dist/sandbox-#{package.version}.tar.xz'

after :install do
	File.write("#{package.distdir}/etc/sandbox.d/09sandbox", package.filesystem['files/sandbox'])
	File.write("#{package.distdir}/etc/sandbox.d/10packo", package.filesystem['files/packo'])
end

__END__
$$$

$$$ files/sandbox $$$

CONFIG_PROTECT_MASK="/etc/sandbox.d"

$$$ files/packo $$$

SANDBOX_READ="/var/lib/packo"
SANDBOX_WRITE="/var/lib/packo"

SANDBOX_READ="${HOME}/.packo"
SANDBOX_WRITE="${HOME}/.packo"

As you can see we have the usual informational variables and then a callback that refers to a package.filesystem variable.

This variable is an FFFS::FileSystem object and you can access the files by path.

Files are defined after the __END__ part, it should be pretty obvious how to use this feature by reading the example.

Rbuild with dependencies

In the ctags example, we didn’t tell Packø about any dependencies. As it happens, that’s ok, because ctags only needs a basic toolchain to compile and run. However, life is rarely that simple.

Here’s application/system/detox:

name 'detox'
tags 'application', 'system'

description 'Safely remove spaces and strange characters from filenames'
homepage    'http://detox.sourceforge.net/'
license     'BSD'

dependencies << 'development/library/popt' << 'system/development/flex!' << 'system/development/bison!'

source 'sourceforge://detox/detox/#{package.version}/detox-#{package.version}'

before :configure do |conf|
	conf.with ['popt']
end

after :install do |conf|
	package.do.rm '/etc/detoxrc.sample'
	package.do.doc 'README', 'CHANGES'
end

Again, you can see the rbuild various informational variables.

Again, we hook to configure and compile.

The dependencies variable is how Packø determines which packages are needed to build and run the package. Dependencies can be specified to be needed to build, during runtime, or both. The default is both, to specify it as build put a ! at the end and !! for runtime.

Rbuild with patches

Often we need to apply patches. This can be done in two ways, by adding a patches directory (in data/ or embedded), these patches are used by the module Building::Patch appropriately.

name 'detox'
tags 'application', 'system'

description 'Safely remove spaces and strange characters from filenames'
homepage    'http://detox.sourceforge.net/'
license     'BSD'

dependencies << 'development/library/popt' << 'system/development/flex!' << 'system/development/bison!'

source 'sourceforge://detox/detox/#{package.version}/detox-#{package.version}'

before :configure do |conf|
	conf.with ['popt']
end

after :install do |conf|
	package.do.rm '/etc/detoxrc.sample'
	package.do.doc 'README', 'CHANGES'
end

__END__
$$$

$$$ patches/Makefile.patch $$$

https://sourceforge.net/tracker/index.php?func=detail&aid=2166388&group_id=101612&atid=630105

--- Makefile.in	2008-10-14 16:37:22 +0000
+++ Makefile.in	2008-10-14 16:38:17 +0000
@@ -70,10 +70,10 @@
 #

 detox: ${detoxOBJS}
-	${CC} -o detox ${detoxOBJS} ${L_OPT}
+	${CC} ${LDFLAGS} -o detox ${detoxOBJS} ${L_OPT}

 inline-detox: ${inline-detoxOBJS}
-	${CC} -o inline-detox ${inline-detoxOBJS} ${L_OPT}
+	${CC} ${LDFLAGS} -o inline-detox ${inline-detoxOBJS} ${L_OPT}

 #
 # Special Source Compiles

$$$ patches/Makefile.2.patch $$$

https://sourceforge.net/tracker/index.php?func=detail&aid=2166387&group_id=101612&atid=630105

--- Makefile.in	2008-10-14 16:39:34 +0000
+++ Makefile.in	2008-10-14 16:38:51 +0000
@@ -131,7 +131,7 @@
    ${INSTALL} -m 644 detox.1 ${DESTDIR}${mandir}/man1
    ${INSTALL} -m 644 detoxrc.5 detox.tbl.5 ${DESTDIR}${mandir}/man5

-install-safe-config:
+install-safe-config: install-base
    @if [ ! -f ${DESTDIR}${sysconfdir}/detoxrc ]; then \
        ${INSTALL} -m 644 detoxrc ${DESTDIR}${sysconfdir}; \
    else \
@@ -148,12 +148,12 @@
        echo "${DESTDIR}${datadir}/detox/unicode.tbl exists, skipping"; \
    fi

-install-unsafe-config:
+install-unsafe-config: install-base
    ${INSTALL} -m 644 detoxrc ${DESTDIR}${sysconfdir}
    ${INSTALL} -m 644 iso8859_1.tbl ${DESTDIR}${datadir}/detox
    ${INSTALL} -m 644 unicode.tbl ${DESTDIR}${datadir}/detox

-install-sample-config:
+install-sample-config: install-base
    ${INSTALL} -m 644 detoxrc ${DESTDIR}${sysconfdir}/detoxrc.sample
    ${INSTALL} -m 644 iso8859_1.tbl ${DESTDIR}${datadir}/detox/iso8859_1.tbl.sample
    ${INSTALL} -m 644 unicode.tbl ${DESTDIR}${datadir}/detox/unicode.tbl.sample

For bigger sets of patches it’s suggested to use archives, see Building::Patch for more informations.

Rbuild with features

Now for some features. Here’s application/mail/client/sylpheed.

maintainer 'meh. <meh@paranoici.org>'

name 'sylpheed'
tags 'application', 'mail', 'client'

description 'A lightweight email client and newsreader'
homepage    'http://sylpheed.sraoss.jp/'
license     'GPL-2', 'LGPL-2.1'

source 'http://sylpheed.sraoss.jp/sylpheed/v#{package.version.major}.#{package.version.minor}/sylpheed-#{package.version}.tar.bz2'

dependencies << 'misc/mime-types' << 'misc/network/curl' << 'misc/x11/shared-mime-info'

features {
	ipv6 {
		before :configure do |conf|
			conf.enable 'ipv6', enabled?
		end
	}

	ssl {
		before :configure do |conf|
			conf.enable 'ssl', enabled?
		end
	}

	crypt {
		before :dependecies do |deps|
			deps << 'application/crypt/gpgme'
		end

		before :configure do |conf|
			conf.enable 'gpgme', enabled?

			if disabled?
				Do.cp 'ac/missing/gpgme.m4', 'ac/'
			end
		end
	}

	ldap {
		before :configure do |conf|
			conf.enable 'ldap', enabled?
		end
	}

	nls

	pda {
		before :dependencies do |deps|
			deps << 'application/pda/jpilot'
		end

		before :configure do |conf|
			conf.enable 'jpilot', enabled?
		end
	}

	spell {
		before :dependencies do |deps|
			deps << 'application/text/gtkspell'
		end

		before :configure do |conf|
			conf.enable 'gtkspell', enabled?
		end
	}

	xface {
		before :dependencies do |deps|
			deps << 'library/media/compface!'
		end

		before :configure do |conf|
			conf.enable 'compface', enabled?
		end
	}
}

before :configure do |conf|
	autotools.autoreconf

	htmldir = Path.clean("/usr/share/doc/sylpheed-#{package.version}")

	conf.with 'manualdir', "#{htmldir}/manual"
	conf.with 'faqdir',    "#{htmldir}/faq"

	conf.disable 'updatecheck'
end

after :install do |conf|
	package.do.doc 'AUTHORS', 'ChangeLog*', 'NEWS*', 'README*', 'TODO*'
end
}

As you can see features have their own block and they can hook to callbacks as it was in the toplevel.

When in a feature block you have few helper methods to work with the feature, like enabling it by default or knowing if it’s enabled or disabled. More details here.

conf.enable is used to enable or disable a feature, it will then be transormed into --enable-something or --disable-something as per ./configure. More details here.

This work by meh. is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.