Chapter 20. Porting an Application

Porting an application means starting with the original sources and changing them a little bit to make it work. When using a recipe the port will work on many platforms.

The presence of the variable "PORTNAME" triggers A-A-P to handle the recipe as
a port recipe.  This will happen:

1. Add the dependency:
	all: dependcheck builddepend
			fetch checksum extract patch configure build test
			package install rundepend
2. For each of the targets in the dependency above add a dependency based on
   the variables set in the recipe.

You can define dependencies for:
	do-XXX		replace the body of a step
	pre-XXX  	do something before a step
	post-XXX	do something after a step

General info provided by the port recipe:
	Various variables need to be set to specify properties of the port.
	PORTNAME	name of the port  	"foobar"
	PORTVERSION	app version number  	"3.8alpha"
	PORTREVISION	port patchlevel	  	"32"
		--> foobar-3.8alpha_32
			info URL		http://www.foobar.org
	MAINTAINER_NAME	maintainer name		John Doe
	MAINTAINER	maintainer e-mail	john@foobar.org
	PORTCOMMENT	short description	get foo into the bar
	PORTDESCR	long description	blah blah blah
	IS_INTERACTIVE	requires user input	yes or no

Variables that can be used by the port recipe:
	WRKDIR		directory all files are extracted in and the building
			is done in		default: "work"
	DISTDIR		directory where downloaded distfiles are stored
						default: "distfiles"
	PATCHDISTDIR	directory where downloaded patches are stored
						default: "patches"
	PKGDIR		directory where files are stored before creating a
			package			default: "pack"

Variables that may be set by the port recipe, defaults are set only after
reading the recipe:
	WRKSRC		Directory inside $WRKDIR where the unpacked sources
			end up. This should be the common top directory in the
			unpacked archives.	default: $PORTNAME-$PORTVERSION
			When using CVS it is always set to $CVSWRKSRC (also
			when $WRKSRC was already set).
	CVSWRKSRC	Directory inside $WRKDIR where files obtained with CVS
			end up.			default: the first entry in
						$CVSMODULES
 	NO_WRKSUBDIR	When not empty, $WRKSRC will be empty instead of using
			the default value.	default: not set
	PATCHDIR	Directory inside $WRKDIR where patches are to be
			applied.  		default: $WRKSRC
	BUILDDIR	Directory inside $WRKDIR where building is to be
			done.  			default: $WRKSRC
	TESTDIR		Directory inside $WRKDIR where testing is to be
			done.  			default: $WRKSRC
	
	INSTALLDIR	Directory inside $WRKDIR where $INSTALLCMD is to be
			done.  			default: $WRKSRC
	CONFIGURECMD    Set to the command used to configure the application.
			Usually "./configure".
			Default: nothing
	BUILDCMD	Set to the command used to build the application.
			Usually just "make".
			Default: "aap".
	TESTCMD		Set to the command used to test the application.
			Usually "make test".
			Default: "aap test".
	INSTALLCMD	Set to the command used to do a fake install of the
			application.
			Default: "aap install DESTDIR=$PKGDIR


For running configure, define a pre-build target.  Example:

	pre-build:
		:cd $WRKDIR/$WRKSRC
		:sys LANG=de ./configure --with-extra


DEPENDENCY FORMAT

Dependencies on other modules are specified with the various DEPEND_
variables.  The format of these variables is a list of items.

Items are normally white separated, which means there is an "and" relation
between them.  Alternatively "|" can be used to indicate an "or" relation.

	DEPENDS = perl python		require both perl and python
	DEPENDS = perl | python		require perl or python

Parenthesis can be used to group items.  Parenthesis must be used when
combining "or" and "and" relations.  Example:

	(foo bar) | foobar	Either both "foo" and "bar" or "foobar"
	foo bar | foobar	Illegal
	foo (bar | foobar)	"foo" and either "bar" or "foobar"

When a dependency is not met the first alternative will be installed, thus the
order of "or" alternatives is significant.

Each item is in one of these formats:

	name-version_revision		a specific version and revision
	name				any version
	name-regexp			a version specified with a regular
					expression (shell style)
	name>=version_revision		any version at or above a specific
					version and revision
	name>version_revision		any version above a specific version
					and revision
	name<=version_revision		any version at or below a specific
					version and revision
	name<version_revision		any version below a specific version
					and revision
	name!version_revision		any version but a specific version and
					revision

