Crystal on OpenBSD 6.0

Not the most ideal way to install something on OpenBSD for various reasons. It will be great if there were packages already built for Crystal.

Pre-requisites

Install bash: doas pkg_add bash

OpenBSD comes with a default shell ksh. Crystal needs bash to run.

$ crystal
env: bash: No such file or directory

Installing the binary

Download the OpenBSD tarball from https://github.com/crystal-lang/crystal/releases. The latest version of Crystal available for OpenBSD is 0.19.4.

Extract it to where you store user downloaded binaries e.g. /usr/local or /opt

Link the binary to your path.

$ ln -sf /usr/local/crystal/bin/crystal /usr/local/bin/crystal

Making sure it works

Try running crystal to get the version:

$ crystal -v
Crystal 0.19.4 [7f82f79] (2016-10-07)

Create a Crystal program and run it.

/home/user/fib.cr
def fibonacci(n)
  return n if n <= 1
  fibonacci(n - 1) + fibonacci(n - 2)
end
puts fibonacci 40
$ vim fib.cr
$ crystal build --release fib.cr
$ time ./fib
102334155
    0m00.94s real     0m00.81s user     0m00.01s system

It runs pretty fast on my OpenBSD server. OpenBSD is not particularly fast versus other operating systems, choosing a fast programming language helps speed things up.

Why there was no package

Crystal has a bootstrap problem: the compiler is written in Crystal, so building it from source needs a working Crystal compiler. A ports tree solves that by chaining forward from a previous build, and for OpenBSD 6.0 nobody had carried that chain to a current release yet, so the community tarball on the GitHub releases page was the practical install. It is the same trade you make with any LLVM-backed language on a niche platform: the compiler leans on LLVM headers and libraries, the platform needs someone to keep all of that in sync through releases, and until that person shows up you fetch the tarball.

The bash dependency is smaller than the error message makes it look. The crystal launcher is a shell script with a #!/usr/bin/env bash shebang, and OpenBSD ships ksh by default, so the env line fails before the real compiler ever starts. One pkg_add and the launcher is satisfied.

Why the release build matters

The fib benchmark above ran with --release, the flag that hands optimization to LLVM instead of prioritizing compile time. Without it you get the fast-compile, slow-run configuration meant for iteration. With it, recursive fibonacci of 40 finishes in under a second, because the recursion compiles to machine code with no interpreter, no boxed integers, and no runtime checks in the hot path. That is the whole appeal of Crystal for server work: Ruby-shaped syntax that exits as native code.

The pairing suits OpenBSD on purpose. The system trades throughput for correctness and tight defaults everywhere else, so a language that makes the application fast is the right place to win the performance back.