Porting an Application

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

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

Prev | Contents | Next
Using Python | Up | Debugging a Recipe