In the above "_revision" can be left out to ignore the revision number.  It
actually works as if there is a "*" wildcard at the end of each item.

"name" can contain wildcards.  When a part is following it is appended at the
position of the wildcard (or at -9 if it comes first).
	foo-*		matches foo-big, foo-big-1.2 and foo-1.2
	foo-*!1.2	matches foo-big, foo-big-1.2 and skips foo-1.2

The version specifications can be concatenated, this creates an "and"
relation.  Example:

	foo>=1.2<=1.4		versions 1.2 to 1.4 (inclusive)
	foo>=1.2!1.8		versions 1.2 and above, excluding 1.8
	xv>3.10			versions above 3.10, accepts xv-3.10a

The "!" can be followed by parenthesis containing a list of specifications.
This excludes the versions matching the specifications in the parenthesis.
Example:

	foo>=1.1!(>=1.3<=1.5)		versions 1.1 and higher, but not
					versions 1.3 to 1.5
	foo>=6.1!6.1[a-z]*		version 6.1 and later but not 6.1a,
					6.1rc3, etc.

When a dependency is not met the newest version that meets the description is
used.

For systems that do not allow specifying dependencies like this in a binary
pacakge, the specific package version that exists when generating the package
is used.


DEPENDENCIES FOR VARIOUS STEPS

The various variables used to specify dependencies:

	DEPEND_FETCH		Required for fetching files.  Also for
				computing checksums.
	DEPEND_EXTRACT		Required for unpacking archives.
	DEPEND_BUILD		Required for building but not necessarily for
				running; these are not included in the binary
				package; items may also appear in DEPEND_RUN.
	DEPEND_TEST		Required for testing only; don't include items
				that are already in DEPEND_RUN.
	DEPEND_RUN		Required for running; these will also be
				included in the generated binary package.
	DEPENDS			Used for DEPEND_BUILD and DEPEND_RUN when
				empty.

Only the dependencies specified with DEPEND_RUN will end up in the generated
binary package.  When using a shared library, it is recommended to put a
dependency on the developer version (includes header files) in DEPEND_BUILD
and a dependency on the library itself in DEPEND_RUN.  The result is that when
installing binary packages the header files for the library don't need to be
installed.


The "CONFLICTS" variable should be set to specify modules with which this one
conflits.  That means only one of the two packages can be installed in the
same location.  It should still be possible to install the packages in
different locations.  The format of CONFLICTS is identical to that of the
DEPENDS_ variables.

Dependencies are automatically installed, unless "AUTODEPEND" is "no".
The dependencies are normally satisfied by installing a port.  When a
satisfying port can not be found a binary package is installed.
The ports and packages are first searched for on the local system.  When not
found the internet is searched.

