----------------------------------------
Porting an ANSI C application to Plan 9
May 23 2021
----------------------------------------
The distinct lack of a reversi game in any version of Plan 9 has yet
to be remedied upstream, and knowing that I should not survive much
longer without that game, I took it upon myself to see what porting an
existing game requires.
Lo and behold, it wasn't too bad a process once I found a reversi game
written in proper ANSI C. Here are some of my notes along the way.
If you would like to get a look at the original source code yourself,
you can find it here:
=>
http://www.java2s.com/Code/C/String/REVERSIAnOthellotypegame.htm
The source code needs a couple of things right off the bat. The Plan
9 C libraries used for its functions are a little different:
#include <u.h>
#include <stdio.h>
#include <libc.h>
#include <ctype.h>
As far as I know, "u.h" is present in every Plan 9 C program.
The code conventions for source code under Plan 9 are also a bit
different from what many of us are used to seeing these days, and the
most immediate difference is that function return types are written on
their own line. Curly braces never occupy the same line as the
function declaration, either.
The long and short here is that this:
void display(char board[][SIZE]) {...}
.. doesn't fly.
Instead, you should write:
void
display(char board[][SIZE])
{
...
}
That might seem a little strange, but I've begun to find this a bit
more readable compared to the first example. It also makes the
top-level function name easy to search (/^display/).
Believe it or not, this was all it took for the program to compile,
but after tidying things up a bit, I thought this might be a good time
to also learn about mkfiles under Plan 9. This was another thing the
Plan 9 designers aimed to simplify, and once I learned a bit about it,
I have to say it's pretty refreshing.
Here is my "first blush" mkfile:
</$objtype/mkfile
BIN=/$objtype/bin
TARGET=reversi
$TARGET:
$CC $TARGET.c
$LD -o $TARGET $TARGET.$O
clean:V:
rm -f *.$O $O.out
install:V: $TARGET
mv $TARGET $BIN/games/
Interesting! Notice that I did not declare the compiler or linker.
The system can figure out what it's supposed to use for that purpose
on its own. "$O" in my case turns out to be "6", which is to say that
it is an object file compiled for amd64. The default output after
linking would be "6.out". If it were for Intel i386, this would be
"8", for ARM it would be "5", and there are yet others, all with their
own compilers and linkers corresponding to the architecture. All
of the typical compilers and linkers are installed by default.
$objtype is simply the architecture for the server. Plan 9 binds
executables under /bin, but many of them come from (say) /amd64/bin
or /386/bin. This, too, is refreshing compared to the barely-coherent
filesystem standards you see on most Linux distributions and even the
BSDs. If it's something to be executed, you can forget about /sbin,
/usr/bin, /usr/local/bin, /opt/bin and all their little friends.
Given how easy it is to cross-compile with Plan 9 right out of the
box, why restrict software you make to only the one architecture? And
you see an answer to that question in this mkfile. It does not care
on what it is compiling provided it has a Plan 9 compiler, linker, and
the tools needed for understanding the mkfile. Heck, if I wanted to
compile for every supported architecture on this one machine, that is
always an option provided the code doesn't use anything specific to
any one of them.
Once I knew all this worked, I got to working on the program itself
and its logic. There I'm not quite done.
I gather that the program is not written to be the most efficient,
hardest, or most fun incarnation of reversi on the planet. It doesn't
even use pointers. But it does serve for a great teaching exercise,
and it's a nice enough starting point.
If you'd like to play the game yourself, be sure to set the board size
to "8", and if you're going to hack on it, definitely work on the AI.
It loses just about every time because it's not aggressive enough
about capturing corners, which is the whole key to winning the game.
Additionally, it does not exit cleanly and the error handling leaves
something to be desired.
Even so, I wanted to play reversi, and thanks to the fine work behind
Plan 9, I got my wish. Here's to learning something and having fun on
a Sunday afternoon.
Cheers.