Request for Teaching: How to Create a Nix Expression for a BASIC Compiler?


#1

Hello, fellow Nixers!

Cutting to the chase: I want to create a Nix expression for the FreeBASIC compiler project. It is a self-hosting compiler - yes, a BASIC compiler written in BASIC!

I want to effectively learn-by-doing; my plan is to post the progress of it in my programming blog, as a way of teaching others how to build a self-hosting compiler.

Can someone help me, then?

Thanks in advance!


#2

Anderson Torres via Nix community nixos1@discoursemail.com writes:

Hello, fellow Nixers!

Cutting to the chase: I want to create a Nix expression for the
FreeBASIC compiler
project
. It
is a self-hosting compiler - yes, a BASIC compiler written in BASIC!

I want to effectively learn-by-doing; my plan is to post the progress
of it in my programming blog, as a way of teaching others how to build
a self-hosting compiler.

Can someone help me, then?

Thanks in advance!

Here’s my suggested “high level” approach to get started. Feel free to
come back with more specific questions if you get stuck (I’ve heard of
FreeBASIC, but haven’t actually looked into it in detail).

If you’re completely new to Nix, I’d recommend using it (either
installed on your existing Linux or macOS, or try NixOS in a VM), read
some of the manual, play around, etc.

Once you’re comfortable using Nix (e.g. nix-build, nix repl), then you
can try packaging something (like FreeBASIC).

My approach to packaging is to start off with an expression like this:

with import <nixpkgs> {};
runCommand "freebasic"
  {}
  ''
  ''

You can put data inside that second attrset {}. It’s recommended to use
this for fetching source code, etc. from the network (e.g.
‘src = fetchgit {…}’) rather than running commands like ‘git’ or ‘wget’
in the builder. If you need a particular program during the build, put
its package in a list called ‘buildInputs = […]’.

Inside the string ‘’’’ you put bash commands. Usually these come
straight from the project’s install instructions. This might include
running ‘make’, or using ‘sed’ to patch the source, etc. These commands
have access to a bash variable called $out. This is what Nix will add to
the store, for example ‘echo “hello” > “$out”’ will produce a file
containing ‘hello’. Most likely you’ll want to do ‘mkdir -p “$out/bin”’
and copy the compiled binaries into there.

Self-hosting compilers are tricky. Your choices are:

  • Fetch a pre-built binary from some URL and use that as your output.
    This is the easiest thing to do, e.g. if you just want to get your
    own FreeBASIC projects up and running and don’t want to bother
    maintaining the compiler itself. This approach probably wouldn’t be
    accepted into upstream nixpkgs, if you care about that.

  • Fetch a pre-built binary from some URL and use that to compile the
    compiler. This will give more flexibility, e.g. allowing package
    overrides to affect the compiler flags, etc. This is how GHC is
    packaged in nixpkgs, for example.

  • Package a different, non-self-hosting BASIC interpreter/compiler, and
    use that to compile FreeBASIC. This would be nicest, since it avoids
    the need for pre-built binaries; but there might not be any projects
    which are compatible enough with FreeBASIC to do this.

Once this is working, if you want it to be accepted into nixpkgs you
should then switch it over to using ‘stdenv.mkDerivation’, since that
has more hooks for people to override. ‘stdenv.mkDerivation’ splits up
the bash commands between “phases”, like ‘buildPhase’, ‘installPhase’,
‘checkPhase’, etc. so you should split up your bash commands
accordingly.

Finally (if you want to be in nixpkgs), you should add some metadata to
your expression (look at existing nixpkgs files for examples), add your
file to a clone of nixpkgs, then replace the ‘with import {};’
line with a list of arguments that you’ve used, e.g.
‘{ dependency1, fetchurl, stdenv }:’. Add a top-level ‘callPackage’ for
your file somewhere, like ‘pkgs/top-level/all-packages.nix’, then you
can open a pull request :slight_smile:

Good luck!