A-A-P home page | A-A-P Recipe Executive |
Prev | User Manual | Next

## Chapter 22. Porting an Application

Porting an application means starting with the original sources and changing them a little bit to make the application compile and install on a specific system. An Aap port recipe offers a simple way to create a port, because all the standard work does not need to be specified.

NOTE: not all features mentioned here fully work. Make sure you test your port recipe before publishing it.

## The Port Recipe

The basic idea is that you assign values to a number of predefined variables. Aap will then generate the steps for building and installing the package, using the values you have specified. The presence of the "PORTNAME" variable triggers Aap to handle the recipe as a port recipe. The list of variables is in the next section.

This is thee list of steps performed when executing Aap without arguments, in this order:

dependcheck | early check to see if dependencies can be met; abort without doing anything if something is known to fail
fetchdepend | handle dependencies for fetch and checksum
fetch | get the required files
checksum | check if the files have correct checksums
extractdepend | handle dependencies for extract and patch
extract | unpack archives
patch | apply patches
builddepend | handle dependencies for configuring and building
config | do pre-building configuration
build | build
testdepend | handle dependencies for testing
test | check if building was done properly
package | create a binary package
install | install the binary package
rundepend | handle runtime dependencies
installtest | test if the package fully works and was installed properly

For each step a dependency with build commands is added. The purpose of each step is further explained below.

| Meaning of "dependency"
The term "dependency" is ambiguous here. You should be able to guess from the context whether it is used for a dependency of one software package on another package, or a dependency of a target file on a source file.

You can do part of the work by starting Aap with one of the step names. The steps before it will also be executed if necessary. For example, "aap package" will do all the steps necessary to generate the binary package but not install it.

If your port requires non-standard stuff, you can specify your own build commands. You can replace the normal step, prepend something to it and append something to it:

do-XXX | replace the body of a step
pre-XXX | do something before a step
post-XXX | do something after a step

Example:

           post-test:
              # delete the directory used for testing
              :del {r}{f} $WRKDIR/testdir

## Variables

Various variables need to be set to specify properties of the port.

variable | used for | example value
--- | --- | ---
PORTNAME | name of the port | "foobar"
PORTVERSION | app version number | "3.8alpha"
PORTREVISION | port patchlevel (optional) | "32"
CVSMODULES | names of CVS modules to checkout (optional) | Exec
MAINTAINER_NAME | maintainer name (optional) | John Doe
MAINTAINER | maintainer e-mail (optional) | john@foobar.org
PORTCOMMENT | short description | get foo into the bar
PORTDESCR | long description | blah blah blah
IS_INTERACTIVE | requires user input (optional) | yes or no

Variables that can be used by the port recipe:

variable | used for |  | default value
--- | --- | --- | ---
WRKDIR | directory all files are extracted in and the building is done in |  | "work"
DISTDIR | directory where downloaded distfiles are stored |  | "distfiles"
PATCHDISTDIR | directory where downloaded patches are stored |  | "patches"
PKGDIR | directory where files are stored before creating a package |  | "pack"

Variables that may be set by the port recipe, defaults are set only after reading the recipe:

variable | used for | default value
--- | --- | ---
WRKSRC | Directory inside $WRKDIR where the unpacked sources end up. This should be the common top directory in the unpacked archives. When using CVS it is always set to $CVSWRKSRC (also when $WRKSRC was already set). | $PORTNAME-$PORTVERSION
CVSWRKSRC | Directory inside $WRKDIR where files obtained with CVS end up. | the first entry in $CVSMODULES
PATCHDIR | Directory inside $WRKDIR where patches are to be applied. Can be overruled for a specific patch with a "patchdir" attribute. | $WRKSRC
BUILDDIR | Directory inside $WRKDIR where building is to be done. | $WRKSRC
TESTDIR | Directory inside $WRKDIR where testing is to be done. | $WRKSRC
INSTALLDIR | Directory inside $WRKDIR where $INSTALLCMD is to be done. | $WRKSRC
CONFIGURECMD | Set to the command used to configure the application. Usually "./configure". | nothing
BUILDCMD | Set to the command used to build the application. Usually just "make". | "aap"
TESTCMD | Set to the command used to test the application. Usually "make test". | "aap test"
INSTALLCMD | Set to the command used to do a fake install of the application. | "aap install DESTDIR=$PKGDIR"

