Brian Robert Callahan
academic, developer, with an eye towards a brighter techno-social life
By popular demand, I have unearthed my first OpenBSD port. I will review it and discuss what I would do differently now after ten years of working on ports.
I will have a YouTube video reviewing the port up in a few days. I'll update this post once it's up.
The first port I ever sent was Beret, a 2D puzzle-platformer game. I guess even from the beginning I was helping out thfr@ in his #PlayOnBSD project. I cannot find the very first attempt at it, as it seems I linked a tarball from a server that has since gone to the great bitbucket in the sky. So I have the first tarball I posted instead.
Makefile
The most "important," or at least meaty, part of any port is usually the Makefile
and that is true here as well. Let's take a look at it. This is as I posted it, mistakes and all.
# $OPENBSD$ COMMENT= 2D puzzle-platformer game DISTNAME= beret-1.2.1 CATEGORIES= games x11 HOMEPAGE= http://kiwisauce.com/beret/ MAINTAINER= Brian Callahan <bcallah@devio.us> # LGPLv3 PERMIT_PACKAGE_CDROM= Yes PERMIT_PACKAGE_FTP= Yes PERMIT_DISTFILES_CDROM= Yes PERMIT_DISTFILES_FTP= Yes WANTLIB += c m SDL SDL_image SDL_mixer WANTLIB += SDL_ttf pthread MASTER_SITES= http://devio.us/~bcallah/ LIB_DEPENDS= converters/libiconv \ devel/sdl \ devel/sdl-image \ devel/sdl-mixer \ devel/sdl-ttf \ print/freetype MAKE_FLAGS= CC="${CC}" CFLAGS="${CFLAGS}" CFLAGS+= -I/usr/local/include \ -I/usr/local/include/SDL -Wall -g do-install: ${INSTALL_PROGRAM} ${WRKSRC}/beret ${PREFIX}/bin ${INSTALL_DATA_DIR} ${PREFIX}/share/doc/beret ${INSTALL_DATA} ${WRKSRC}/lgpl-3.0.txt ${PREFIX}/share/doc/beret ${INSTALL_DATA} ${WRKSRC}/OFL.txt ${PREFIX}/share/doc/beret ${INSTALL_DATA} ${WRKSRC}/FONTLOG.txt ${PREFIX}/share/doc/beret ${INSTALL_DATA} ${WRKSRC}/README.txt ${PREFIX}/share/doc/beret ${INSTALL_DATA_DIR} ${PREFIX}/share/beret ${INSTALL_DATA} ${WRKSRC}/AveriaSans-Regular.ttf ${PREFIX}/share/beret ${INSTALL_DATA_DIR} ${PREFIX}/share/beret/images ${INSTALL_DATA} ${WRKSRC}/images/* ${PREFIX}/share/beret/images ${INSTALL_DATA_DIR} ${PREFIX}/share/beret/music ${INSTALL_DATA} ${WRKSRC}/music/* ${PREFIX}/share/beret/music ${INSTALL_DATA_DIR} ${PREFIX}/share/beret/rooms ${INSTALL_DATA} ${WRKSRC}/rooms/* ${PREFIX}/share/beret/rooms ${INSTALL_DATA_DIR} ${PREFIX}/share/beret/sfx ${INSTALL_DATA} ${WRKSRC}/sfx/* ${PREFIX}/share/beret/sfx .include <bsd.port.mk>
OK, so things have changed in the interim decade. I am going to fix up this Makefile
to fit into today's ports infrastructure, since you cannot build the port as-is. What needs to change? Fortunately not too much. The PERMIT_PACKAGE
lines have been simplified. We used to have all these permutations when we shipped CDs. But today that no longer happens and it has been streamlined to a single PERMIT_PACKAGE
line. So let's do that to make our lives a little easier.
# $OPENBSD$ COMMENT= 2D puzzle-platformer game DISTNAME= beret-1.2.1 CATEGORIES= games x11 HOMEPAGE= http://kiwisauce.com/beret/ MAINTAINER= Brian Callahan <bcallah@devio.us> # LGPLv3 PERMIT_PACKAGE = Yes WANTLIB += c m SDL SDL_image SDL_mixer WANTLIB += SDL_ttf pthread MASTER_SITES= http://devio.us/~bcallah/ LIB_DEPENDS= converters/libiconv \ devel/sdl \ devel/sdl-image \ devel/sdl-mixer \ devel/sdl-ttf \ print/freetype MAKE_FLAGS= CC="${CC}" CFLAGS="${CFLAGS}" CFLAGS+= -I/usr/local/include \ -I/usr/local/include/SDL -Wall -g do-install: ${INSTALL_PROGRAM} ${WRKSRC}/beret ${PREFIX}/bin ${INSTALL_DATA_DIR} ${PREFIX}/share/doc/beret ${INSTALL_DATA} ${WRKSRC}/lgpl-3.0.txt ${PREFIX}/share/doc/beret ${INSTALL_DATA} ${WRKSRC}/OFL.txt ${PREFIX}/share/doc/beret ${INSTALL_DATA} ${WRKSRC}/FONTLOG.txt ${PREFIX}/share/doc/beret ${INSTALL_DATA} ${WRKSRC}/README.txt ${PREFIX}/share/doc/beret ${INSTALL_DATA_DIR} ${PREFIX}/share/beret ${INSTALL_DATA} ${WRKSRC}/AveriaSans-Regular.ttf ${PREFIX}/share/beret ${INSTALL_DATA_DIR} ${PREFIX}/share/beret/images ${INSTALL_DATA} ${WRKSRC}/images/* ${PREFIX}/share/beret/images ${INSTALL_DATA_DIR} ${PREFIX}/share/beret/music ${INSTALL_DATA} ${WRKSRC}/music/* ${PREFIX}/share/beret/music ${INSTALL_DATA_DIR} ${PREFIX}/share/beret/rooms ${INSTALL_DATA} ${WRKSRC}/rooms/* ${PREFIX}/share/beret/rooms ${INSTALL_DATA_DIR} ${PREFIX}/share/beret/sfx ${INSTALL_DATA} ${WRKSRC}/sfx/* ${PREFIX}/share/beret/sfx .include <bsd.port.mk>
OK, let's start from the top and work our way down.
Our first issue in on the very top line. The RCS ID should read $OpenBSD$
. Not a huge problem, but needs to be fixed.
One important style tweak that you may have noticed I did with the new PERMIT_PACKAGE
line: putting a space after each variable name. I would highly recommend for all new ports that be done.
Moving on, I would make the license marker more exacting. The current tag, LGPLv3
is slightly ambiguous: it could mean LGPLv3 only or it could mean LGPLv3 or later. For Beret, it is LGPLv3 only, so that's what I would tweak the license marker to.
In the LIB_DEPENDS
list, which informs the ports system the shared libraries also found in ports that are linked into this program, and thus are needed on the system at both build time and run time, there seem to be extra libraries. Both converters/libiconv
and print/freetype
do not appear in the WANTLIB
list, which is the list of all shared libraries this ports needs, so that tells me that either these libraries are not needed or the WANTLIB
list is incorrect. We will learn which of these is the case once we have successfully built the port. For now, let's assume they are extra and remove them. If we're wrong about that, we'll find out soon enough and the fix is easy enough: add them back.
Additionally, the devel/sdl
entry is also extraneous. It will get pulled in by all of the SDL sub-libraries.
The next tweak I would make are to combine the MAKE_FLAGS
and CFLAGS
lines. There is a utility, sdl-config
that can be used to get the correct CFLAGS
for SDL programs. So I would compress these two lines into the following.
MAKE_FLAGS = CC="${CC}" CFLAGS="${CFLAGS} `sdl-config --cflags`"
Shorter and I suppose more pedantically correct.
The last tweak I would make would be to put a comment about why we have the do-install
routine. In this case, it is because upstream did not write an installation routine, so we have to do it ourselves.
By the way, in case you didn't know, there are pre-
, do-
, and post-
routines for all the major steps of the build process. The pre-
and post-
run immediately before or immediately after the suffixed step, while do-
replaces the step with whatever is specified. Note that post-
of a step is run before pre-
of the subsequent step, so post-configure
will run before pre-build
.
Looking over the do-install
routine, I noticed that a font is being installed. It is not always the case, but it is often enough the case that fonts are licensed under a different license from the rest of the code, usually the SIL Open Font License. I checked and indeed the font is licensed under the SIL OFL. We should notate that in the license marker.
Oh, and that MASTER_SITES
doesn't exist anymore. The current port uses a server that does exist. Let's go ahead and change it too to make our lives easier.
Let's rewrite our Makefile
with all these changes.
# $OpenBSD$ COMMENT = 2D puzzle-platformer game DISTNAME = beret-1.2.1 CATEGORIES = games x11 HOMEPAGE = http://kiwisauce.com/beret/ MAINTAINER = Brian Callahan <bcallah@devio.us> # LGPLv3 only # AveriaSans-Regular.ttf: SIL Open Font License PERMIT_PACKAGE = Yes WANTLIB += c m SDL SDL_image SDL_mixer WANTLIB += SDL_ttf pthread MASTER_SITES = https://mirrors.nycbug.org/pub/distfiles/ LIB_DEPENDS = devel/sdl-image \ devel/sdl-mixer \ devel/sdl-ttf MAKE_FLAGS= CC="${CC}" CFLAGS="${CFLAGS} `sdl-config --cflags`" # Upstream does not provide an installation routine. do-install: ${INSTALL_PROGRAM} ${WRKSRC}/beret ${PREFIX}/bin ${INSTALL_DATA_DIR} ${PREFIX}/share/doc/beret ${INSTALL_DATA} ${WRKSRC}/lgpl-3.0.txt ${PREFIX}/share/doc/beret ${INSTALL_DATA} ${WRKSRC}/OFL.txt ${PREFIX}/share/doc/beret ${INSTALL_DATA} ${WRKSRC}/FONTLOG.txt ${PREFIX}/share/doc/beret ${INSTALL_DATA} ${WRKSRC}/README.txt ${PREFIX}/share/doc/beret ${INSTALL_DATA_DIR} ${PREFIX}/share/beret ${INSTALL_DATA} ${WRKSRC}/AveriaSans-Regular.ttf ${PREFIX}/share/beret ${INSTALL_DATA_DIR} ${PREFIX}/share/beret/images ${INSTALL_DATA} ${WRKSRC}/images/* ${PREFIX}/share/beret/images ${INSTALL_DATA_DIR} ${PREFIX}/share/beret/music ${INSTALL_DATA} ${WRKSRC}/music/* ${PREFIX}/share/beret/music ${INSTALL_DATA_DIR} ${PREFIX}/share/beret/rooms ${INSTALL_DATA} ${WRKSRC}/rooms/* ${PREFIX}/share/beret/rooms ${INSTALL_DATA_DIR} ${PREFIX}/share/beret/sfx ${INSTALL_DATA} ${WRKSRC}/sfx/* ${PREFIX}/share/beret/sfx .include <bsd.port.mk>
patches/
Now let's take a look at the patches
directory. Inside there are two patches: patch-Makefile
and patch-game_c
. Let's take them one at a time. Here is patch-Makefile
.
$OpenBSD$ --- Makefile.orig Tue Jan 10 01:55:02 2012 +++ Makefile Wed Jan 11 14:58:26 2012 @@ -1,13 +1,11 @@ -CC= gcc -CFLAGS= -Wall -g -LFLAGS= -lSDLmain -lSDL -lSDL_image -lSDL_ttf -lSDL_mixer +LFLAGS= -L/usr/local/lib -L/usr/X11R6/lib -lSDLmain -lSDL -lSDL_image -lSDL_ttf -lSDL_mixer -default: beret +all: beret clean: rm beret *.o beret: game.o thing.o physics.o - $(CC) $(LFLAGS) -o $@ game.o thing.o physics.o + $(CC) $(LFLAGS) -pthread -o $@ game.o thing.o physics.o %.o: %.c %.h
OK, this looks less than ideal. We don't want to hardcode /usr/local
or /usr/X11R6
. Instead, we can again use sdl-config
to get the correct linker flags. This would be added to the Makefile
we just finished editing and removed from this patch. We should do the following.
MAKE_FLAGS = CC="${CC}" CFLAGS="${CFLAGS} `sdl-config --cflags`" \ LFLAGS="${LDFLAGS} `sdl-config --libs` -lSDL_image -lSDL_mixer -lSDL_ttf"
Additionally, we can set ALL_TARGET
in the Makefile
as well, which will completely eliminate the need for this patch. It looks like this.
ALL_TARGET = default
Neat! One less patch is one less thing to worry about maintaining. I will reproduce a new Makefile
after we look at all the patches, in case we can also elimate the other patch.
Here is patch-game_c
.
$OpenBSD$ --- game.c.orig Tue Jan 10 01:55:02 2012 +++ game.c Thu Jan 12 11:33:20 2012 @@ -95,7 +95,7 @@ #define RESOURCE_PATH "" #else #define SUPPORT_PATH ".beret/" -#define RESOURCE_PATH "" +#define RESOURCE_PATH "/usr/local/share/beret/" #endif #define QUITMOD_WIN KMOD_ALT
Same thing here, we do not want to hardcode /usr/local
. Additionally, we should put a comment at the top of the patch explaining why this patch is needed. It will help out a lot to remind you why you did something years later when you need to update to port.
Here is the new patch.
$OpenBSD$ Install the game data files to ${TRUEPREFIX}/share/beret This matches the do-install routine. --- game.c.orig Tue Jan 10 01:55:02 2012 +++ game.c Thu Jan 12 11:33:20 2012 @@ -95,7 +95,7 @@ #define RESOURCE_PATH "" #else #define SUPPORT_PATH ".beret/" -#define RESOURCE_PATH "" +#define RESOURCE_PATH "${TRUEPREFIX}/share/beret/" #endif #define QUITMOD_WIN KMOD_ALT
We will need to add a do-configure
routine to expand ${TRUEPREFIX}
.
Let's try to build our new port. This is the finalized Makefile
and remember too we have removed patch-Makefile
.
# $OpenBSD$ COMMENT = 2D puzzle-platformer game DISTNAME = beret-1.2.1pl1 CATEGORIES = games x11 HOMEPAGE = http://kiwisauce.com/beret/ MAINTAINER = Brian Callahan <bcallah@devio.us> # LGPLv3 only # AveriaSans-Regular.ttf: SIL Open Font License PERMIT_PACKAGE = Yes WANTLIB += c m SDL SDL_image SDL_mixer WANTLIB += SDL_ttf pthread MASTER_SITES = https://mirrors.nycbug.org/pub/distfiles/ LIB_DEPENDS = devel/sdl-image \ devel/sdl-mixer \ devel/sdl-ttf MAKE_FLAGS = CC="${CC}" CFLAGS="${CFLAGS} `sdl-config --cflags`" \ LFLAGS="${LDFLAGS} `sdl-config --libs` -lSDL_image -lSDL_mixer -lSDL_ttf" # Expand ${TRUEPREFIX} do-configure: ${SUBST_CMD} ${WRKSRC}/game.c # Upstream does not provide an installation routine. do-install: ${INSTALL_PROGRAM} ${WRKSRC}/beret ${PREFIX}/bin ${INSTALL_DATA_DIR} ${PREFIX}/share/doc/beret ${INSTALL_DATA} ${WRKSRC}/lgpl-3.0.txt ${PREFIX}/share/doc/beret ${INSTALL_DATA} ${WRKSRC}/OFL.txt ${PREFIX}/share/doc/beret ${INSTALL_DATA} ${WRKSRC}/FONTLOG.txt ${PREFIX}/share/doc/beret ${INSTALL_DATA} ${WRKSRC}/README.txt ${PREFIX}/share/doc/beret ${INSTALL_DATA_DIR} ${PREFIX}/share/beret ${INSTALL_DATA} ${WRKSRC}/AveriaSans-Regular.ttf ${PREFIX}/share/beret ${INSTALL_DATA_DIR} ${PREFIX}/share/beret/images ${INSTALL_DATA} ${WRKSRC}/images/* ${PREFIX}/share/beret/images ${INSTALL_DATA_DIR} ${PREFIX}/share/beret/music ${INSTALL_DATA} ${WRKSRC}/music/* ${PREFIX}/share/beret/music ${INSTALL_DATA_DIR} ${PREFIX}/share/beret/rooms ${INSTALL_DATA} ${WRKSRC}/rooms/* ${PREFIX}/share/beret/rooms ${INSTALL_DATA_DIR} ${PREFIX}/share/beret/sfx ${INSTALL_DATA} ${WRKSRC}/sfx/* ${PREFIX}/share/beret/sfx .include <bsd.port.mk>
Let's start the build process. I changed DISTNAME
to match the current name of the tarball the port is made from.
make makesum
, which fetches the tarball and generates a distfile
, worked fine. But I didn't expect any issues here. make configure
, which will run make extract
and make patch
as well, also worked fine and I see that the variable expansion took place correctly.
But make build
failed on the linker stage. It looks like the LFLAGS
didn't catch. So let's revise. Let's replace our LFLAGS
line within MAKE_FLAGS
to be LDFLAGS="${LDFLAGS} `sdl-config --libs`"
instead. We will have to recreate a patch-Makefile
but it will be much more simple.
$OpenBSD$ Use the LDFLAGS we specified in the port Makefile. Index: Makefile --- Makefile.orig +++ Makefile @@ -8,6 +8,6 @@ clean: rm beret *.o beret: game.o thing.o physics.o - $(CC) $(LFLAGS) -o $@ game.o thing.o physics.o + $(CC) ${LDFLAGS} $(LFLAGS) -o $@ game.o thing.o physics.o %.o: %.c %.h
Let's try building again. Another linker error. This time it reports some undefined symbols that live in libm
so we can just add that. We can just tack it on to our new LDFLAGS
line or in the patch itself. I put it in the LDFLAGS
line.
OK, now it builds. Let's run make update-plist
which will run make fake
first and the generate pkg/PLIST
. Then we'll run make test
and it complains there are no tests, so we will need to add NO_TEST=Yes
to our Makefile
. Finally, we will run make port-lib-depends-check
to check WANTLIB
. I am going to presume my WANTLIB
is wrong or at least out of style, so I'll delete it entirely and copy and paste the output of make port-lib-depends-check
.
Here is our finished Makefile
.
# $OpenBSD$ COMMENT = 2D puzzle-platformer game DISTNAME = beret-1.2.1pl1 CATEGORIES = games x11 HOMEPAGE = https://kiwisauce.com/beret/ MAINTAINER = Brian Callahan <bcallah@devio.us> # LGPLv3 only # AveriaSans-Regular.ttf: SIL Open Font License PERMIT_PACKAGE = Yes WANTLIB += SDL SDL_image SDL_mixer SDL_ttf c m pthread MASTER_SITES = https://mirrors.nycbug.org/pub/distfiles/ LIB_DEPENDS = devel/sdl-image \ devel/sdl-mixer \ devel/sdl-ttf ALL_TARGET = beret MAKE_FLAGS = CC="${CC}" CFLAGS="${CFLAGS} `pkg-config --cflags sdl`" \ LDFLAGS="${LDFLAGS} `pkg-config --libs sdl` -lm" NO_TEST = Yes do-configure: ${SUBST_CMD} ${WRKSRC}/game.c do-install: ${INSTALL_PROGRAM} ${WRKSRC}/beret ${PREFIX}/bin ${INSTALL_DATA_DIR} ${PREFIX}/share/doc/beret ${INSTALL_DATA} ${WRKSRC}/lgpl-3.0.txt ${PREFIX}/share/doc/beret ${INSTALL_DATA} ${WRKSRC}/OFL.txt ${PREFIX}/share/doc/beret ${INSTALL_DATA} ${WRKSRC}/FONTLOG.txt ${PREFIX}/share/doc/beret ${INSTALL_DATA} ${WRKSRC}/README.txt ${PREFIX}/share/doc/beret ${INSTALL_DATA_DIR} ${PREFIX}/share/beret ${INSTALL_DATA} ${WRKSRC}/AveriaSans-Regular.ttf ${PREFIX}/share/beret ${INSTALL_DATA_DIR} ${PREFIX}/share/beret/images ${INSTALL_DATA} ${WRKSRC}/images/* ${PREFIX}/share/beret/images ${INSTALL_DATA_DIR} ${PREFIX}/share/beret/music ${INSTALL_DATA} ${WRKSRC}/music/* ${PREFIX}/share/beret/music ${INSTALL_DATA_DIR} ${PREFIX}/share/beret/rooms ${INSTALL_DATA} ${WRKSRC}/rooms/* ${PREFIX}/share/beret/rooms ${INSTALL_DATA_DIR} ${PREFIX}/share/beret/sfx ${INSTALL_DATA} ${WRKSRC}/sfx/* ${PREFIX}/share/beret/sfx .include <bsd.port.mk>
To complete the port, I just used the existing pkg/DESCR
.
Now we can run make install
and see if it works. It does, though that isn't too surprising. And with that, we have finished revising our port.
Following along with the upcoming video may be more illuminating than just the blog post. But I hope you learned something about how I approach creating OpenBSD ports. I enjoyed revising my first port, though I'll note it's basically identical to the current version of the port. That's kinda nice.