← Blog

Two files, not one — and we claimed one first

26 August 2026 · Mansour Ayouni

An early draft of this project's own design document promised that packaging a Ring program would produce a single self-contained file. It was written before anyone tested whether that was possible.

It was not. This post is about what actually ships, and about a habit worth more than the answer: the claim came first, and the measurement came second, and it should have been the other way round.

What was assumed

The idea seemed reasonable. Ring can already turn your program into a compact compiled form — a .ringo file — with no C compiler involved. Attach that to a small copy of Ring itself and you have one file the user double-clicks. Plenty of tools in other languages do exactly this.

Two things had to be true for it to work. Both were checked directly, and both were false.

the assumption what the test showed
Ring looks for a matching bytecode file next to the program when run with no arguments No. It does not look
Bytecode can be appended to the end of the executable and still be found No. Appending does nothing

So the honest artefact is a pair: yourprogram.exe and yourprogram.ringo, copied together and invoked together. That is what the documentation says now, in the same plain words, because a small true claim is worth more than a large one that fails on someone else's machine.

A correction, courtesy of Ring's own author

The day after this post went out, the author of Ring read it and pointed at an old, documented distribution trick. He was right in substance, we were right in the letter, and the difference earned its own finding.

Measured again, source in hand: Ring never looks for a bytecode file matching the program's name — the table above stands. But before reading a single argument, it looks in the current directory for a file named literally ring.ringo (or ring.ring) and runs it if found. Name the bytecode ring.ringo and the pair launches with no arguments at all — double-click included. The packaged program inherits this, because its runtime is Ring's own entry point: verified by renaming the bytecode beside a freshly packaged hello.exe and running it bare.

So our published sentence was bigger than our measurement: a same-named bytecode is not found; a fixed-named one is. The same mechanism hides a trap, recorded as finding F-35: a stray ring.ringo in your working directory silently hijacks every Ring invocation — even ring myfile.ring -go runs the stray file and ignores everything you typed.

What you actually get

Two files, and nothing else required on the target machine — no Ring installation, no compiler, no runtime to install first. Copy them to an empty folder on a machine that has never seen Ring and the program runs. That is verified in the test suite by doing exactly that.

Then is this a replacement for Ring's own packaging tool?

No, and it is not trying to be. Ring ships ring2exe, which produces a true single executable — by writing out a C file and handing it to a real C compiler on your machine.

That is a different bargain, not a worse one:

ring2exe

One self-contained file. Requires a working C compiler — Visual C++, GCC or Clang — installed and configured on the machine doing the packaging.

ringpp build

A pair of files. Requires no compiler at all, on any machine, ever — and can produce packages for five different systems from whichever one you happen to be sitting at.

If you need one file, use ring2exe — or Ring2EXE++, Youssef Saeed's cross-platform extension of it. They are the right tools for that, and Ring++ neither changes nor competes with them.

And what does "dependency-free" precisely mean?

It is a phrase that invites hand-waving, so here is the exact scope.

The library needs nothing but ordinary Ring. No extension to compile, no DLL, no toolchain. One load line.

The command-line tool needs nothing but itself. No C compiler on the user's machine, ever.

Two things are built into the tool before it reaches you, and they are named on the front page rather than tucked away: Ring's own grammar, written by Youssef Saeed, and the Zig toolchain that compiles the binary. Both are our cost to carry, not yours — nothing is fetched or built when you install.

The distinction that matters: dependency-free is a promise about your machine, not a boast about ours.

Next

Native build The one thing we refuse to package