Advent of Code in Odin

Setting up VS Code for Odin and AoC

October 7, 2024

I’ve been wanting to try Odin for a while now and decided it’s the language I’ll use for this year’s Advent of Code event.

For those unfamiliar, Advent of Code is a Christmas-themed annual event consisting of an advent calendar of programming puzzles. Each day, from the 1st of December to the 25th (inclusive), a puzzle is unlocked. Each puzzle consists of two parts, each requiring an answer. One star is earned per correct answer.

For those who want to take part competitively, there are public leaderboards as well as the option to create private ones.

It’s an excellent way to explore a language you’ve not used before or practice with one you’re already familiar with!

Before I could properly get familiar with Odin, I wanted to set up an easy way of building, debugging, and testing puzzle solutions in VS Code. I also wanted to be able to do these things easily on both Windows and Linux.

At the time of writing, there aren’t many public GitHub repos with the specific combination of Odin, VS Code and Advent of Code, and none of them felt suitable as a starting point (especially cross-platform), so I decided to put together some useful utils and VS Code configurations of my own.

First up were the tasks . I wanted to be able to do three things with these:

  • Build the package that the current file belongs to (which should, by Odin’s conventions, be the directory the file resides in).
  • Build any tests available in the package the current file belongs to.
  • Easily generate boilerplate for a new puzzle solution.

Odin comes with its own tool for managing Odin source code, including building and testing. It plays a similar role to Rust’s cargo. The first two tasks can be handled by odin build and odin test respectively, while the third can be handled by a utility written in Odin, which is then run with odin run using a user-defined name for the directory it should create.

Here’s what I came up with:

{
    "version": "2.0.0",
    "command": "",
    "args": [],
    "tasks": [
        {
            "label": "Init",
            "type": "shell",
            "command": "odin run ${workspaceFolder}/utils/init -out:build/util-init -- ${input:directoryName}",
            "windows": {
                "command": "odin run ${workspaceFolder}\\utils\\init -out:build\\util-init.exe -- ${input:directoryName}",
            },
            "problemMatcher": [],
            "group": "none"
        },
        {
            "label": "Build",
            "type": "shell",
            "command": "odin build ${relativeFileDirname} -debug -out:build/${relativeFileDirname}",
            "windows": {
                "command": "odin build ${relativeFileDirname} -debug -out:build\\${relativeFileDirname}.exe",
            },
            "group": "build"
        },
        {
            "label": "Test",
            "type": "shell",
            "command": "odin test ${relativeFileDirname} -debug -define:ODIN_TEST_SHORT_LOGS=true -out:build/${relativeFileDirname}-tests",
            "windows": {
                "command": "odin test ${relativeFileDirname} -debug -define:ODIN_TEST_SHORT_LOGS=true -out:build\\${relativeFileDirname}-tests.exe",
            },
            "problemMatcher": [],
            "group": "test"
        }
    ],
    "inputs": [
        {
            "id": "directoryName",
            "description": "Enter directory name",
            "type": "promptString",
            "default": "01"
        }
    ]
}
.vscode/tasks.json

(Note the “inputs” section—this is a useful feature that allows you to accept input from the user via a prompt.)

Next, the launch configurations . I just needed two—one for debugging a solution, and another for debugging its tests.

Originally, the plan was to make the same configurations work on both Windows and Linux, so I started down the path of using GDB as a debugger on both platforms. Unfortunately that didn’t work because Odin on Windows compiles via MSVC, which produces PDB files, which can’t be used by GDB. I’d have to either figure out how to make Odin use a different compiler on Windows (assuming that’s even possible) or use WSL2. I opted to create separate Windows-specific launch configs instead.

I ended up with this:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Debug",
            "type": "lldb",
            "request": "launch",
            "preLaunchTask": "Build",
            "program": "${workspaceFolder}/build/${relativeFileDirname}",
            "args": [],
            "cwd": "${workspaceFolder}/build"
        },
        {
            "name": "Debug tests",
            "type": "lldb",
            "request": "launch",
            "preLaunchTask": "Test",
            "program": "${workspaceFolder}/build/${relativeFileDirname}-tests",
            "args": [],
            "cwd": "${workspaceFolder}/build"
        },
        {
            "name": "(Windows) Debug",
            "type": "cppvsdbg",
            "request": "launch",
            "preLaunchTask": "Build",
            "program": "${workspaceFolder}\\build\\${relativeFileDirname}.exe",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}\\build",
            "environment": [],
            "console": "integratedTerminal"
        },
        {
            "name": "(Windows) Debug tests",
            "type": "cppvsdbg",
            "request": "launch",
            "preLaunchTask": "Test",
            "program": "${workspaceFolder}\\build\\${relativeFileDirname}-tests.exe",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}\\build",
            "environment": [],
            "console": "integratedTerminal"
        }
    ]
}
.vscode/launch.json

The lldb configuration type is provided by the CodeLLDB extension and the cppvsdbg type is provided by the C/C++ extension.

There is a slight caveat with the Debug tests configs in that they execute the tests twice—once without a debugger and again with. This is because the only way to build tests (as far as I can tell) is with odin test (hence that’s what the Test task uses). So Debug tests will run that first to get up-to-date test binaries, then launch the debugger. If I can figure out a way of building the tests without running them, I’ll update the config.

Other than that, it works pretty well. Now I can focus on writing some Odin and get some practice in before AoC 2024 begins!

If you’re interested in using the same setup for AoC, I created a GitHub template repo for it: