_(Draft of a new iteration of the project's documentation.)_ # Mu: a human-scale computer Mu is a minimal-dependency hobbyist computing stack (everything above the processor and OS kernel). Mu is not designed to operate in large clusters providing services for millions of people. Mu is designed for _you_, to run one computer. (Or a few.) Running the code you want to run, and nothing else. ```sh $ git clone https://github.com/akkartik/mu $ cd mu $ ./subx # requires C++ and Linux ``` [![Build Status](https://api.travis-ci.org/akkartik/mu.svg?branch=master)](https://travis-ci.org/akkartik/mu) There's a minimal number of layers of abstraction, every layer depends strictly on lower layers, and all levels have thorough automated tests, from machine code up. ## Goals In priority order: * [Reward curiosity.](http://akkartik.name/about) * Easy to build, easy to run. [Minimal dependencies](https://news.ycombinator.com/item?id=16882140#16882555), so that installation is always painless. * All design decisions comprehensible to a single individual. (On demand.) * All design decisions comprehensible without needing to talk to anyone. (I always love talking to you, but I try hard to make myself redundant.) * [A globally comprehensible _codebase_ rather than locally clean code.](http://akkartik.name/post/readable-bad) * Clear error messages over expressive syntax. * Safe. * Thorough test coverage. If you break something you should immediately see an error message. If you can manually test for something you should be able to write an automated test for it. * Memory leaks over memory corruption. * Teach the computer bottom-up. ## Non-goals * Efficiency. Clear programs over fast programs. * Portability. Runs on any computer as long as it's x86. * Compatibility. The goal is to get off mainstream stacks, not to perpetuate them. Sometimes the right long-term solution is to [bump the major version number](http://akkartik.name/post/versioning). * Syntax. Mu code is meant to be comprehended by [running, not just reading](http://akkartik.name/post/comprehension). ## What works so far Mu contains a type-safe, memory-safe and testable language where most statements map directly to a single CPU instruction. This language is built entirely in a notation called SubX for a subset of the x86 instruction set. The language is designed to be easy to implement in glorified machine code. (Some features will require multiple instructions for a statement: local variable definitions, array indexing with bounds checking, dereferencing heap allocations while protecting against freed memory.) ### SubX Here's a quick rundown of SubX's capabilities from the outside. For more details on the internal experience of the SubX notation itself, see [SubX.md](SubX.md). You can generate tiny zero-dependency ELF binaries with it. ```sh $ ./ntranslate init.linux examples/ex1.subx -o examples/ex1 $ ./examples/ex1 $ echo $? 42 ``` You can run the generated binaries on an interpreter/VM for better error messages. ```sh $ ./subx run examples/ex1 # on Linux or BSD or Mac $ echo $? 42 ``` Emulated runs can generate a trace that permits [time-travel debugging](https://github.com/akkartik/mu/blob/master/browse_trace/Readme.md). ```sh $ ./subx --debug translate init.linux examples/factorial.subx -o examples/factorial saving address->label information to 'labels' saving address->source information to 'source_lines' $ ./subx --debug --trace run examples/factorial saving trace to 'last_run' $ ./browse_trace/browse_trace last_run # text-mode debugger UI ``` You can write tests for your programs. The entire stack is thoroughly covered by automated tests. SubX's tagline: tests before syntax. ```sh $ ./subx test $ ./subx run apps/factorial test ``` You can package up SubX binaries with the minimal hobbyist OS [Soso](https://github.com/ozkl/soso) and run them on Qemu. (Requires graphics and sudo access. Currently doesn't work on a cloud server.) ```sh # dependencies $ sudo apt install util-linux nasm xorriso # maybe also dosfstools and mtools # package up a "hello world" program with a third-party kernel into mu_soso.iso # requires sudo $ ./gen_soso_iso init.soso examples/ex6.subx # try it out $ qemu-system-i386 -cdrom mu_soso.iso ``` You can also package up SubX binaries with a Linux kernel and run them on either Qemu or [a cloud server that supports custom images](http://akkartik.name/post/iso-on-linode). (Takes 12 minutes with 8GB RAM. Requires 12 million LoC of C for the Linux kernel; that number will gradually go down.) ```sh $ sudo apt install build-essential flex bison wget libelf-dev libssl-dev xorriso $ ./gen_linux_iso init.linux examples/ex6.subx $ qemu-system-x86_64 -m 256M -cdrom mu.iso -boot d ``` ## Conclusion The hypothesis of Mu and SubX is that designing the entire system to be testable from day 1 and from the ground up would radically impact the culture of the eco-system in a way that no bolted-on tool or service at higher levels can replicate: * Tests would make it easier to write programs that can be easily understood by newcomers. * More broad-based understanding would lead to more forks. * Tests would make it easy to share code across forks. Copy the tests over, and then copy code over and polish it until the tests pass. Manual work, but tractable and without major risks. * The community would gain a diversified portfolio of forks for each program, a “wavefront” of possible combinations of features and alternative implementations of features. Application writers who wrote thorough tests for their apps (something they just can’t do today) would be able to bounce around between forks more easily without getting locked in to a single one as currently happens. * There would be a stronger culture of reviewing the code for programs you use or libraries you depend on. [More eyeballs would make more bugs shallow.](https://en.wikipedia.org/wiki/Linus%27s_Law) To falsify these hypotheses, here's a roadmap of the next few planned features: * Testable, dependency-injected vocabulary of primitives - Streams: `read()`, `write()`. (✓) - `exit()` (✓) - Client-like non-blocking socket/file primitives: `load`, `save` - Concurrency, and a framework for testing blocking code - Server-like blocking socket/file primitives * Higher-level notations. Like programming languages, but with thinner implementations that you can -- and are expected to! -- modify. - syntax for addressing modes: `%reg`, `*reg`, `*(reg+disp)`, `*(reg+reg+disp)`, `*(reg+reg<