The order of searching can be changed with "AUTODEPEND":
	binary			only search for binary packages, default
				locations
	source			only search for ports, default locations
	source {path = /usr/ports http://ports.a-a-p.org}
				only search for ports in /usr/ports and on the
				ports.a-a-p.org web site.


STEPS

These are the individual steps for installing a ported application.  Each step
up to "install" depends on the previous one.  Thus "aap install" will do all
the preceding steps.  But the steps that have already been successfully done
will be skipped.  The "rundepend", "installtest", "clean", etc. targets do not
depend on previous steps, they can be used separately.

dependcheck: check if required dependencies can be fulfilled
	This doesn't install anything yet, it does an early check if building
	and/or installing the port will probably work before starting to
	download files.
	This uses all the DEPEND_ variables that will actually be used.
	Fails if something is not available.

fetchdepend: check dependencies for fetch and checksum
	Uses DEPEND_FETCH, unless disabled with AUTODEPEND=no

fetch: get required files
	if $CVSMODULES is set and $CVS is not "no", obtain files from CVS
		uses $CVSROOT or cvsroot attribute in $CVSMODULES
		$CVSWRKSRC is where the files will end up (default is first
			entry in $CVSMODULES)
		also obtain $CVSDISTFILES if defined
		also obtain $CVSPATCHFILES if defined
		use post-fetch to rename directories
	else
		if $DISTFILES is set obtain them
		if $PATCHFILES is set obtain them
	Use MASTER_SITES for [CVS]DISTFILES
	Use PATCH_SITES for [CVS]PATCHFILES
	the [CVS]DISTFILES are put in $DISTDIR
	the [CVS]PATCHFILES are put in $PATCHDISTDIR
	The directory can be overruled with a {distdir = dir} attribute on
	individual patch files.
	Files that already exist are skipped (if there is a checksum error,
	delete the file(s) manually).

checksum: check if checksums are correct
	The port recipe writer must add the "do-checksum" target with
	":checksum" commands to verify that downloaded files are not
	corrupted.  Example:

		# >>> automatically inserted by "aap makesum" <<<
		do-checksum:
		    :checksum $DISTDIR/foo-1.1.tgz {md5 = 2341423423423423434}
		    :checksum $PATCHDISTDIR/foo-patch3.gz {md5 = 3923858739234}
		# >>> end <<<

	The "aap makesum" command can be used to generate the lines.

extractdepend: check dependencies for extract and patch
	Uses DEPEND_EXTRACT, unless disabled with AUTODEPEND=no

extract: unpack the archives
	unpack archives in the right place
		use $EXTRACT_ONLY if defined, otherwise $DISTFILES or
		$CVSDISTFILES when CVS was used
	Uses the "extract" action.  Do extract a new type of archive:
		add filetype detection for this type
		define an "extract" action
	Extraction is done in $WRKDIR.  A subdirectory may be specified with
	the "extractdir" attribute on each archive.
		DISTFILES = foo-1.1.tgz foo_doc-1.1.tgz {extractdir = doc}

patch:
	apply patches not applied already
	$PATCHCMD defines the patch command, default "patch -p < "
		The patch file name is appended, unless "%s" appears in the
		string, then it's replaced by the file name.
	A "patchcmd" attribute on each patch file may specify a patch command
	that overrules $PATCHCMD.
	The patches are applied in $WRKDIR/$PATCHDIR (default: $WRKSRC).
	A "patchdir" attribute on each patch file may overrule the value of
	$PATCHDIR.
	
builddepend: check dependencies for configure and build
	Uses DEPEND_BUILD, unless disabled with AUTODEPEND=no

configure: configuration
	autoconf/imake/etc.  USE_IMAKE
	may be empty

build:
	run make or aap
		USE_GMAKE
		USE_BSDMAKE
		BUILDCMD=make foo	default: "aap"
	Done in $WRKDIR/$BUILDDIR, default: $WRKDIR/$WRKSRC

testdepend: check test dependencies
	Uses DEPEND_TEST.
	check if all required items are present
	try to install them automatically, unless disabled  AUTODEPEND=no
	This is skipped when "SKIPTEST=yes"

test:
	check if building was done properly
		TESTCMD=make testall	default: "aap test"
	This is skipped when "SKIPTEST=yes"
	Done in $WRKDIR/$TESTDIR, default: $WRKDIR/$WRKSRC

package: create binary package
	Two methods to select files to include:
	1. list of files below $WRKDIR, with "dest" attr where they end up
	   PACKFILES = $WRKSRC/bin/prog {dest = /usr/local/bin/prog}
	   		$WRKSRC/man/prog.1 {dest = usr/local/man/man1/prog.1}
	2. prog to fake-install into $PKGDIR, use all files there.
	   INSTALLCMD = "aap install DESTDIR=$PKGDIR"
	   INSTALLDIR in $WRKDIR   default is $WRKSRC
	   $PKGDIR/$PREFIX is where files end up
	generate packing list and other files for local package system
	execute pkg_create or equivalent

install: install the binary package
	in home dir or in system (require typing root password)
	execute pkg_add or equivalent
	Exception: This updates the "rundepend" and "installtest" targets
	after updating the post-install target.  This allows doing "aap
	install", which is a lot more obvious than "aap installtest".

rundepend: check runtime dependencies
	Check if all required items specified with $DEPEND_RUN are present and
	tries to install them automatically, unless $AUTODEPEND is "no".
	This is skipped if $SKIPRUNTIME is "yes".  The pre-rundepend and
	post-rundepend are still done, they should check $SKIPRUNTIME
	themselves.
	"aap rundepend" will _not_ cause previous steps to be updated.

installtest: test if the installed package works
	This is empty by default, specify a "do-installtest" target to
	actually do something.
	Note that when $SKIPRUNTIME is "yes" the dependencies have not been
	verified and running the application might not work.

deinstall: uninstall the binary package
	Execute pkg_delete or equivalent.
	Does not depend on other steps.

clean: delete all generated, unpacked, patched and CVS files
	not the downloaded files.
	Does not depend on other steps.

distclean: delete everything except the toplevel recipe
	Does not depend on other steps.

makesum: generate checksum file
	Generates a checksum file to be able the check if the fetched files
	were not corrupted.
	The generated file can be included into the port recipe.
	Does not depend on other steps.  The files must already be present.
	You can use "aap fetch --nofetch-recipe" to obtain the files, if
	needed (it obtains the files but not the recipes).

srcpackage: generate a package with recipe and source files
	Put main recipe and all downloaded files into an archive.  The
	resulting archive can be installed without downloading.
	Depends on the "fetch" target.


PORT DESCRIPTION

The text to describe the port is usually a page full of plain text.  Here is an
example:

	PORTDESCR << EOF
	This is the description of the port.

	See our website http://myport.org.
	EOF

In the rare situation that "EOF" actually appears in the text you can use
anything else, such as "THEEND".


USING AUTOCONF

The autoconf system is often used to configure C programs to be able to
compile them on any Unix system.  This section explains how to use autoconf
with A-A-P in a nice way.

A recipe that uses the generated configure script can start like this:

	$BDIR/config.h $BDIR/config.aap : \
				 configure config.arg config.h.in config.aap.in
		:sys ./configure `file2string("config.arg")`
		:move {force} config.h $BDIR/config.h
		:move {force} config.aap $BDIR/config.aap
	config.arg:
		:touch {exist} config.arg

	:update $BDIR/config.aap
	:include $BDIR/config.aap

What happens here is that the "config.aap" target is updated before any of the
building is done.  This is required, because running the configure script
will generate or update the "config.aap" file that influences how the building
is done.

The arguments for configure are stored in the "config.arg" file.  This
makes it easy to run configure again with the same arguments.  There should be
a "config.txt" file that explains all the possible configure arguments, with
examples that can be copied into "config.arg".  Example:

	# Select the library to be used for terminal access.  When omitted a
	# series of libraries will be tried.  Useful values:
		--with-tlib=curses
		--with-tlib=termcap
		--with-tlib=termlib

The user can now copy one of the example lines to his "config.arg" file.
Example:

	# select specific terminal library
		--with-tlib=termcap

Comment lines can be used, they must start with a "#".  Note: a comment after
an argument doesn't work, it will be seen as an argument.

When updating to a new version of the program, the same "config.arg" file
can still be used.  A "diff" between the old and the new "config.txt" will
show what configure arguments have changed.

"config.aap" and "config.h" are put in $BDIR, because they depend on the
current system.  They might also depend on the variant to be build.  In that
case the ":variant" statement must be before the use of $BDIR.  However, if
the variant is selected by running configure, the variant must come later.
"config.aap" and "config.h" are then updated when selecting another variant.

For a developer there also needs to be a method to generate the configure
script from configure.in.  This needs to be done even before configure is run.
Prepending this to the example above should work:

	configure {distributed} : configure.in
		:del {force} config.cache config.status
		:sys autoconf
	:update configure

The "{distributed}" attribute on the target indicates that the "configure"
file is included in the distribution.  When "configure" was not built (there
is no old signature for it) but it does exist, it doesn't need to be build.
This is useful to avoid running autoconf after unpacking sources that already
include the up-to-date configure script.  But when "configure.in" changes
after executing the recipe once, configure will be built, because the
signatures will be remembered when executing the recipe.  When changing
configure.in before executing the recipe (or after deleting the recipe file
manually) no building will be done, the change will not be noticed.

The "config.cache" and "config.status" files are deleted, because they may
become invalid when generating a new configure script.