toybox/www/design.html
<<
>>
Prefs
   1<html><head><title>The design of toybox</title></head>
   2<!--#include file="header.html" -->
   3
   4<h2>Topics</h2>
   5<ul>
   6<li><a href=#goals><h3>Design Goals</h3></a></li>
   7<li><a href=#portability><h3>Portability Issues</h3></a></li>
   8<li><a href=#license><h3>License</a></h3></a></li>
   9<li><a href=#codestyle><h3>Coding Style</h3></a></li>
  10</ul>
  11<hr />
  12
  13<a name="goals"><b><h2><a href="#goals">Design goals</a></h2></b>
  14
  15<p>Toybox should be simple, small, fast, and full featured. In that order.</p>
  16
  17<p>It should be possible to get about <a href=https://en.wikipedia.org/wiki/Pareto_principle>80% of the way</a> to each goal
  18before they really start to fight.
  19When these goals need to be balanced off against each other, keeping the code
  20as simple as it can be to do what it does is the most important (and hardest)
  21goal. Then keeping it small is slightly more important than making it fast.
  22Features are the reason we write code in the first place but this has all
  23been implemented before so if we can't do a better job why bother?</p>
  24
  25<b><h3>Features</h3></b>
  26
  27<p>Toybox should provide the command line utilities of a build
  28environment capable of recompiling itself under itself from source code.
  29This minimal build system conceptually consists of 4 parts: toybox,
  30a C library, a compiler, and a kernel. Toybox needs to provide all the
  31commands (with all the behavior) necessary to run the configure/make/install
  32of each package and boot the resulting system into a usable state.</p>
  33
  34<p>In addition, it should be possible to bootstrap up to arbitrary complexity
  35under the result by compiling and installing additional packages into this
  36minimal system, as measured by building both Linux From Scratch and the
  37Android Open Source Project under the result. Any "circular dependencies"
  38should be solved by toybox including the missing dependencies itself
  39(see "Shared Libraries" below).</p>
  40
  41<p>Toybox may also provide some "convenience" utilties
  42like top and vi that aren't necessarily used in a build but which turn
  43the minimal build environment into a minimal development environment
  44(supporting edit/compile/test cycles in a text console), configure
  45network infrastructure for communication with other systems (in a build
  46cluster), and so on.</p>
  47
  48<p>And these days toybox is the command line of Android, so anything the android
  49guys say to do gets at the very least closely listened to.</p>
  50
  51<p>The hard part is deciding what NOT to include. A project without boundaries
  52will bloat itself to death. One of the hardest but most important things a
  53project must do is draw a line and say "no, this is somebody else's problem,
  54not something we should do."
  55Some things are simply outside the scope of the project: even though
  56posix defines commands for compiling and linking, we're not going to include
  57a compiler or linker (and support for a potentially infinite number of hardware
  58targets). And until somebody comes up with a ~30k ssh implementation (with
  59a crypto algorithm that won't need replacing every 5 years), we're
  60going to point you at dropbear or bearssl.</p>
  61
  62<p>The <a href=roadmap.html>roadmap</a> has the list of features we're
  63trying to implement, and the reasons why we decided to include those
  64features. After the 1.0 release some of that material may get moved here,
  65but for now it needs its own page. The <a href=status.html>status</a>
  66page shows the project's progress against the roadmap.</p>
  67
  68<p>There are potential features (such as a screen/tmux implementation)
  69that might be worth adding after 1.0, in part because they could share
  70infrastructure with things like "less" and "vi" so might be less work for
  71us to do than for an external from scratch implementation. But for now, major
  72new features outside posix, android's existing commands, and the needs of
  73development systems, are a distraction from the 1.0 release.</p>
  74
  75<b><h3>Speed</h3></b>
  76
  77<p>Quick smoketest: use the "time" command, and if you haven't got a test
  78case that's embarassing enough to motivate digging, move on.</p>
  79
  80<p>It's easy to say a lot about optimizing for speed (which is why this section
  81is so long), but at the same time it's the optimization we care the least about.
  82The essence of speed is being as efficient as possible, which means doing as
  83little work as possible.  A design that's small and simple gets you 90% of the
  84way there, and most of the rest is either fine-tuning or more trouble than
  85it's worth (and often actually counterproductive).  Still, here's some
  86advice:</p>
  87
  88<p>First, understand the darn problem you're trying to solve.  You'd think
  89I wouldn't have to say this, and yet.  Trying to find a faster sorting
  90algorithm is no substitute for figuring out a way to skip the sorting step
  91entirely.  The fastest way to do anything is not to have to do it at all,
  92and _all_ optimization boils down to avoiding unnecessary work.</p>
  93
  94<p>Speed is easy to measure; there are dozens of profiling tools for Linux,
  95but sticking in calls to "millitime()" out of lib.c and subtracting
  96(or doing two clock_gettime() calls and then nanodiff() on them) is
  97quick and easy. Don't waste too much time trying to optimize something you
  98can't measure, and there's no much point speeding up things you don't spend
  99much time doing anyway.</p>
 100
 101<p>Understand the difference between throughput and latency.  Faster
 102processors improve throughput, but don't always do much for latency.
 103After 30 years of Moore's Law, most of the remaining problems are latency,
 104not throughput.  (There are of course a few exceptions, like data compression
 105code, encryption, rsync...)  Worry about throughput inside long-running
 106loops, and worry about latency everywhere else.  (And don't worry too much
 107about avoiding system calls or function calls or anything else in the name
 108of speed unless you are in the middle of a tight loop that's you've already
 109proven isn't running fast enough.)</p>
 110
 111<p>The lowest hanging optimization fruit is usually either "don't make
 112unnecessary copies of data" or "use a reasonable block size in your
 113I/O transactions instead of byte-at-a-time".
 114Start by looking for those, most of the rest of this advice is just explaining
 115why they're bad.</p>
 116
 117<p>"Locality of reference" is generally nice, in all sorts of contexts.
 118It's obvious that waiting for disk access is 1000x slower than doing stuff in
 119RAM (and making the disk seek is 10x slower than sequential reads/writes),
 120but it's just as true that a loop which stays in L1 cache is many times faster
 121than a loop that has to wait for a DRAM fetch on each iteration.  Don't worry
 122about whether "&" is faster than "%" until your executable loop stays in L1
 123cache and the data access is fetching cache lines intelligently.  (To
 124understand DRAM, L1, and L2 cache, read Hannibal's marvelous ram guide at Ars
 125Technica:
 126<a href=http://arstechnica.com/paedia/r/ram_guide/ram_guide.part1-2.html>part one</a>,
 127<a href=http://arstechnica.com/paedia/r/ram_guide/ram_guide.part2-1.html>part two</a>,
 128<a href=http://arstechnica.com/paedia/r/ram_guide/ram_guide.part3-1.html>part three</a>,
 129plus this
 130<a href=http://arstechnica.com/articles/paedia/cpu/caching.ars/1>article on
 131cacheing</a>, and this one on
 132<a href=http://arstechnica.com/articles/paedia/cpu/bandwidth-latency.ars>bandwidth
 133and latency</a>.
 134And there's <a href=http://arstechnica.com/paedia/index.html>more where that came from</a>.)
 135Running out of L1 cache can execute one instruction per clock cycle, going
 136to L2 cache costs a dozen or so clock cycles, and waiting for a worst case dram
 137fetch (round trip latency with a bank switch) can cost thousands of
 138clock cycles.  (Historically, this disparity has gotten worse with time,
 139just like the speed hit for swapping to disk.  These days, a _big_ L1 cache
 140is 128k and a big L2 cache is a couple of megabytes.  A cheap low-power
 141embedded processor may have 8k of L1 cache and no L2.)</p>
 142
 143<p>Learn how <a href=http://nommu.org/memory-faq.txt>virtual memory and
 144memory managment units work</a>.  Don't touch
 145memory you don't have to.  Even just reading memory evicts stuff from L1 and L2
 146cache, which may have to be read back in later.  Writing memory can force the
 147operating system to break copy-on-write, which allocates more memory.  (The
 148memory returned by malloc() is only a virtual allocation, filled with lots of
 149copy-on-write mappings of the zero page.  Actual physical pages get allocated
 150when the copy-on-write gets broken by writing to the virtual page.  This
 151is why checking the return value of malloc() isn't very useful anymore, it
 152only detects running out of virtual memory, not physical memory.  Unless
 153you're using a <a href=http://nommu.org>NOMMU system</a>, where all bets
 154are off.)</p>
 155
 156<p>Don't think that just because you don't have a swap file the system can't
 157start swap thrashing: any file backed page (ala mmap) can be evicted, and
 158there's a reason all running programs require an executable file (they're
 159mmaped, and can be flushed back to disk when memory is short).  And long
 160before that, disk cache gets reclaimed and has to be read back in.  When the
 161operating system really can't free up any more pages it triggers the out of
 162memory killer to free up pages by killing processes (the alternative is the
 163entire OS freezing solid).  Modern operating systems seldom run out of
 164memory gracefully.</p>
 165
 166<p>It's usually better to be simple than clever. Many people think that mmap()
 167is faster than read() because it avoids a copy, but twiddling with the memory
 168management is itself slow, and can cause unnecessary CPU cache flushes.  And
 169if a read faults in dozens of pages sequentially, but your mmap iterates
 170backwards through a file (causing lots of seeks, each of which your program
 171blocks waiting for), the read can be many times faster.  On the other hand, the
 172mmap can sometimes use less memory, since the memory provided by mmap
 173comes from the page cache (allocated anyway), and it can be faster if you're
 174doing a lot of different updates to the same area.  The moral?  Measure, then
 175try to speed things up, and measure again to confirm it actually _did_ speed
 176things up rather than made them worse.  (And understanding what's really going
 177on underneath is a big help to making it happen faster.)</p>
 178
 179<p>Another reason to be simple than clever is optimization
 180strategies change with time.  For example, decades ago precalculating a table
 181of results (for things like isdigit() or cosine(int degrees)) was clearly
 182faster because processors were so slow.  Then processors got faster and grew
 183math coprocessors, and calculating the value each time became faster than
 184the table lookup (because the calculation fit in L1 cache but the lookup
 185had to go out to DRAM).  Then cache sizes got bigger (the Pentium M has
 1862 megabytes of L2 cache) and the table fit in cache, so the table became
 187fast again...  Predicting how changes in hardware will affect your algorithm
 188is difficult, and using ten year old optimization advice can produce
 189laughably bad results.  Being simple and efficient should give at least a
 190reasonable starting point.</p>
 191
 192<p>Even at the design level, a lot of simple algorithms scale terribly but
 193perform fine with small data sets. When small datasets are the common case,
 194"better" versions that trade higher throughput for worse latency can
 195consistently perform worse.
 196So if you think you're only ever going to feed the algorithm small data sets,
 197maybe just do the simple thing and wait for somebody to complain. For example,
 198you probably don't need to sort and binary search the contents of
 199/etc/passwd, because even 50k users is still a reasonably manageable data
 200set for a readline/strcmp loop, and that's the userbase of a fairly major
 201<a href=https://en.wikipedia.org/wiki/List_of_United_States_public_university_campuses_by_enrollment>university</a>.
 202Instead commands like "ls" call bufgetpwuid() out of lib/lib.c
 203which keeps a linked list of recently seen items, avoiding reparsing entirely
 204and trusting locality of reference to bring up the same dozen or so entries
 205for "ls -l /dev" or similar. The pathological failure mode of "simple
 206linked list" is to perform exactly as badly as constantly rescanning a
 207huge /etc/passwd, so this simple optimization shouldn't ever make performance
 208worse (modulo possible memory exhaustion and thus swap thrashing).
 209On the other hand, toybox's multiplexer does sort and binary
 210search its command list to minimize the latency of each command startup,
 211because the sort is a compile-time cost done once per build,
 212and the whole of command startup
 213is a "hot path" that should do as little work as possible because EVERY
 214command has to go through it every time before performing any other function
 215so tiny gains are worthwhile. (These decisions aren't perfect, the point is
 216to show that thought went into them.)</p>
 217
 218<p>The famous quote from Ken Thompson, "When in doubt, use brute force",
 219applies to toybox.  Do the simple thing first, do as little of it as possible,
 220and make sure it's right.  You can always speed it up later.</p>
 221
 222<b><h3>Size</h3></b>
 223<p>Quick smoketest: build toybox with and without the command (or the change),
 224and maybe run "nm --size-sort" on files in generated/unstripped.
 225(See make bloatcheck below for toybox's built in nm size diff-er.)</p>
 226
 227<p>Again, being simple gives you most of this. An algorithm that does less work
 228is generally smaller. Understand the problem, treat size as a cost, and
 229get a good bang for the byte.</p>
 230
 231<p>What "size" means depends on context: there are at least a half dozen
 232different metrics in two broad categories: space used on disk/flash/ROM,
 233and space used in memory at runtime.</p>
 234
 235<p>Your executable file has at least
 236four main segments (text = executable code, rodata = read only data,
 237data = writeable variables initialized to a value other than zero,
 238bss = writeable data initialized to zero). Text and rodata are shared between multiple instances of the program running
 239simultaneously, the other 4 aren't. Only text, rodata, and data take up
 240space in the binary, bss, stack and heap only matter at runtime. You can
 241view toybox's symbols with "nm generated/unstripped/toybox", the T/R/D/B
 242lets you know the segment the symbol lives in. (Lowercase means it's
 243local/static.)</p>
 244
 245<p>Then at runtime there's
 246heap size (where malloc() memory lives) and stack size (where local
 247variables and function call arguments and return addresses live). And
 248on 32 bit systems mmap() can have a constrained amount of virtual memory
 249(usually a couple gigabytes: the limits on 64 bit systems are generally big
 250enough it doesn't come up)</p>
 251
 252<p>Optimizing for binary size is generally good: less code is less to go
 253wrong, and executing fewer instructions makes your program run faster (and
 254fits more of it in cache). On embedded systems, binary size is especially
 255precious because flash is expensive and code may need binary auditing for
 256security. Small stack size
 257is important for nommu systems because they have to preallocate their stack
 258and can't make it bigger via page fault. And everybody likes a small heap.</p>
 259
 260<p>Measure the right things. Especially with modern optimizers, expecting
 261something to be smaller is no guarantee it will be after the compiler's done
 262with it. Will total binary size is the final result, it isn't always the most
 263accurate indicator of the impact of a given change, because lots of things
 264get combined and rounded during compilation and linking (and things like
 265ASAN disable optimization). Toybox has scripts/bloatcheck to compare two versions
 266of a program and show size changes in each symbol (using "nm --size-sort").
 267You can "make baseline" to build a baseline version to compare against,
 268and then apply your changes and "make bloatcheck" to compare against
 269the saved baseline version.</p>
 270
 271<p>Avoid special cases. Whenever you see similar chunks of code in more than
 272one place, it might be possible to combine them and have the users call shared
 273code (perhaps out of lib/*.c). This is the most commonly cited trick, which
 274doesn't make it easy to work out HOW to share. If seeing two lines of code do
 275the same thing makes you slightly uncomfortable, you've got the right mindset,
 276but "reuse" requires the "re" to have benefit, and infrastructure in search
 277of a user will generally bit-rot before it finds one.</p>
 278
 279<p>The are a lot of potential microoptimizations (on some architectures
 280using char instead of int as a loop index is noticeably slower, on some
 281architectures C bitfields are surprisingly inefficient, & is often faster
 282than % in a tight loop, conditional assignment avoids branch prediction
 283failures...) but they're generally not worth doing unless you're trying to
 284speed up the middle of a tight inner loop chewing through a large amount
 285of data (such as a compression algorithm). For data pumps sane blocking
 286and fewer system calls (buffer some input/output and do a big read/write
 287instead of a bunch of little small ones) is usually the big win. But
 288be careful about cacheing stuff: the two persistently hard problems in computer
 289science are naming things, cache coherency, and off by one errors.</p>
 290
 291<b><h3>Simplicity</h3></b>
 292
 293<p>Complexity is a cost, just like code size or runtime speed. Treat it as
 294a cost, and spend your complexity budget wisely. (Sometimes this means you
 295can't afford a feature because it complicates the code too much to be
 296worth it.)</p>
 297
 298<p>Simplicity has lots of benefits.  Simple code is easy to maintain, easy to
 299port to new processors, easy to audit for security holes, and easy to
 300understand.</p>
 301
 302<p>Simplicity itself can have subtle non-obvious aspects requiring a tradeoff
 303between one kind of simplicity and another: simple for the computer to
 304execute and simple for a human reader to understand aren't always the
 305same thing. A compact and clever algorithm that does very little work may
 306not be as easy to explain or understand as a larger more explicit version
 307requiring more code, memory, and CPU time. When balancing these, err on the
 308side of doing less work, but add comments describing how you
 309could be more explicit.</p>
 310
 311<p>In general, comments are not a substitute for good code (or well chosen
 312variable or function names). Commenting "x += y;" with "/* add y to x */"
 313can actually detract from the program's readability. If you need to describe
 314what the code is doing (rather than _why_ it's doing it), that means the
 315code itself isn't very clear.</p>
 316
 317<p>Environmental dependencies are another type of complexity, so needing other
 318packages to build or run is a big downside. For example, we don't use curses
 319when we can simply output ansi escape sequences and trust all terminal
 320programs written in the past 30 years to be able to support them. Regularly
 321testing that we work with C libraries which support static linking (musl does,
 322glibc doesn't) is another way to be self-contained with known boundaries:
 323it doesn't have to be the only way to build the project, but should be regularly
 324tested and supported.</p>
 325
 326<p>Prioritizing simplicity tends to serve our other goals: simplifying code
 327generally reduces its size (both in terms of binary size and runtime memory
 328usage), and avoiding unnecessary work makes code run faster. Smaller code
 329also tends to run faster on modern hardware due to CPU cacheing: fitting your
 330code into L1 cache is great, and staying in L2 cache is still pretty good.</p>
 331
 332<p>But a simple implementation is not always the smallest or fastest, and
 333balancing simplicity vs the other goals can be difficult. For example, the
 334atolx_range() function in lib/lib.c always uses the 64 bit "long long" type,
 335which produces larger and slower code on 32 bit platforms and
 336often assigned into smaller interger types. Although libc has parallel
 337implementations for different data sizes (atoi, atol, atoll) we chose a
 338common codepath which can cover all cases (every user goes through the
 339same codepath, with the maximum amount of testing and minimum and avoids
 340surprising variations in behavior).</p>
 341
 342<p>On the other hand, the "tail" command has two codepaths, one for seekable
 343files and one for nonseekable files. Although the nonseekable case can handle
 344all inputs (and is required when input comes from a pipe or similar, so cannot
 345be removed), reading through multiple gigabytes of data to reach the end of
 346seekable files was both a common case and hugely penalized by a nonseekable
 347approach (half-minute wait vs instant results). This is one example
 348where performance did outweigh simplicity of implementation.</p>
 349
 350<p><a href=http://www.joelonsoftware.com/articles/fog0000000069.html>Joel
 351Spolsky argues against throwing code out and starting over</a>, and he has
 352good points: an existing debugged codebase contains a huge amount of baked
 353in knowledge about strange real-world use cases that the designers didn't
 354know about until users hit the bugs, and most of this knowledge is never
 355explicitly stated anywhere except in the source code.</p>
 356
 357<p>That said, the Mythical Man-Month's "build one to throw away" advice points
 358out that until you've solved the problem you don't properly understand it, and
 359about the time you finish your first version is when you've finally figured
 360out what you _should_ have done.  (The corrolary is that if you build one
 361expecting to throw it away, you'll actually wind up throwing away two.  You
 362don't understand the problem until you _have_ solved it.)</p>
 363
 364<p>Joel is talking about what closed source software can afford to do: Code
 365that works and has been paid for is a corporate asset not lightly abandoned.
 366Open source software can afford to re-implement code that works, over and
 367over from scratch, for incremental gains.  Before toybox, the unix command line
 368has already been reimplemented from scratch several times (the
 369original AT&amp;T Unix command line in assembly and then in C, the BSD
 370versions, Coherent was the first full from-scratch Unix clone in 1980,
 371Minix was another clone which Linux was inspired by and developed under,
 372the GNU tools were yet another rewrite intended for use in the stillborn
 373"Hurd" project, BusyBox was still another rewrite, and more versions
 374were written in Plan 9, uclinux, klibc, sash, sbase, s6, and of course
 375android toolbox...). But maybe toybox can do a better job. :)</p>
 376
 377<p>As Antoine de St. Exupery (author of "The Little Prince" and an early
 378aircraft designer) said, "Perfection is achieved, not when there
 379is nothing left to add, but when there is nothing left to take away."
 380And Ken Thompson (creator of Unix) said "One of my most productive
 381days was throwing away 1000 lines of code." It's always possible to
 382come up with a better way to do it.</p>
 383
 384<p>P.S. How could I resist linking to an article about
 385<a href=http://blog.outer-court.com/archive/2005-08-24-n14.html>why
 386programmers should strive to be lazy and dumb</a>?</p>
 387
 388<hr>
 389<a name="portability"><b><h2><a href="#portability">Portability issues</a></h2></b>
 390
 391<b><h3>Platforms</h3></b>
 392<p>Toybox should run on Android (all commands with musl-libc, as large a subset
 393as practical with bionic), and every other hardware platform Linux runs on.
 394Other posix/susv4 environments (perhaps MacOS X or newlib+libgloss) are vaguely
 395interesting but only if they're easy to support; I'm not going to spend much
 396effort on them.</p>
 397
 398<p>I don't do windows.</p>
 399
 400<a name="standards" />
 401<b><h3>Standards</h3></b>
 402
 403<p>Toybox is implemented with reference to
 404<a href=https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1548.pdf>c11</a>,
 405<a href=roadmap.html#susv4>Posix 2008</a>,
 406<a href=#bits>LP64</a>,
 407<a href=roadmap.html#sigh>LSB 4.1</a>,
 408the <a href=https://www.kernel.org/doc/man-pages/>Linux man pages</a>,
 409various <a href=https://www.rfc-editor.org/rfc-index.html>IETF RFCs</a>,
 410the linux kernel source's
 411<a href=https://www.kernel.org/doc/Documentation/>Documentation</a> directory,
 412utf8 and unicode, and our terminal control outputs ANSI
 413<a href=https://man7.org/linux/man-pages/man4/console_codes.4.html>escape sequences</a>.
 414Toybox gets <a href=faq.html#cross>tested</a> with gcc and llvm on glibc,
 415musl-libc, and bionic, plus occasional <a href=https://github.com/landley/toybox/blob/master/kconfig/freebsd_miniconfig>FreeBSD</a> and
 416<a href=https://github.com/landley/toybox/blob/master/kconfig/macos_miniconfig>MacOS</a> builds for subsets
 417of the commands.</p>
 418
 419<p>For the build environment and runtime environment, toybox depends on
 420posix-2008 libc features such as the openat() family of
 421functions. We also root around in the linux /proc directory a lot (no other
 422way to implement "ps" at the moment), and assume certain "modern" linux kernel
 423behavior (for example <a href=https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b6a2fea39318>linux 2.6.22</a>
 424expanded the 128k process environment size limit to 2 gigabytes, then it was
 425trimmed back down to 10 megabytes, and when I asked for a way to query the
 426actual value from the kernel if it was going to keep changing
 427like that <a href=https://lkml.org/lkml/2017/11/5/204>Linus declined</a>).
 428We make an effort to support <a href=faq.html#support_horizon>older kernels</a>
 429and other implementations (primarily MacOS and BSD) but we don't always
 430police their corner cases very closely.</p>
 431
 432<p><b>Why not just use the newest version of each standard?</b>
 433
 434<p>Partly to <a href=faq.html#support_horizon>support older systems</a>:
 435you can't fix a bug in the old system if you can't build in the old
 436environment.</p>
 437
 438<p>Partly because toybox's maintainer has his own corollary to Moore's law:
 43950% of what you know about programming the hardware is obsolete every 18
 440months, but the advantage of C &amp; Unix it's usually the same 50% cycling
 441out over and over.</p>
 442
 443<p>But mostly because the updates haven't added anything we care about.
 444Posix-2008 switched some things to larger (64 bit) data types and added the
 445openat() family of functions (which take a directory filehandle instead of
 446using the Current Working Directory),
 447but the 2013 and 2018 releases of posix were basically typo fixes: still
 448release 7, still SUSv4. (An eventual release 8 might be interesting but
 449it's not out yet.)</p>
 450
 451<p>We're nominally C11 but mostly just writing good old ANSI C (I.E. C89).
 452We use a few of the new features like compound literals (6.5.2.5) and structure
 453initialization by member name with unnamed members zeroed (6.7.9),
 454but mostly we "officially" went from c99 to C11 to work around a
 455<a href=https://github.com/landley/toybox/commit/3625a260065b>clang compiler bug</a>.
 456The main thing we use from c99 that c89 hadn't had was // single line comments.
 457(We mostly don't even use C99's explicit width data types, ala uint32_t and
 458friends, because LP64 handles that for us.)</p>
 459
 460<p>We're ignoring new versions of the Linux Foundation's standards (LSB, FHS)
 461entirely, for the same reason Debian is: they're not good at maintaining
 462standards. (The Linux Foundation acquiring the Free Standards Group worked
 463out about as well as Microsoft buying Nokia, Twitter buying Vine, Yahoo
 464buying Flickr...)</p>
 465
 466<p>We refer to current versions of man7.org because it's
 467not easily versioned (the website updates regularly) and because
 468Michael Kerrisk does a good job maintaining it so far. That said, we
 469try to "provide new" in our commands but "depend on old" in our build scripts.
 470(For example, we didn't start using "wait -n" until it had been in bash for 7
 471years, and even then people depending on Centos' 10 year support horizon
 472complained.)</p>
 473
 474<p>Using newer vs older RFCs, and upgrading between versions, is a per-case
 475judgement call.</p>
 476
 477<p><b>How strictly do you adhere to these standards?</b>
 478
 479<p>...ish? The man pages have a lot of stuff that's not in posix,
 480and there's no "init" or "mount" in posix, you can't implement "ps"
 481without replying on non-posix APIs....</p>
 482
 483<p>When the options a command offers visibly contradict posix, we try to have
 484a "deviations from posix" section at the top of the source listing the
 485differences, but that's about what we provide not what we used from the OS
 486or build environment.</p>
 487
 488<p>The build needs bash (not a pure-posix sh), and building on MacOS requires
 489"gsed" (because Mac's sed is terrible), but toybox is explicitly self-hosting
 490and any failure to build under the tool versions we provide would be a bug
 491needing to be fixed.</p>
 492
 493<p>Within the code, everything in main.c and lib/*.c has to build
 494on every supported Linux version, compiler, and library, plus BSD and MacOS.
 495We mostly try to keep #if/else staircases for portability issues to
 496lib/portability.[ch].</p>
 497
 498<p>Portability of individual commands varies: we sometimes program directly
 499against linux kernel APIs (unavoidable when accessing /proc and /sys),
 500individual commands are allowed to #include &lt;linux/*.h&gt; (common
 501headers and library files are not, except maybe lib/portability.* within an
 502appropriate #ifdef),  we only really test against Linux errno values
 503(unless somebody on BSD submits a bug), and a few commands outright cheat
 504(the way ifconfig checks for ioctl numbers in the 0x89XX range). This is
 505the main reason some commands build on BSD/MacOS and some don't.</p>
 506
 507<a name="bits" />
 508<b><h3>32/64 bit</h3></b>
 509<p>Toybox should work on both 32 bit and 64 bit systems. 64 bit desktop
 510hardware went mainstream <a href=https://web.archive.org/web/20040307000108mp_/http://developer.intel.com/technology/64bitextensions/faq.htm>in 2005</a>
 511and was essentially ubiquitous <a href=faq.html#support_horizon>by 2012</a>,
 512but 32 bit hardware will continue to be important in embedded devices for years to come.</p>
 513
 514<p>Toybox relies on the
 515<a href=http://archive.opengroup.org/public/tech/aspen/lp64_wp.htm>LP64 standard</a>
 516which Linux, MacOS X, and BSD all implement, and which modern 64 bit processors such as
 517x86-64 were <a href=http://www.pagetable.com/?p=6>explicitly designed to
 518support</a>. (Here's the original <a href=https://web.archive.org/web/20020905181545/http://www.unix.org/whitepapers/64bit.html>LP64 white paper</a>.)</p>
 519
 520<p>LP64 defines explicit sizes for all the basic C integer types, and
 521guarantees that on any Unix-like platform "long" and "pointer" types
 522are always the same size (the processor's register size).
 523This means it's safe to assign pointers into
 524longs and vice versa without losing data: on 32 bit systems both are 32 bit,
 525on 64 bit systems both are 64 bit.</p>
 526
 527<table border=1 cellpadding=10 cellspacing=2>
 528<tr><td>C type</td><td>char</td><td>short</td><td>int</td><td>long</td><td>long long</td></tr>
 529<tr><td>32 bit<br />sizeof</td><td>8 bits</td><td>16 bits</td><td>32 bits</td><td>32 bits</td><td>64 bits</td></tr>
 530<tr><td>64 bit<br />sizeof</td><td>8 bits</td><td>16 bits</td><td>32 bits</td><td>64 bits</td><td>64 bits</td></tr>
 531</table>
 532
 533<p>LP64 eliminates the need to use c99 "uint32_t" and friends: the basic
 534C types all have known size/behavior, and the only type whose
 535size varies is "long", which is the natural register size of the processor.</p>
 536
 537<p>Note that Windows doesn't work like this, and I don't care, but if you're
 538curious here are <a href=https://devblogs.microsoft.com/oldnewthing/20050131-00/?p=36563>the insane legacy reasons why this is broken on Windows</a>.</a></p>
 539
 540<p>The main squishy bit in LP64 is that "long long" was defined as
 541"at least" 64 bits instead of "exactly" 64 bits, and the standards body
 542that issued it collapsed in the wake of the <a href=https://en.wikipedia.org/wiki/Unix_wars>proprietary unix wars</a> (all
 543those lawsuits between AT&amp;T/BSDI/Novell/Caldera/SCO), so is
 544not available to issue an official correction. Then again a processor
 545with 128-bit general purpose registers wouldn't be commercially viable
 546<a href=https://landley.net/notes-2011.html#26-06-2011>until 2053</a>
 547(because 2005+32*1.5), and with the S-curve of Moore's Law slowly
 548<a href=http://www.acm.org/articles/people-of-acm/2016/david-patterson>bending back down</a> as
 549atomic limits and <a href=http://www.cnet.com/news/end-of-moores-law-its-not-just-about-physics/>exponential cost increases</a> produce increasing
 550drag.... (The original Moore's Law curve would mean that in the year 2022
 551a high end workstation would have around 8 terabytes of RAM, available retail.
 552Most don't even come with
 553that much disk space.) At worst we don't need to care for decades, the
 554S-curve bending down means probably not in our lifetimes, and
 555atomic limits may mean "never". So I'm ok treating "long long" as exactly 64 bits.</p>
 556
 557<b><h3>Signedness of char</h3></b>
 558<p>On platforms like x86, variables of type char default to unsigned.  On
 559platforms like arm, char defaults to signed.  This difference can lead to
 560subtle portability bugs, and to avoid them we specify which one we want by
 561feeding the compiler -funsigned-char.</p>
 562
 563<p>The reason to pick "unsigned" is that way char strings are 8-bit clean by
 564default, which makes UTF-8 support easier.</p>
 565
 566<p><h3>Error messages and internationalization:</h3></p>
 567
 568<p>Error messages are extremely terse not just to save bytes, but because we
 569don't use any sort of _("string") translation infrastructure. (We're not
 570translating the command names themselves, so we must expect a minimum amount of
 571english knowledge from our users, but let's keep it to a minimum.)</p>
 572
 573<p>Thus "bad -A '%c'" is
 574preferable to "Unrecognized address base '%c'", because a non-english speaker
 575can see that -A was the problem (giving back the command line argument they
 576supplied). A user with a ~20 word english vocabulary is
 577more likely to know (or guess) "bad" than the longer message, and you can
 578use "bad" in place of "invalid", "inappropriate", "unrecognized"...
 579Similarly when atolx_range() complains about range constraints with
 580"4 < 17" or "12 > 5", it's intentional: those don't need to be translated.</p>
 581
 582<p>The strerror() messages produced by perror_exit() and friends should be
 583localized by libc, and our error functions also prepend the command name
 584(which non-english speakers can presumably recognize already). Keep the
 585explanation in between to a minimum, and where possible feed back the values
 586they passed in to identify _what_ we couldn't process.
 587If you say perror_exit("setsockopt"), you've identified the action you
 588were trying to take, and the perror gives a translated error message (from libc)
 589explaining _why_ it couldn't do it, so you probably don't need to add english
 590words like "failed" or "couldn't assign".</p>
 591
 592<p>All commands should be 8-bit clean, with explicit
 593<a href=http://yarchive.net/comp/linux/utf8.html>UTF-8</a> support where
 594necessary. Assume all input data might be utf8, and at least preserve
 595it and pass it through. (For this reason, our build is -funsigned-char on
 596all architectures; "char" is unsigned unless you stick "signed" in front
 597of it.)</p>
 598
 599<p>Locale support isn't currently a goal; that's a presentation layer issue
 600(I.E. a GUI problem).</p>
 601
 602<p>Someday we should probably have translated --help text, but that's a
 603post-1.0 issue.</p>
 604
 605<p><h3>Shared Libraries</h3></p>
 606
 607<p>Toybox's policy on shared libraries is that they should never be
 608required, but can optionally be used to improve performance.</p>
 609
 610<p>Toybox should provide the command line utilities for
 611<a href=roadmap.html#dev_env>self-hosting development envirionments</a>,
 612and an easy way to set up "hermetic builds" (I.E. builds which provide
 613their own dependencies, isolating the build logic from host command version
 614skew with a simple known build environment). In both cases, external
 615dependencies defeat the purpose.</p>
 616
 617<p>This means toybox should provide full functionality without relying
 618on any external dependencies (other than libc). But toybox may optionally use
 619libraries such as zlib and openssl to improve performance for things like
 620deflate and sha1sum, which lets the corresponding built-in implementations
 621be simple (and thus slow). But the built-in implementations need to exist and
 622work.</p>
 623
 624<p>(This is why we use an external https wrapper program, because depending on
 625openssl or similar to be linked in would change the behavior of toybox.)</p>
 626
 627<hr /><a name="license" /><h2>License</h2>
 628
 629<p>Toybox is licensed <a href=license.html>0BSD</a>, which is a public domain
 630equivalent license approved by <a href=https://spdx.org/licenses/0BSD.html>SPDX</a>. This works like other BSD licenses except that it doesn't
 631require copying specific license text into the resulting project when
 632you copy code. (We care about attribution, not ownership, and the internet's
 633really good at pointing out plagiarism.)</p>
 634
 635<p>This means toybox usually can't use external code contributions, and must
 636implement new versions of everything unless the external code's original
 637author (and any additional contributors) grants permission to relicense.
 638Just as a GPLv2 project can't incorporate GPLv3 code and a BSD-licensed
 639project can't incorporate either kind of GPL code, we can't incorporate
 640most BSD or Apache licensed code without changing our license terms.</p>
 641
 642<p>The exception to this is code under an existing public domain equivalent
 643license, such as the xz decompressor or
 644<a href=https://github.com/mkj/dropbear/blob/master/libtommath/LICENSE>libtommath</a> and <a href=https://github.com/mkj/dropbear/blob/master/libtomcrypt/LICENSE>libtomcrypt</a>.</p>
 645
 646<hr /><a name="codestyle" /><h2>Coding style</h2>
 647
 648<p>The real coding style holy wars are over things that don't matter
 649(whitespace, indentation, curly bracket placement...) and thus have no
 650obviously correct answer. As in academia, "the fighting is so vicious because
 651the stakes are so small". That said, being consistent makes the code readable,
 652so here's how to make toybox code look like other toybox code.</p>
 653
 654<p>Toybox source uses two spaces per indentation level, and wraps at 80
 655columns. (Indentation of continuation lines is awkward no matter what
 656you do, sometimes two spaces looks better, sometimes indenting to the
 657contents of a parentheses looks better.)</p>
 658
 659<p>I'm aware this indentation style creeps some people out, so here's
 660the sed invocation to convert groups of two leading spaces to tabs:</p>
 661<blockquote><pre>
 662sed -i ':loop;s/^\( *\)  /\1\t/;t loop' filename
 663</pre></blockquote>
 664
 665<p>And here's the sed invocation to convert leading tabs to two spaces each:</p>
 666<blockquote><pre>
 667sed -i ':loop;s/^\( *\)\t/\1  /;t loop' filename
 668</pre></blockquote>
 669
 670<p>There's a space after C flow control statements that look like functions, so
 671"if (blah)" instead of "if(blah)". (Note that sizeof is actually an
 672operator, so we don't give it a space for the same reason ++ doesn't get
 673one. Yeah, it doesn't need the parentheses either, but it gets them.
 674These rules are mostly to make the code look consistent, and thus easier
 675to read.) We also put a space around assignment operators (on both sides),
 676so "int x = 0;".</p>
 677
 678<p>Blank lines (vertical whitespace) go between thoughts. "We were doing that,
 679now we're doing this." (Not a hard and fast rule about _where_ it goes,
 680but there should be some for the same reason writing has paragraph breaks.)</p>
 681
 682<p>Variable declarations go at the start of blocks, with a blank line between
 683them and other code. Yes, c99 allowed you to put them anywhere, but they're
 684harder to find if you do that. If there's a large enough distance between
 685the declaration and the code using it to make you uncomfortable, maybe the
 686function's too big, or is there an if statement or something you can
 687use as an excuse to start a new closer block? Use a longer variable name
 688that's easier to search for perhaps?</p>
 689
 690<p>An * binds to a variable name not a type name, so space it that way.
 691(In C "char *a, b;" and "char* a, b;" mean the same thing: "a" is a pointer
 692but "b" is not. Spacing it the second way is not how C works.)</p>
 693
 694<p>We wrap lines at 80 columns. Part of the reason for this I (toybox's
 695founder Rob) have mediocre eyesight (so tend to increase the font size in
 696terminal windows and web browsers), and program in a lot of coffee shops
 697on laptops with a smallish sceen. I'm aware this <a href=http://lkml.iu.edu/hypermail/linux/kernel/2005.3/08168.html>exasperates Linus torvalds</a>
 698(with his 8-character tab indents where just being in a function eats 8 chars
 699and 4 more indent levels eats half of an 80 column terminal), but you've
 700gotta break somewhere and even Linus admits there isn't another obvious
 701place to do so. (80 columns came from punched cards, which came
 702from civil war era dollar bill sorting boxes IBM founder Herman Hollerith
 703bought secondhand when bidding to run the 1890 census. "Totally arbitrary"
 704plus "100 yeas old" = standard.)</p>
 705
 706<p>If statements with a single line body go on the same line when the result
 707fits in 80 columns, on a second line when it doesn't. We usually only use
 708curly brackets if we need to, either because the body is multiple lines or
 709because we need to distinguish which if an else binds to. Curly brackets go
 710on the same line as the test/loop statement. The exception to both cases is
 711if the test part of an if statement is long enough to split into multiple
 712lines, then we put the curly bracket on its own line afterwards (so it doesn't
 713get lost in the multple line variably indented mess), and we put it there
 714even if it's only grouping one line (because the indentation level is not
 715providing clear information in that case).</p>
 716
 717<p>I.E.</p>
 718
 719<blockquote>
 720<pre>
 721if (thingy) thingy;
 722else thingy;
 723
 724if (thingy) {
 725  thingy;
 726  thingy;
 727} else thingy;
 728
 729if (blah blah blah...
 730    && blah blah blah)
 731{
 732  thingy;
 733}
 734</pre></blockquote>
 735
 736<p>Gotos are allowed for error handling, and for breaking out of
 737nested loops. In general, a goto should only jump forward (not back), and
 738should either jump to the end of an outer loop, or to error handling code
 739at the end of the function. Goto labels are never indented: they override the
 740block structure of the file. Putting them at the left edge makes them easy
 741to spot as overrides to the normal flow of control, which they are.</p>
 742
 743<p>When there's a shorter way to say something, we tend to do that for
 744consistency. For example, we tend to say "*blah" instead of "blah[0]" unless
 745we're referring to more than one element of blah. Similarly, NULL is
 746really just 0 (and C will automatically typecast 0 to anything, except in
 747varargs), "if (function() != NULL)" is the same as "if (function())",
 748"x = (blah == NULL);" is "x = !blah;", and so on.</p>
 749
 750<p>The goal is to be
 751concise, not cryptic: if you're worried about the code being hard to
 752understand, splitting it to multiple steps on multiple lines is
 753better than a NOP operation like "!= NULL". A common sign of trying too
 754hard is nesting ? : three levels deep, sometimes if/else and a temporary
 755variable is just plain easier to read. If you think you need a comment,
 756you may be right.</p>
 757
 758<p>Comments are nice, but don't overdo it. Comments should explain _why_,
 759not how. If the code doesn't make the how part obvious, that's a problem with
 760the code. Sometimes choosing a better variable name is more revealing than a
 761comment. Comments on their own line are better than comments on the end of
 762lines, and they usually have a blank line before them. Most of toybox's
 763comments are c99 style // single line comments, even when there's more than
 764one of them. The /* multiline */ style is used at the start for the metadata,
 765but not so much in the code itself. They don't nest cleanly, are easy to leave
 766accidentally unterminated, need extra nonfunctional * to look right, and if
 767you need _that_ much explanation maybe what you really need is a URL citation
 768linking to a standards document? Long comments can fall out of sync with what
 769the code is doing. Comments do not get regression tested. There's no such
 770thing as self-documenting code (if nothing else, code with _no_ comments
 771is a bit unfriendly to new readers), but "chocolate sauce isn't the answer
 772to bad cooking" either. Don't use comments as a crutch to explain unclear
 773code if the code can be fixed.</p>
 774
 775<!--#include file="footer.html" -->
 776