Skip to Content
DocumentationInstallation

Installation

Warning

🚧 Work in progress. Prebuilt downloads and an installer are planned. For now, you build Nio from a copy of its source code.

Prerequisites

You need one thing: clang on your PATH.

  • macOS: clang comes with the Xcode command line tools. Install them with xcode-select --install.
  • Linux: install clang from your distribution’s packages.
  • Windows: install LLVM  (or run winget install LLVM.LLVM) and the Visual Studio Build Tools with the “Desktop development with C++” workload, which provides the C runtime clang needs. Add C:\Program Files\LLVM\bin to your PATH. The build script is a shell script, so run it from Git Bash, which comes with Git for Windows. Programs built on Windows always get an .exe name.

Building the compiler

The compiler is written in Nio, so you need a Nio compiler to build it. The repository solves this with a copy of the compiler in bootstrap/, stored as LLVM IR, which clang can build on its own:

sh bootstrap/build.sh # writes ./nio ./nio run examples/car.nio

That first compiler works, but it is not the fastest one. Use it to build the compiler again, this time optimized:

./nio build --release src/nio.nio -o nio

Put nio somewhere on your PATH, and every command in this documentation works as written.

Running programs

# run a program directly nio run examples/car.nio # build a native executable nio build examples/car.nio -o car ./car # see the LLVM IR the compiler generates nio emit examples/car.nio # format every .nio file in this folder and below nio format . # run every *_test.nio file in this folder and below nio test # show what a module declares, with its documentation nio doc http # show the compiler's version nio version

Flags

Flags go before the file name. With run, everything after the file name is passed to your program, not to the compiler.

FlagEffect
-o <path>build only: where to write the executable
--releasemake the program as fast as possible (see below)
-ginclude debug information, so a debugger can read the program
--coveragerecord which lines run (coverage)
nio run --coverage tests/math.nio nio build -g server.nio -o server nio build --release server.nio -o server

Two build modes

There are two ways to build, and they trade build time against speed:

  • The default build is quick to make, so you can change something and see the result straight away.
  • A --release build takes longer, because it optimizes the whole program, and the result runs faster.

Both run your program the same way; only the speed differs. For small programs, both take under a second, so the difference only matters as a program grows. For example, building the Nio compiler itself:

build timeresulting program
default5 sabout 2× slower
--release34 sfull speed

Use the default while you work, and --release for anything you ship or measure. nio package, which builds an installable application, always uses --release.

A --release build is also reproducible: the same source always produces exactly the same file. A default build is not, although it behaves identically.

The build cache

Nio’s runtime — the C code linked into every program — is compiled once and then reused, which makes default builds much faster. It is kept in:

PlatformLocation
macOS~/Library/Application Support/nio/cache
Windows%APPDATA%\nio\cache
Linux and others$XDG_DATA_HOME/nio/cache, or ~/.local/share/nio/cache

Upgrading Nio or clang starts a fresh cache automatically, and old ones are cleaned up. You can delete the folder at any time; the next build recreates what it needs.

Reading an error

The compiler reports every error it finds at once, each with the code it is about:

error: cannot use String as int in declaration of "x" --> main.nio:2:9 | 2 | int x = "hello"; | ^^^^^^^ note: expected because of this type --> main.nio:2:1 | 2 | int x = "hello"; | ---

The ^^^ underlines exactly the code the error is about. A note: points at a second place that explains it — here, the type the value had to match. Type errors are usually a disagreement between two places, and the second one is often where the fix belongs. It can even be in another file.

A help: line means the compiler knows the exact change that fixes the error:

error: path is a built-in library; import it first: import 'path'; --> main.nio:4:9 | 4 | int n = path.join("a", "b"); | ^^^^ help: add import 'path';

In an editor using the language server, the same fix is offered as a one-click quick fix. The compiler only offers a fix when it is certain of it.

Debugging

Build with -g to include debug information, then run the program under lldb or gdb:

nio build -g server.nio -o server lldb ./server

Breakpoints work on source lines, functions have the names you gave them (a method is Type.name), and parameters and local variables can be inspected — including inside async functions, across an await.

  • On macOS the debug information is written to server.dSYM next to the program. Keep the two together.
  • Top-level variables are globals, so inspect them with target variable rather than frame variable.
  • A String, an array or a record shows as its type name and an address, not its contents. To see inside a value, print it or turn it into JSON with json.toText.
  • Debug a default build rather than a --release one. The optimizer in a release build can remove variables (they show as optimized out) and reorder lines, which makes stepping confusing.

Without -g, no debug information is added at all, and with it the program runs just as fast.

Editor support

nio lsp

nio lsp is a language server : your editor starts it and talks to it. You never run it by hand. It is the same compiler as nio build, so it reports exactly the same errors.

In an editor it:

  • shows errors as you type, including errors caused by files you have changed but not saved;
  • shows the type of anything you hover over, with the documentation comment written above its declaration;
  • jumps to a declaration with Cmd+click or F12, even in another file;
  • completes names: string. lists what the string module offers, and car. lists a record’s fields and methods.

VS Code needs the extension from the repository, which also provides syntax highlighting:

./editors/sync.sh cd editors/vscode && npm install && npm run build ln -s "$PWD" ~/.vscode/extensions/nio

Then run Developer: Reload Window. If nio is not on your PATH, set nio.server.path in the settings.

Neovim, Helix and Zed need nothing installed; add the command to your editor’s configuration:

-- Neovim vim.lsp.config.nio = { cmd = { "nio", "lsp" }, filetypes = { "nio" }, root_markers = { ".git" } } vim.lsp.enable("nio")

Syntax highlighting works without the server. It comes from a TextMate grammar, which VS Code, JetBrains IDEs and Sublime Text can all read; the editors/ folder in the repository has it, with instructions for each editor.