A blog that is a single executable binary
andreinc.net
andreinc.net
Doing it in C is pretty crazy, but it's pretty easy to do in either Go or Rust. No more difficult than writing a website in any other language. It's a great option if you want a high-performance (or low resource utilisation) website but with a little more dynamism than a static-site generator will easily allow.
It's possible that you could even use this to enumerate all the files in some directory, such that you wouldn't require source code changes in order to add a new post - you'd simply need to run the preprocessor again in a different build environment.
Also, in the spirit of the post: it should be relatively easy to implement this oneself with a build script in Rust. In Go I don't think it's as easy, and iirc the author of the package uses the semi-public 'build tags' API[2] (which always gave me a sense of being grudgingly released, in one of the countless "we core developers mustn't allow the unwashed hordes of lowly application developers to have these dangerous, powerful tools" fights that seem to characterise Go development).
[0] https://github.com/glassbearInc/rs-bindata
//go:embed player.html
var player_html []byteBut, yes, to samhw's issues, it is now trivial in Go and built into the standard library to embed arbitrary files and/or directories into a Go executable. Also have no idea what the "semi-grudging" comment about build tags are; they've been there since the beginning and heavily used by the Go standard library for many things. Go, of all languages lately, is the most comfortable with reserving things for the compiler/runtime; if they wanted to, they would have. It was always obvious that build tags were necessary and I don't see what's "grudging" about them at all.
let content: &'static str = include_str!("path/to/file");There's another crate includedir which looks more popular. It also supports compression. But if the file is stored in compressed form, looks like it also will (decompress/)copy into a fresh Vec, whether you request the uncompressed or compressed forms. [2] That's not what I would like. I'd prefer (lazily or eagerly) decompressing once and keeping it around in RAM for next time. YMMV.
I could use a high-quality implementation of this same idea. Personally I don't get using it for a personal blog (I'd rather be able to change the content without recompiling/restarting), but on my todo list is producing a zero-dependency, single-binary form of software I'm working on, including its web interface. I might end up writing my own.
[1] https://github.com/glassbearInc/rs-bindata/blob/93f61807b206...
[2] lines 59 and 80, respectively. https://github.com/tilpner/includedir/blob/6a81c906e233649af...
While I wouldn't do something like this for production (as most of us wouldn't), it's fun to do in C, especially just with the standard library. Feels like you have the entire world in your hands and you can do anything you want, as long as you don't segfault.
But, would it be possible to do something like this where new posts are appended to a binary? You have one executable, but then to update the content, new data is appended to that file?
I assume it’s possible, but I’m not familiar enough with executable formats to know where to start. I’m also not sure how this works security wise — but I again assume that you can update a file, even if the memory holding the code loaded from that file is protected from writes.
To help code legibility you could maybe put the socket functions in a separate file ? Or even make it a lib. (Though I admit it may go against your compactness goal). Same for HTTP stuff.
My website is one binary - https://news.ycombinator.com/item?id=30937515 - April 2022 (66 comments)
An idea for going further still would be a blog, including a content management system, that is a single, self-contained, self-modifying binary. Write a new blog post, save it and the executable modifies itself to contain the new post and be able to output it.
Just been crappy little experiments so far but I’ll prob push something out when I get some more time for it.
The Von Neumann architecture sounded good in the beginning when computers were hulking beasts and had to be timeshared to be economical. Scaling this to individual global-Internet-connected network PCs provided to be a disaster as is evidenced by all the "expert C programmers" over the years that couldn't keep their buffer overflows in their pants and things like NX support in CPUs and pointer authentication that just wouldn't have to exist if the CPU would get instructions from a 100% separate address space than its data (kinda like that old 8051 that's still kicking).
This is a terrible idea. Sorry.
In the end of the article I've told this should be taken lightly, as an exercise in minimalism and a joke.
Interesting choice. I'm now wondering whether the opposite approach might also be completely viable and surprisingly fast: it looks like the overhead of starting a process is single-digit miliseconds, so having a static binary that looks at PATH_INFO and returns content would work. Of course that's difficult to distinguish from just having a static site ..
If you've got a tiny little C program that doesn't do much DLL loading and runtime linking, and is likely already in cache to be memmapped directly into a process, and is shoveling out content with little-to-no computation you'll have a website that'll take an HN'ing without even noticing even on old hardware.
"A tiny little C program" worries me on other fronts, but there's a reasonable selection of things that are safe enough to put on the internet and still compile to single fast binaries that you could use in 2022. Alas, the options were not so nice in 2005.
A well configured valgrind scan during CI/CD phase and clang with all warnings should be enough to help with the traditional footguns.