Porting applications

Contributed by &a.jkh;. Here are the guidelines one should follow in creating a new port for FreeBSD 2.x . This documentation will change as this process is progressively refined, so watch this space for details. The ${..} variable names you see in this document all refer to various user-overridable defaults used (and documented) by /usr/share/mk/bsd.port.mk. Please refer to that file for more details. Before starting the port

Note: Only a fraction of the overridable variables are mentioned in this document. Most (if not all) are documented at the start of the bsd.port.mk file which can be found in /usr/share/mk. This file uses a non-standard tab setting. Emacs should recognise the setting on loading the file. vi or ex can be set to using the correct value by typing ":set tabstop=4" once the file has been loaded. - &a.gpalmer; You may come across code that needs modifications or conditional compilation based upon what version of UNIX it's running under. If you need to make such changes to the code for conditional compilation, make sure you make the changes as general as possible so that we can back-port code to FreeBSD 1.x systems and cross-port to other BSD systems such as 4.4bsd from CSRG, BSD/386, 386BSD and NetBSD. The preferred way to tell 4.3BSD/Reno and newer versions of the BSD code apart is by using the "BSD" macro defined in <sys/param.h>. Hopefully that file is already included; if not, add the code: #ifdef _HAVE_PARAM_H #include #endif to the proper place in the .c file and add -D_HAVE_PARAM_H to the CFLAGS in the Makefile. Then, you may use: #if (defined(BSD) && (BSD >= 199103)) to detect if the code is being compiled on a 4.3 Net2 code base or newer (e.g. FreeBSD 1.x, 4.3/Reno, NetBSD 0.9, 386BSD, BSD/386 1.0). Use: #if (defined(BSD) && (BSD >= 199306)) to detect if the code is being compiled on a 4.4 code base or newer (e.g. FreeBSD 2.x, 4.4, NetBSD 1.0, BSD/386 1.1). Use sparingly: __FreeBSD__ is defined in all versions of FreeBSD. Use it if the change you are making ONLY affects FreeBSD. Porting gotchas like the use of sys_errlist[] vs strerror() are Berkeleyisms, not FreeBSD changes. In FreeBSD 2.x, __FreeBSD__ is defined to be 2. In earlier versions, it's 1. If you need to tell the difference between a FreeBSD 1.x system and a FreeBSD 2.x system, usually the right answer is to use the BSD macros described above. If there actually is a FreeBSD specific change (such as special shared library options when using 'ld') then it's OK to use __FreeBSD__ and "#if __FreeBSD_ > 1" to detect a FreeBSD 2.x system. In the dozens of ports that have been done, there have only been one or two cases where __FreeBSD__ should have been used. Just because an earlier port screwed up and used it in the wrong place doesn't mean you should do so too. Doing the port

NOTE: If your sources work without change under FreeBSD, skip to the next section. Get the original sources (normally) as a compressed tarball (<foo>.tar.gz or <foo>.tar.Z) and copy it into ${DISTDIR}. Always use mainstream sources when and where you can, and don't be tempted to patch a tarball 2 or 3 revisions ahead just to save yourself trouble. The idea is that the ports collection should be usable even with all of ${DISTDIR} blown away, which is to say that it should be possible for a user to repopulate all of ${DISTDIR} with publically available files. Unpack a copy of the tarball in a private directory and make whatever changes are necessary to get the port to compile properly under FreeBSD 2.0. Keep careful track of everything you do, as you will be automating the process shortly. Everything, including the deletion, addition or modification of files should be doable using an automated script or patch file when your port is finished. If your port requires significant user interaction/customization to compile or install, you should take a look at one of Larry Wall's classic Configure scripts and perhaps do something similar yourself. The goal of the new ports collection is to make each port as `plug-and-play' as possible for the end-user while using a minimum of disk space. Carefully consider the list of patches, shell commands or user queries necessary for customizing the port, then, making sure you understand the following thoroughly, go for it. The sequence of events you need to understand is that which occurs when the user first types `make' in your port's directory, and you may find that having bsd.port.mk in another window while you read this really helps to understand it: Sequence of events: The pre-fetch and fetch targets are run. The fetch target is responsible for making sure that the tarball exists locally in ${DISTDIR}. The pre-fetch target hook is optional. If fetch cannot find the required files in ${DISTDIR} it will look up the URL ${MASTER_SITES}, which can be set in the Makefile or allowed to default to the Walnut Creek CDROM archive site. It will then attempt to fetch the named distribution file with ${NCFTP}, assuming that the requesting site has direct access to the Internet. If that succeeds, it will save the file in ${DISTDIR} for future use and proceed. The pre-extract target hook, if it exists, is run. The extract target, if not disabled, is run. It looks for your ports' distribution file in ${DISTDIR} (typically a gzip'd tarball) and unpacks it into a temporary directory. The pre-configure target hook is run. The configure target is run. This can do any one of many different things. First, if any patches are found in the ${PATCHDIR} subdirectory, they are applied at this time in alphabetical order. Next, a series of scripts, if detected, are run in the following order: ${SCRIPTDIR}/pre-configure ${SCRIPTDIR/configure or ${WRKSRC}/configure if ${HAS_CONFIGURE} is set. If ${USE_IMAKE} is set, an xmkmf command is done. ${SCRIPTDIR}/post-configure As you can see, it's possible to do just about anything to your port, in a variety of stages! The pre-build target hook is run. The build target is run. This is responsible for decending into the ports' private working directory (${WRKSRC}) and building it. If ${USE_GMAKE} is set, GNU make will be used, otherwise the system ${MAKE}. In the preparation of the port, files that have been added or changed can be picked up with a recursive diff for later feeding to patch. This is the easiest kind of change to make as it doesn't involve any mucking around with configuration files. Each set of patches you wish to apply should be collected into a file named "patch-<xx>" where <xx> denotes the sequence in which the patches will be applied - these are done in alphabetical order, thus "aa" first, "ab" second and so on. These files should be stored in ${PATCHDIR}, from where they will be automatically applied. All patches should be relative to ${WRKSRC} (generally the directory your port's tarball unpacks itself into, that being where the make is done). Include any additional customization commands to your `configure' script and save it to ${SCRIPTDIR}/configure. Add your port to the Makefile one level above it so that it will be made automatically. Always try to install relative to ${PREFIX} in your Makefiles. This will normally be set to /usr/local, though it can be can be reassigned in your Makefile or in the users environment. Not hardcoding /usr/local anywhere in your installation will make the port much more flexible and cater to the needs of other sites. Note that this doesn't count for package `packing list' files since they have their own scheme for relocating themselves and can be left independant of ${PREFIX} unless the package is one that hardcodes itself to a compiled-in location. If your port requires user input to build, configure or install, then set IS_INTERACTIVE in your Makefile. This will allow "overnight builds" to progress past your port if the user sets the variable BATCH in his environment (and if the user sets the variable INTERACTIVE, then only those ports requiring interaction are built). For more details on any of this (since it may not be clear at first reading), examine an existing port and read the contents of /usr/share/mk/bsd.port.mk; you'll see that it's not as difficult as it sounds! Configuring the Makefile

