## Contributing to FreeBSD: Creating a Port ## Jim Mock Ok, so you're surfing the 'net and you find an app that you really like. You decide to save yourself some time and install the port from the ports collection instead. Whoops, there isn't a port, now what? Well, first, compile the source and make sure it works. After that, if you think other people will like it, you can attempt to port it for inclusion in the ports collection yourself. As I said, make sure the app is working properly before you attempt to make a port of it. This article will attempt to get you on your way to creating your first port. This example is a very simple one. It assumes that the source compiled with no changes required for it to work on your FreeBSD box. I may write a follow-up article to this in the next issue which will show how to create a port that doesn't compile out of the box and requires a patch in order to compile. Note: The URLs in this article may change by the time you read this as the Handbook is updated daily. If the URL isn't valid, you can always get to it by going to the Handbook table of contents at http://www.freebsd.org/handbook/handbook.html. Creating the Port The first thing you'll need to do is get the original tarball and put it in the ${DISTDIR}, which is /usr/ports/distfiles by default. First, create a directory for the port. It doesn't really matter where you create it, but you'll need it because that's where the Makefile and other things needed for the port will go. I have a directory in my home directory.. /home/jim/freebsd/ports. I put ports that I'm working on there. This port in particular is in /home/jim/freebsd/ports/wmpinboard. The next thing you need to do is create a Makefile. To do so, cd to the directory and type pico Makefile, replacing pico with the editor of your choice. Writing the Makefile Here's an example Makefile: # New ports collection makefile for: wmpinboard # Version required: 0.7 # Date created: 17 January 1999 # Whom: Jim Mock # # $Id: porting.txt,v 1.1 2000/02/16 08:07:45 jim Exp $ # DISTNAME= wmpinboard-0.7 CATEGORIES= misc deskutils MASTER_SITES= http://www.tu-ilmenau.de/~gomar/stuff/wmpinboard/ MAINTAINER= jim@phrantic.phear.net LIB_DEPENDS= Xpm.4:${PORTSDIR}/graphics/xpm WRKSRC= ${WRKDIR}/wmpinboard.app USE_IMAKE= yes NO_INSTALL_MANPAGES= yes do-install: ${INSTALL_PROGRAM} ${WRKSRC}/wmpinboard ${X11BASE}/bin .include Don't worry about the $Id: porting.txt,v 1.1 2000/02/16 08:07:45 jim Exp $ line. It's filled out automatically when the port is imported into the ports tree. Here's an explanation of the above. Comments are below each line. # New ports collection makefile for: wmpinboard The above line is the header. It's there to make it easy to identify the port. # Version required: 0.7 This should be changed to the new version whenever a port is upgraded. # Date created: 17 January 1999 This is the date the Makefile was originally created. Don't change this line if updating a port. # Whom: Jim Mock This is the person who wrote the original Makefile and did the original port. This should not be changed if upgrading a port. # # $Id: porting.txt,v 1.1 2000/02/16 08:07:45 jim Exp $ # Leave this as is. It will be replaced with an ID string by CVS when the port is committed to the repository. DISTNAME= wmpinboard-0.7 CATEGORIES= misc deskutils MASTER_SITES= http://www.tu-ilmenau.de/~gomar/stuff/wmpinboard/ These three sections are to describe the port itself and where the tarball should be fetched from. The DISTNAME is the name of the tarball (before the .tar.gz extension) it always comes first, followed by package name (if necessary). The second example will show this. CATEGORIES are the categories the port should be put into in the ports tree. This port falls into two categories, misc, and deskutils. MASTER_SITES is the ftp site(s) (or web server as in this case) where the tarball can be found. This can have multiple entries. MAINTAINER= jim@phrantic.phear.net This is mandatory. It's the email address of a person that users can contact for questions and or bug reports. This person should be the porter or someone who can forward questions to the original porter promptly. If you really don't want your email address here, use the ports mailing list address (ports@freebsd.org). LIB_DEPENDS= Xpm.4:${PORTSDIR}/graphics/xpm The dependencies can be empty if your port doesn't depend on another in order to build or run. In this case, wmpinboard depends on xpm. WRKSRC= ${WRKDIR}/wmpinboard.app The WRKSRC is used if the tarball is extracted to something other than the ${DISTNAME}. In this case it uncompresses to a wmpinboard.app directory instead of wmpinboard-0.7. USE_IMAKE= yes This is used if it's an X application and requires 'xmkmf -a' to be run. NO_INSTALL_MANPAGES= yes This is for ports using imake that don't like the install.man target. do-install: ${INSTALL_PROGRAM} ${WRKSRC}/wmpinboard ${X11BASE}/bin This tells where to install the wmpinboard binary. It takes it from the ${WRKSRC} directory (which is the work directory inside the port directory that's created when make is run), and in this case installs it to ${X11BASE}/bin (/usr/X11R6/bin, /usr/X11R6 is the X11BASE). .include This goes at the end of every Makefile for any ports. For a more detailed examples, you can look at the Makefiles for the ports in /usr/ports, and at bsd.port.mk in either /usr/share/mk or /usr/ports/Mk depending on when you last updated your ports collection. Writing the description files Each port requires three description files. They are COMMENT, DESCR, and PLIST. Each should be created in a pkg subdirectory of the port directory. For example, /home/jim/freebsd/ports/wmpinboard/pkg. COMMENT This is a one line description of the port. Please don't include the package name or version number of the software in the COMMENT. Here's the one I used for wmpinboard: Post-it notes for the WindowMaker dock or AfterStep Wharf. DESCR This is a longer description of the port. A few paragraphs that explain what the port does is plenty (most are only a paragraph or so). This isn't a manual or a detailed description on how to use or compile the port. If the port has an official homepage, you should list it here. It's also recommended that you sign the end of the DESCR file. Here's the DESCR from the port of aterm I did: aterm is a color vt102 terminal emulator, based on rxvt 2.4.8 with additions for fast transparency. It was created with AfterStep users in mind, but is not tied to any libraries, and can be used anywhere. - Jim PLIST This file lists all of the files installed by the port. It's also called the 'packing list' because the package is created by packing the files listed in PLIST. The pathnames are relative to the installation prefix (usually /usr/local or /usr/X11R6). Don't list any man pages here. Here's an example from the ascd port I did: bin/ascd share/doc/ascd/README @dirrm share/doc/ascd Looking at the man page for pkg_create(1) will give you more details on packing lists. Be sure to list all the files, but not the name directories in the list. Also, if the port creates directories during the installation, use @dirrm lines to remove them when the port is deleted. It's also recommended that you keep the files listed alphabetically because it makes upgrading the port much easier. Creating the checksum file To create the checksum for your port, be sure the tarball is in /usr/ports/distfiles and that you're in the port directory. Once you've assured the tarball is there, and you're where you should be, type 'make makesum'. The port will then generate a files directory with the md5 checksum file in it. Testing your port You should always test your port before submitting it. It's a good idea to have other people to test it as well to see if there's any problems. I've had ports compile fine on my box, but when others tested them they were broken. It's very easy to miss dependencies if you already have the dependency installed, so the more people who test your port, the more likely the chances of finding an error are. Make sure that the port rules do exactly what you want them to do, including creating the package. Here are the important things to verify: PLIST doesn't contact anything not installed by your port PLIST contains everything installed by your port your port can be installed multiple times using make reinstall your port cleans up after itself when make deinstall is run This is the recommended order of testing: 1) make install 2) make package 3) make deinstall 4) pkg_add 'package-name' 5) make deinstall 6) make reinstall 7) make package Make sure there aren't any warning issued in any of the package and deinstall stages. After doing step 3, make sure any directories created by the port are deleted, and after doing step 4, try running the software to make sure it works correctly if installed from a package. Using portlint to check your port It's always a very good idea to run portlint on your port to make sure no errors are found. You can find portlint in the ports collection in /usr/ports/devel/portlint. Be sure there are no error generated when running portlint. If there are, please correct them before submitting the port. Submitting the port Once you're satisfied that your port works, the only thing left to do is to get it put into the ports tree. When submitting a port, the work directory or the package-name.tgz are NOT needed. Please delete them before performing the next step. Also, please read the "Do's and Don'ts" of porting at http://www.freebsd.org/handbook/handbook.html#porting:dads. Once you've deleted the package, and run make clean to remove the work directory, run "shar `find port_dir` and include the output in a bug report and send it in using send-pr. See the man page for send-pr(1) for more info on send-pr. I usually redirect the output of shar to a text file that I import into the bug report, like so: [jim@corp:~/freebsd/ports]$ shar `find wmdate` > wmdate.txt It makes it much easier to include in the bug report if you can just import it as a text file. If the uncompressed port is larger than 20KB, you should compress it into a tarball and use uuencode(1) before including it in the bug report. Be sure to classify the bug report as category 'ports' and class 'change-request'. Do NOT mark the report 'confidential'! To recap, don't include the orignal source tarball from /usr/ports/distfiles, the work directory, or the package. Once your port is submitted, it will be looked at, and if all is ok, it will be put into the ports tree. You'll also get your name listed in the list of 'Additional FreeBSD contributors' in the Handbook.. pretty cool dontcha think? =) That's all there is to it. I suggest starting with something simple (most of the dockapps for WindowMaker are a good place to start, they're pretty easy), and work your way up to more difficult ports once you start to get the hang of it. As always, the docs in the Handbook, the existing ports (you've got over 2,000 Makefiles to use as examples if you have the ports collection installed), and the bsd.port.mk file are your friend. It's also a good idea to subscribe to the ports mailing list (ports@freebsd.org) and post questions if you really get stuck. Please read through the documentation first though.. you might be able to answer your own question. Happy porting, Jim