jehanne/doc/hacking/overview.md

294 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Hacking Jehanne
===============
Jehanne is a work in progress that still needs a lot of effort to become
useful.
Here you find a quick tour of the project organization.
Further help can be obtained from the [mailing list]: you are welcome
to challenge my assumptions.
Coding Styles
=============
Jehanne is a small operating system, but it's composed of a kernel, a
few libraries and a minimal set of commands coded in C.
Most of libraries and commands come either from Bell Labs' Plan 9 or
from 9front, and thus they loosely follow the coding conventions
described in the [style(6)] manual page there.
It's wise to stick to that convention for such code, in the hope to
share improvements between the projects in a friendly manner.
Other libraries and commands may come from the Unix ecosystem:
we stick with the existing conventions there too.
Here I describe the **arbitrary** conventions that are followed for
new original C components **and for the kernel**.
This unfortunately means that, depending on the age of a kernel file,
you will find either the loosely followed Pike' style or my ugly
rules and conventions.
Fortunately, if you contribute a new interesting program, you are free
to choose your favourite coding style, declare it clearly in a README
file and stick with it. Note however that this won't apply to libraries.
Use good sense
--------------
> Le bon sens est la chose du monde la mieux partagée; car
> chacun pense en être si bien pourvu, que ceux même qui sont les
> plus difficiles à contenter en toute autre chose nont point coutume
> den désirer plus quils en ont.
>
> -- [René Descartes], [Discours de la méthode]
In Jehanne good sense is both **strictly enforced** and **loosely defined**.
This way nobody will try to sell you books, lectures or TED conferences
about it.
These are my rules of thumb:
1. **Keep it simple**
Never add features just because you can. Remove redundant features.
Decouple unrelated features. Use obvious names for files and folders.
2. **Encapsulate**
Use properly scoped functions to access structures' members.
3. **Do not abstract**
Replace abstractions used less than 3 times. Remove unused code.
Aestetics
---------
I do not care too much about aestetics, just readability.
Unfortunately, just like any other programmer, what I find readable
largely depends on the codebase that I had to debug.
The conventions I try to honor are:
1. Tabs are 8 characters.
2. Lines should be no longer than readable. You can use macros to
improve readability.
3. Format blocks like this:
if(x == nil)
do_something();
if(x == y){
...
} else {
...
}
switch(v){
case AnOption:
...
break;
case AnotherOption:
...
break;
default:
...
break;
}
4. Format functions like this:
/* will wlock/wunlock pool_lock */
static void
freelist_add(ImagePointer ptr, ElfImage *img)
{
body of function
}
5. Use one space around `=` `+` `-` `<` `>` `*` `/` `%`
`|` `&` `^` `<=` `>=` `==` `!=` `?` `:`, but no space between
unary operators (`&` `*` `+` `-` `~` `!` `sizeof` `typeof`
`alignof` `__attribute__` `defined` `++` `--`) and their
operand, and obviously no space around the `.` and `->` structure
member operators
6. Use short names in local variables and module functions when the
meaning is obvious in the context using them (`tmp`, `i`, `j`).
7. Use descriptive names for globally visible functions and variables
(eg `proc_segment_detach`). In Jehanne's kernel a few frequently
used global variables are allowed to violate this rule:
`up` (current user process), `m` (current processor) and `sys`.
8. Use `typedefs` for struct and enums (CamelCase) but not for pointers.
9. Functions should be short, do one thing, hold few local variables
and `goto` a centralized cleanup section error.
Return values should consider errors as first class citizens.
Use Plan9's `error()` machinery only in functions directly called by
other modules (like `Dev` methods and exported ones), not just
to easily unroll the stack.
Hacking Tools
=============
To fasten development, a set of simple tools have been created.
As tools to a greater goal, they are **disposable** and can only evolve
as required by Jehanne's development.
Development Environment
-----------------------
Currently, Jehanne is coded and cross compiled from Linux (I work on a
stable Debian GNU/Linux).
To build it you need `bash`, `git`, `golang`, `build-essential` `flex`,
`bison` and `qemu-system`.
Inside the root of the repository you can enter the development
environment with `./hacking/devshell.sh` that will start a new Bash:
* your `$PS1` will be prepended with "JehanneDEV "
* the environment variable `$JEHANNE` will hold the path of the root
of the respository
* the environment variable `$ARCH` will be "amd64" (aka x86_64, the
only supported architecture so far)
* `$PATH` will include `$JEHANNE/hacking/bin` and
`$JEHANNE/hacking/cross/toolchain/bin`
* the environment variable `$TOOLPREFIX` will contain the prefix of
the cross compiling toolchain
To build the cross compiler you "only" need to run
`(cd $JEHANNE/hacking/cross/; ./init.sh; git clean -xdf src/)`.
It will automatically download and compile Binutils and GCC
(and their obsolete build dependencies).
The process requires around 30 minutes (depending on your hardware)
and 4 GB of free disk space, but fortunately it's seldom required
during development.
All other development tools can be built with the command
`./hacking/buildtools.sh`.
You can also invoke it with `--no-drawterm` or `--no-tools`: since
building drawterm is slower than all the other tools together, I
usually build it alone.
The build system
----------------
Jehanne's build system is an evolution of the Harvey's original one
based on Go and Json. It violates the [principle of least surprise],
so that [I was originally pretty skeptic about it], but it turns out
that [Aki was right]: a general purpose language provide both power
and painless evolution to a build system.
Thus, to build Jehanne you use the `build` commands.
Its source code is at `./hacking/src/jehanne/cmd/` and its documantation
can be obtained with `build --help`.
It consumes small JSON files (usually named `build.json`) describing the
build process. Some example to get started are [the commands one] and
[the libc one].
When I need to rebuild the entire system (for example after a
change to libc) I simply run `cd $JEHANNE; git clean -xdf . && build`.
However you can always build just a specific component
(or component set), for example `build sys/src/cmd/rc/`
or `build sys/src/cmds.json Cmds` or even
`cd sys/src/cmd/hmi/console/ && build screenconsole.json && cd -`.
Note that the Jehanne's build system does not track or enforce
dependencies or file changes: it always run the **entire build**
described in the provided JSON **and nothing more**. Thus it's simple,
fast enough and fully **predictable**.
The workhorse
-------------
A simplified kernel is built before the others: [the workhorse].
It's used during the compilation, whenever we need to run a Jehanne's
program that is impractical to port to Linux. For example it's run in a
qemu instance to create the initial ram disk for the other kernels.
Custom Go tools
---------------
Here is a brief summary of the other custom tools in
`./hacking/src/jehanne/cmd/`:
* `runqemu` runs Jehanne in a qemu instance and send commands to it.
It is used both during compilation (to create the initial ram disk,
for example) and to run [quality checks].
* `ksyscalls` and `usyscalls` produce the boring code for system calls,
in kernel and in libc respectively. It reads [sysconf.json].
* `mksys` produces several headers reading from the [sysconf.json] too
* `data2c` and `elf2c` embeed in programs in kernels (mainly in the
workhorse).
* `fetch` downloads external resources listed in [a fetch.json file]
* `telnet` can connect a running instance of Jehanne.
It was used before drawterm was available.
* `preen` pretty print the JSON files used by `build`
Inside the development shell, these tools are available in `$PATH`.
Miscellaneous utilities
-----------------------
Among [devtools] you can also find several shell scripts and files
that are designed to be used only from the repository root.
To get a bootable usb stick (or a disk image to be used with Bochs
or Qemu) you can use:
* `./hacking/disk-create.sh` creates a raw disk image at `$DISK`
(default `./hacking/sample-disk.img`). It uses syslinux, its bios
files (looked up at `$SYSLINUXBIOS`) and fdisk, but it can be run as
a user **without** `sudo`. The image will contains two separate
partitions, one for syslinux, the kernel and the initial ram disk
(the `dos` partition) and one for the rest of the system
(the `plan9` partition) in a [hjfs] file system.
* `./hacking/disk-boot-update.sh` updates syslinux, the kernel and
the initial ram disk in the appropriate partition of `$DISK`
* `./hacking/disk-update.sh file1 file2 ...` copy the files provided
as arguments **to** the [hjfs] partition of `$DISK`.
* `./hacking/disk-get.sh file1 files2 ...` copy the files provided as
arguments **from** the [hjfs] partition of `$DISK`
to `$JEHANNE/usr/glenda/tmp`.
To run the system in Qemu you can use:
* `./hacking/runOver9P.sh` that uses a 9P2000 file server running on
the host as the root file system
* `./hacking/runDisk.sh [path/to/disk/image]` that uses the disk image
provided (or `$DISK`) to as the root file system.
Moreover `./hacking/QA.sh` is used by `runqemu` to start the workhorse
and execute the QA checks.
In the default configuration (see [cfg/startup]), Jehanne is started as
a cpu server owned by glenda. You can connect it with the
`./hacking/drawterm.sh` script. The password is "demodemo".
Finally `./hacking/continuous-build.sh` and
`./hacking/coverity-scan.sh` are used during continuous build.
Third parties
-------------
In the hacking/third_party directory you can file the
[Go 9P2000 server] used during development and [drawterm], both
downloaded as git submodules and compiled by `./hacking/buildtools.sh`.
[mailing list]: https://groups.google.com/forum/#!forum/jehanneos
[principle of least surprise]: https://en.wikipedia.org/wiki/Principle_of_least_astonishment
[I was originally pretty skeptic about it]: https://groups.google.com/d/msg/harvey/IwK8-gebgyw/vxCPQVaGBAAJ
[Aki was right]: https://groups.google.com/d/msg/harvey/IwK8-gebgyw/vxCPQVaGBAAJ
[the commands one]: https://github.com/JehanneOS/jehanne/blob/master/sys/src/cmd/cmds.json
[the libc one]: https://github.com/JehanneOS/jehanne/blob/master/sys/src/lib/c/build.json
[sysconf.json]: https://github.com/JehanneOS/jehanne/blob/master/sys/src/sysconf.json
[a fetch.json file]: https://github.com/JehanneOS/devtools/blob/master/cross/src/fetch.json
[quality checks]: https://github.com/JehanneOS/jehanne/tree/master/qa
[the workhorse]: https://github.com/JehanneOS/jehanne/blob/master/sys/src/kern/amd64/workhorse.json
[devtools]: https://github.com/JehanneOS/devtools/
[hjfs]: http://man2.aiju.de/4/hjfs
[cfg/startup]: https://github.com/JehanneOS/jehanne/tree/master/cfg
[Go 9P2000 server]: https://github.com/lionkov/ninep
[drawterm]: https://github.com/0intro/drawterm
[style(6)]: http://man.cat-v.org/9front/6/style
[encapsulation]: http://www.tonymarston.co.uk/php-mysql/abstraction.txt
[René Descartes]: https://en.wikipedia.org/wiki/Ren%C3%A9_Descartes
[Discours de la méthode]: http://www.gutenberg.org/files/59/59-h/59-h.htm