Code:

Hacking the Portable Object Compiler

Note: This article is a work in progress.

I'm partial to C for its simplicity and power, but I prefer to work in an object-oriented mindset when I write code. I'm no fan of the hot mess is C++, however. So I was quite excited when I found Objective C a few years ago. Although from a syntactical standpoint, the language is clearly an imposition on the underlying C syntax, I think the overall effect is more intuitive and elegant than the Arcane Wizard Scrawl(TM) that C++ has become. I'd hoped to start using Objective C, by way of GCC, as my main programming language -- but their desire to keep pace with Apple's slow destruction of the language ruined those plans.

In an effort to find an alternative, I stumbled across the Portable Object Compiler. The basic syntax is the same as what Apple brought out of NeXT, except that protocols (interfaces) are not supported -- though there are ways to live without this -- and categories have to be implemented in a different fashion, albeit one that makes sense.

Intrigued, I downloaded the bootstrap compiler and compiler sources and...they didn't compile on my Linux box.

More specifically: the bootstrap compiler built without issue, but when it came time to use it to build the final compiler, it threw a bunch of syntax errors and quit.

At that point in time, there were no pre-compiled binaries for Linux; so, after playing with compilation and configuration options for a while and still meeting failure, I was forced to concede defeat for the time being. In the intervening years, I've checked in on the Portable Object Compiler hopefully from time to time, but never had much success getting it to compile in spite of the fact that I would change machines and Linux flavors several times.

I knew the program must compile for some people, and in fact the source tarball contains a file named "Platform.txt" which documents the systems on which the compiler has been successfully built. Recently I decided to make time to unravel the reasons why I continued to run into issues and, at last, I was able to achieve success. These are my notes on the subject, and also a modification that I made to the compiler driver so it could link resource files on Windows.

Compiling on Linux

Right now I'm running Linux Mint 19.3 with gcc 7.5. I downloaded the both the bootstrap and compiler tarballs for version 3.3.17 of Portable Object Compiler, which was the latest available at the time. The configure && make && make install chain has always worked just fine for the bootstrap compiler; compiling the compiler itself is where problems have always arisen for me in the past.

This time around was no different: the bootstrap compiler built and installed without issue, but partway into compiling the compiler, the bootstrap compiler threw the following error:

/usr/local/bin/objc -c -DNDEBUG -O2 -I. -noI -I../../include/objcrt -I../../include/objpak -I../oclib lex.m
Portable Object Compiler 3.3.13 (c) 1997-2019.
Distributed under the terms of the GNU LGPL.
/usr/include/x86_64-linux-gnu/bits/unistd.h:220: fatal: syntax error "char"
Makefile:76: recipe for target 'lex.o' failed
make[2]: *** [lex.o] Error 1

This wasn't the error I previously received when attempting to compile, but I was determined to discover why I was getting it. The Platforms.txt file that came with the tarball indicated that users of GCC 7.5 were able to compile, so I knew it could be done. A Google search quickly leads to the solution: the unistd.h dependency is apparently only required if your lexer has an interactive mode; that is, if it accepts line-by-line input like Python or the old BASIC interpreters. The Portable Object Compiler does not, so we can remove that dependency.

My initial solution was to open "src/objc/Makefile" and alter the line which reads EXTRA_MFLAGS to read:

EXTRA_MFLAGS=-DYY_NO_UNISTD_H

This flag was then passed to the bootstrap compiler when building the final compiler. After running make clean && make, I found myself with a working Objective-C compiler!

However, I was curious to know if there were other ways to approach this solution. An additional way, which seemed to work, was to export EXTRA_MFLAGS=-DYY_NO_UNISTD_H before running configure. A third solution I tested was based on a StackOverflow discussion. Adding the following to the top of "src/objc/lex.lm" also seems to work:

%option nounistd

Compiling on Cygwin64

While I'm required to support Windows at work, I haven't really been a fan of the operating system since Windows 2000. Nonetheless, since I've had occasion to write various utilities and programs for work, I thought it would be useful if I could get the Portable Object Compiler to compile on Windows, too. I didn't want to use the pre-compiled version available from the website, since that still relies on an old version of Visual C++ -- which also ties you to the Microsoft paradigm.

I've toyed around with Cygwin on various occasions, so it seemed like the natural choice for my purposes: we could present a POSIX-like environment to the build tools and hopefully obtain an Objective-C compiler for Windows in the same way we acquired one for Linux. I'll post more details about what steps I had to take to get the compiler up and running in the near future.

Linking resource files on Windows

Coming soon

Living without @protocol

Coming soon

Using categories

A quick overview of what I've tested and found to work, which I'll expand on later:

  1. Derive a subclass of the class to which you are going to add methods
  2. Define and implement those methods
  3. Define +initialize, and call [self addMethodsTo: super]