add compilation thoughts

This commit is contained in:
Brian Picciano 2014-10-04 16:11:52 -04:00
parent 758263300d
commit 06838483d6

113
compilation.md Normal file
View File

@ -0,0 +1,113 @@
# Hello world
The following code in a file called `hello-world.gg` can be compiled to a static
binary which will output "Hello World!" and exit:
```
(. package "github.com/mediocregopher/ginger-hello-world"
(. defn main []
(: fmt.Println "Hello World!"))
)
```
While in the same directory as `hello-world.gg`, this can be compiled and run
with:
```
ginger run
```
and built into a static binary with:
```
ginger build
```
## package
The package string defines where in the namespace tree this file belongs. Code
in this file can directly reference variables, private or public, from other
files in the same package.
The physical layout of the files is not consequential, ginger only cares what
package they say they belong to, it's not required that the directory tree
matches the namespace tree.
## main
Every executable which ginger compiles needs one `main` function to use as the
entrypoint. Ginger looks for a `main` function in all the `.gg` files in the
current working directory in order to compile. If it finds one it uses that, if
it finds zero or more than one it errors and tells the user they need to specify
either a package or file name.
## Compilation
Ginger is first compiled into go code, and the subsequently uses the go tool to
compile that code into a static binary. Because of this ginger is able to use
any code from the go standard library, as well as any third-party go libraries
which may want to be used.
Ginger takes advantage of the `GOPATH` when compiling in order to find packages.
Upon starting up ginger will set the `GOPATH` as follows for the duration of the
run:
```
GOPATH=./target:$GOPATH
```
The following steps are then taken for compilation:
* Create a folder in the cwd called `target`, if it isn't already there. Also
create a `src` subfolder inside of that.
* Scan the cwd and any subdirectories (including `target`) for `.gg` files.
Translate them into `.go` files and place them according to their package name
in the `target/src` directory. So if a file has a package
`github.com/mediocregopher/foobar` it would be compiled and placed as
`target/src/github.com/mediocregopher/foobar/file.go`. The `main` function is
found and the package for it is determined in this step as well.
* As the cwd `.gg` files are scanned a set of packages which are required is
built. If any are not present in `target` at the end of the last step and are
not present as go projects in the `GOPATH` then they are searched for as
ginger projects in the `GOPATH`. Packages found will be translated into the
`target` directory (very important, this prevents the global GOPATH from
getting cluttered with tranlated `.go` files which aren't actually part of the
project). This step is repeated until all dependencies are met, or until
they're not and an error is thrown.
* At this point all necessary `.go` files to build the project are present in
the `GOPATH` (global or `target`). `go build` is called on the `main` package
and output to the `target` directory.
### Properties
Given those compilation steps ginger has the following properties:
* Dependencies for a ginger project, either go or ginger, can be installed
globally or to the `target` folder (sandboxed) by a dependency management tool
(probably built into ginger).
* It is easy to find exactly what your code is being translated to since it will
always be in the `target` directory.
* Translated code will not clutter up the global GOPATH.
* Only the `target` directory needs to be added to a `.gitignore` file.
* Some amount of ginger-to-ginger monkey patching may be possible. Not sure if
this is a good or bad thing.
* Compilation may take a while. There is some amount of hunting for `.gg` files
required, and all found ones *must* be compiled even if they're not going to
be used, since package names can be arbitrarily stated. There are some ways to
help this:
* Might be worth taking a shortcut like grepping through all files in the
`GOPATH` for the package string only compiling the ones which pass the
grep.
* Put placeholder `.go` files in the `target` directory to indicate that the
package isn't needed for subsequent installs. Not the *best* idea, since
changes to the dependency list in the project may not correctly process.