## Dependency Format

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

NOTE: Although you can currently specify dependencies, the code for checking them has not been implemented yet! Thus the user will have to figure it out by himself...

Items are normally white space 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:

            DEPENDS = (foo bar) | foobar    # Either both "foo" and "bar" or "foobar"
            DEPENDS = foo bar | foobar      # Illegal
            DEPENDS = 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.

NOTE: Although you can currently specify dependencies and conflicts, the code for checking them has not been implemented yet! Thus the user will have to figure it out by himself...

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 in a previous invocation of Aap 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 member in $CVSMODULES).
  Also obtain $CVSDISTFILES if defined.
  Also obtain $CVSPATCHFILES if defined.
  Use a post-fetch target if directories need to be renamed.

  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 archives in the right place. Use $EXTRACT_ONLY if defined, otherwise $DISTFILES or $CVSDISTFILES when CVS was used.

  Uses the "extract" action. To extract a new type of archive:

  add filetype detection for this type of archive
  define an "extract" action for this filetype

  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".

config

  Perform configuration.

  Executes the command specified with CONFIGURECMD. Usually autoconf, imake, etc. May be empty.

build

  Run the command specified with BUILDCMD. When empty "aap" is used. Useful values are "gmake", "make", etc. An argument may be included. Example: "BUILDCMD=make foo"

  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.

  Executes TESTCMD. When it is empty "aap test" is used. Example: "TESTCMD=make testall"

  This is skipped when "SKIPTEST=yes" Done in $WRKDIR/$TESTDIR, default: $WRKDIR/$WRKSRC

package

  Create a package with selected files, usually including the compiled program.

  There are two methods to select files to be included in the package:

  1. Specify the list of files below $WRKDIR, with a "dest" attribute where they should end up. Assign the list to $PACKFILES. Example:

                 PACKFILES = $WRKSRC/bin/prog {dest = /usr/local/bin/prog}
                             $WRKSRC/man/prog.1 {dest = usr/local/man/man1/prog.1}

  2. Specify a command to fake-install into $PKGDIR and use all files that end up there. Set $INSTALLCMD to the command to be used. Example:

                 INSTALLCMD = "aap install DESTDIR=$PKGDIR"

     Set INSTALLDIR to the directory inside $WRKDIR where the files are put. Default is $WRKSRC. $PKGDIR/$PREFIX is where files end up.

  A packing list is generated with the files that exist in the package. Then "pkg_create" is executed to actually create the package. Arguments are given such that $PORTDESCR is used as the description of the package and $PORTCOMMENT for a short explanation of what the package is for.

install

  Install the binary package.

  This executes the "pkg_add" command in a separate shell. You are asked to type the root password. This is reasonably safe, since the shell is only connected to Aap and it can only install a package.

  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.

uninstall

  Uninstall the binary package. Not implemented yet!

  Execute pkg_delete or equivalent. Does not depend on other steps.

clean

  Delete all generated, unpacked, patched and CVS files.

  Does not delete the downloaded files. Does not depend on other steps. Does not clean packages this one depends on.

distclean

  Delete everything except the toplevel recipe. After this all steps must be redone.

  Does not depend on other steps. Does not clean packages this one depends on.

makesum

  Generates a "do-checksum" dependency that checks if the fetched files were not corrupted.

  If the recipe already contained a "do-checksum" dependency that was generated it is replaced. Otherwise a new one is appended. Do not change the markers before and after the "do-checksum" dependency, otherwise you end up with two of these when doing "aap makesum" again.

  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. Not implemented yet!

  Puts the 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.
            A very important application indeed.

            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".

Prev | Up | Next
Chapter 21. Using Python | Contents | Chapter 23. Automatic Configuration