Building Pony on DragonFly

Quick notes on how to build the actor-oriented language Pony on DragonFly.

We need LLVM 10 to build or that's what I have tested with:

sudo pkg ins llvm10

It won't build with the stock gcc due to some issues with C11's stdatomic that is used by the Pony runtime. DragonFly does not ship with libatomic, but LLVM 10 is clever enough to emit opcodes for cmpxchg on uint128_t types instead of falling back to calls to __atomic_compare_exchange_16. It still links to -latomic so that I had to provide a dummy libatomic.a in order to make the linker happy. Note that libatomic is part of LLVM but it seems to be disabled by default in the DragonFly port.

Next, what you need is my dragonfly-fix-compile branch of ponyc:

git clone https://github.com/mneumann/ponyc.git
cd ponyc
git checkout dragonfly-fix-compile

This branch contains a few fixes to the CMakefiles as DragonFly is the only BSD that has no BSD in it's uname. This results in a couple of patches like this:

-elseif(${CMAKE_HOST_SYSTEM_NAME} MATCHES "BSD")
+elseif(${CMAKE_HOST_SYSTEM_NAME} MATCHES "BSD|DragonFly")

Furthermore, the benchmark library gbenchmark had to be patched as it did not know anything about DragonFly. I just tricked it so that it now thinks we are FreeBSD:

--- src/internal_macros.h.orig  2020-04-15 14:43:24 UTC
+++ src/internal_macros.h
@@ -54,6 +54,9 @@
   #endif
 #elif defined(__FreeBSD__)
   #define BENCHMARK_OS_FREEBSD 1
+#elif defined(__DragonFly__)
+  #define BENCHMARK_OS_FREEBSD 1
+  #define BENCHMARK_OS_DRAGONFLY 1
 #elif defined(__NetBSD__)
   #define BENCHMARK_OS_NETBSD 1
 #elif defined(__OpenBSD__)

The patch was trivial to create but telling CMake to apply it automatically required a tiny bit of research. In the end it was as simple as adding PATCH_COMMAND to the ExternalProject_Add directive:

PATCH_COMMAND patch -p0 < ...patch-file

In the dragonfly-fix-compile branch I further ship the stdatomic.h header file, as it's not installed by default on DragonFly as mentioned earlier. The only thing I had to modify was:

-#if __STDC_HOSTED__ && __has_include_next(<stdatomic.h>)
+#if 0
 # include_next <stdatomic.h>

I tried to fix the CMakefiles in order to pick the stdatomic.h header up automatically from a local directory, but that did not work. Instead, I ended up with pasting the contents of stdatomic.h directly into the src/common/pony/detail/atomics.h file at the right place.

Then I had to tell CMake to pick up my dummy libatomic.a:

link_directories(
  ${CMAKE_CURRENT_SOURCE_DIR}/../../dragonfly/lib
)

To produce the dummy libatomic.a, I used something like this:

echo "" > atomic.c
gcc -c -o atomic.o atomic.c
ar rcs libatomic.a atomic.o

All these things are contained in my dragonfly-fix-compile branch. To compile ponyc, you just have to execute the following from the ponyc directory:

export CC=clang10
export CXX=clang++10
gmake libs && gmake configure && gmake build

Run tests:

gmake test

And to install:

gmake install prefix=$HOME/pony

Let's try to compile a simple hello world application with the Pony compiler:

mkdir hw && cd hw

cat <<EOF > main.pony
actor Main
  new create(env: Env) =>
    env.out.print("Hello World")
EOF

$HOME/pony/bin/ponyc .
./hw    # => "Hello World"

Works, great!