Configuring the Makefile is pretty simple, and again I suggest that you look at existing examples before starting. Consider the following problems in sequence as you design your new Makefile: Does it live in ${DISTDIR} as a standard gzip'd tarball? If so, you can go on to the next step. If not, you should look at overriding any of the ${EXTRACT_CMD}, ${EXTRACT_ARGS}, ${EXTRACT_SUFX}, or ${DISTFILE} variables, depending on how alien a format your port's distribution file is. In the worst case, you can simply create your own `extract' target to override the default, though this should be rarely, if ever, necessary. If you do find it necessary to do your own, your extract target should take care to "leave tracks" for itself so that files are not unnecessarily extracted twice---see the default extract rule in bsd.port.mk for an example of this. If your port is integrated into the ports directory directly (original sources are already part of FreeBSD), you may also consider simply setting NO_EXTRACT and dispensing with the idea of a distribution file altogether. You should set ${DISTNAME} to be the base name of your port. The default rules expect the distribution file list (${DISTFILES}) to be named ${DISTDIR}/${DISTFILE}${EXTRACT_SUFX} by default which, if it's a normal tarball, is going to be something like: foozolix-1.0.tar.gz For a setting of "DISTNAME=foozolix-1.0" The default rules also expect the tarball(s) to extract into a subdirectory called ${WRKDIR}/${DISTNAME}, e.g. "/foozolix-1.0/" All this behavior can be overridden, of course, it simply represents the most common time-saving defaults. For a port requiring multiple distribution files, simply set ${DISTFILES} explicitly. If only a subset of ${DISTFILES} are actual extractable archives, then set them up in ${EXTRACT_ONLY}, which will override the ${DISTFILES} list when it comes to extraction. If your package uses GNU make, set "USE_GMAKE=yes". If your package uses GNU configure, set "GNU_CONFIGURE=yes". If you want to override the default GNU configure arguments from `i386--freebsd' to something else, set those arguments in ${GNU_CONFIGURE_ARGS}. If your package uses imake (e.g. is an X application that has an Imakefile), then set "USE_IMAKE=yes". This will cause the configure stage to automatically do an xmkmf and then a `make Makefiles'. If you have a URL pointing at the the original tarball, record the directory containing the tarball in ${MASTER_SITES}. This will provide a backup site, as well as a direct pointer to the original source location. The make macros will currently try to use this specification for grabbing the distribution file with ${NCFTP} if they can't find it already on the system. See some of the other ports for examples. Due to a problem in some of the ports, 2.0 was distributed with a setting which meant ports that have ${USE_IMAKE} set do not install their manpages by default. Although -current has the logic reversed, for compatability with 2.0 systems (at least until 2.1 comes out) you should set "INSTALL_MANPAGES=yes". For complete forward compatability, if the port doesn't understand the "install.man" target, "NO_INSTALL_MANPAGES=yes" should be set (which conforms with the current logic in bsd.port.mk) Don't forget to include <bsd.port.mk> at the bottom. That should do it! Do's and Dont's

Don't leave anything valuable lying around in ${WRKDIR}, `make clean' will nuke it completely! If you need auxilliary files that aren't scripts or patches, put them in ${FILESDIR}. Do install package information, if possible. It would sure be nice if `make package' worked for the whole ports tree this time. Do look at existing examples and the bsd.port.mk file before asking me questions! ;-) Do ask me questions if you have any trouble! Don't just beat your head against a wall! :-) Don't rely on custom utilities in your local configure script---they may not be there on the user's system! If you really need something else to be installed before you can work, detect this from your configure script, print a helpful message and exit with a non-zero status! At least you'll have given the user some idea of what's needed. If the custom utility or package is actually part of the ports tree, then set a pointer to it in your DEPENDS variable---the port structure will ensure that all DEPENDS targets are built first. Do send applicable changes/patches to the original author/maintainer for inclusion in next release of the code. This will only make your job that much easier for the next release.