Inko 0.14.0 released

Published on

We're pleased to announce the release of Inko 0.14.0. This release contains a variety of exciting changes, such as support for parallel and incremental compilation, cross compilation, faster linking, and more!

Table of contents

For the full list of changes, refer to the changelog.

A special thanks to the following people for contributing changes included in this release:

We'd also like to thank the following people for financially supporting the development of Inko:

We'd also like to thank the NLnet foundation for sponsoring part of the work that went into this release.

Parallel compilation of object files

Thanks to the NLnet foundation for sponsoring the development of this feature.

Inko uses LLVM for generating machine code, but LLVM is rather slow. To reduce compile times, Inko now compiles LLVM modules (and thus object files) in parallel. In case of Inko's own standard library test suite, the use of parallel compilation reduces compile times by a factor of four on a computer with four cores and eight threads.

The implementation is reasonably straightforward: the compiler spawns a number of threads equal to the number of CPU cores (by default, this can be changed using a command-line option). The work "queue" is an atomic counter that starts at zero. Each thread races to increment the counter using an atomic swap. Whenever a thread succeeds, it uses the resulting value to index an array of modules to compile, then performs the necessary work. When threads reach the maximum value (equal to the number of modules), they stop.

This setup means there's no need for any sort of locking or complex concurrent data structures, as the only shared mutable state is an atomic counter. This in turn means the setup scales well as the number of CPU cores goes up.

See commit 9162406 for more details.

Incremental compilation of object files

In addition to compiling machine code in parallel, we also perform incremental compilation at the LLVM IR/object file level. This means we only recompile object files if needed, greatly reducing compile times. When using a single thread to compile Inko's standard library test suite, we found that incremental compilation reduces compile times by a factor of 8 in the best case scenario. When combining this with parallel compilation, we observed reductions of a factor of 3, depending on the number of threads used.

Implementing this proved rather tricky, as we had to make sure that when compiling the same code, the compiler performs the same work in the same order every time. For example, symbol names used to include the numerical IDs of methods, but these IDs change based on the order in which they're processed. To solve that, symbol names now use a different name mangling scheme to ensure they're unique, without depending on the order in which code is processed.

In it's current implementation there are certain scenarios in which caches are flushed even though this isn't strictly necessary. In general such cases are rare, and it's something we hope to improve in the future when the need for this arises.

See commit 137304d for more details.

Faster linking of object files using Mold

If you're using Linux and have Mold installed, Inko's compiler automatically uses it for linking object files, similar to how it automatically uses LLD if it's available. If both Mold and LLD are installed, the compiler favours Mold over LLD.

See commit 76cf292 for more details.

Support for cross compilation

Thanks to the NLnet foundation for sponsoring the development of this feature.

Cross compilation allows you to compile your programs from one target (e.g. AMD64 Linux) to a different target (e.g. ARM64 macOS), without the need for extra hardware. Starting with version 0.14.0, Inko officially supports cross compilation to different targets.

To make this as easy as possible, Inko tries to automatically detect what toolchain to use for cross compilation. For example, if Zig is installed the compiler favours it over GCC and clang, as cross compilation using Zig is much easier compared to the alternatives.

Cross compilation requires a version of the Inko runtime suitable for the compilation target. To remove the need for manually compiling the runtime for each target, we provide pre-built versions of the runtime which are installed using the inko runtime add command. Take the following program for example:

import std.stdio.STDOUT

class async Main {
  fn async main {
    STDOUT.new.print('hello')
  }
}

To cross compile this to AMD64 macOS using Zig, all we need to do is:

  1. Make sure Zig is installed
  2. Run inko runtime add amd64-mac-native
  3. Run inko build --target amd64-mac-native test.inko to build the program

Of course without Zig cross compilation is still supported, but the process is a bit more difficult depending on what target you're compiling to. For more details, refer to the cross compilation documentation

Inko supports cross compiling to AMD64 and ARM64 macOS and Linux, and AMD64 FreeBSD. ARM64 FreeBSD is supported at the compiler level, but we don't provide pre-built runtimes for FreeBSD as we use rustup as part of building the runtimes, and rustup doesn't provide any pre-built targets for this target.

See commit 03ef71f for more details.

Support for compiling with musl

As part of the cross compilation work, we've also added support for compiling Inko programs using musl. This allows you to build Linux executables that don't depend on glibc and as such are much more portable. To compile using musl, use the amd64-linux-musl or arm64-linux-musl target:

inko runtime add amd64-linux-musl
inko build --target amd64-linux-musl test.inko

When targeting musl from a GNU host, musl is statically linked. If the host is instead a musl host (e.g. Alpine Linux), the compiler dynamically links musl by default to match the expected behaviour on such hosts. In such cases you can force static linking by using inko build --static.

Additions to the standard library

This releases includes a variety of additions to the standard library, such as more methods for the Path type (Path.extension, Path.with_extension, Path.list_all, and more), support for replacing strings, and methods for querying JSON values. This new querying API allows you to query JSON documents as follows:

import std.json.Json
import std.stdio.STDOUT

class async Main {
  fn async main {
    let json = Json
      .parse('{ "name": "Donald Duck" , "address": { "city": "Duckburg" } }')
      .unwrap

    let city = json.query.key('address').key('city').as_string.unwrap
    let stdout = STDOUT.new

    stdout.print(city)
  }
}

Warnings for unused variables

Inko's compiler now produces warnings for unused local variables. This seemingly minor feature can prove useful in finding redundant code, as seen in this commit removing various bits of unused code.

See commit ac24bcc for more details.

A new Inko manual

Inko's manual has received a significant overhaul. Instead of using mkdocs, it's now built using Inko itself using the inko-wobsite static site generator, and it uses a new style more in line with the main website. As part of this we also rewrote and reorganized large parts of the manual.

As part of these changes the ability to search the manual has been removed. We may reintroduce this at some point in the future, when we figure out a solution that provides good and relevant search results (which the old search function didn't always do).

You can find the latest version of the new manual here, and the version for the main branch is found here.

Rust 1.70 is now required

The minimum required version of Rust is increased from 1.68.0 to 1.70.0, allowing us to take advantage of some newer Rust features.

A lot of bug fixes

This release includes many fixes, such as fixes for OR patterns, guard patterns, uniqueness checking for Channels, compile-time memory usage, and much more.

Plans for 0.15.0

For the next version of Inko, we'll be working on generating source code documentation, automatic code formatting, various improvements to the type system (e.g. making working with closures easier), and more.

Following and supporting Inko

If Inko sounds like an interesting language, consider joining the Discord server. You can also follow along on the /r/inko subreddit. If you'd like to support the continued development of Inko, please consider donating using GitHub Sponsors.