packages feed

language-ninja-0.1.0: README.md

# `language-ninja`

[![Hackage][hackage-badge]][hackage-link]
[![Stackage][stackage-badge]][stackage-link]
[![License][license-badge]][license-link]

`language-ninja` is a Haskell library for parsing, pretty-printing, and
compiling the [Ninja build language](https://ninja-build.org).

## Motivation

`language-ninja` was written as a part of Awake Security's efforts in creating
incremental build infrastructure for the Nix package manager, and in particular
for Haskell packages. This library is the basis for a tool, [ninja2nix][], that,
given a Ninja file, will output a JSON file containing information that a Nix
function can use to compute a derivation representing an incremental build
using one derivation per build edge in the parsed Ninja build graph.

In conjunction with an as-of-yet unwritten tool, [cabal2ninja][], that will
generate a Ninja file based on information from `cabal` and `ghc -M`, we will
have incremental builds for any Haskell package that uses a default `Setup.hs`
file.

Using Ninja as an intermediate representation has advantages here, since it
means that [ninja2nix][] could be useful for building other projects that use
a build system that can output Ninja, like the Linux kernel (with `kninja`),
Chromium, any CMake project, any Bazel project, or some Make-based projects
(with `kati`).

## Parsing

Originally, `language-ninja` used the Ninja lexer/parser from Neil Mitchell's
`shake` project. However, we now use a `megaparsec`-based lexer and a highly
modified version of the old parser. There is still work to be done on improving
the diagnostic data and pretty-printability of the AST from this parser.
In my view, it is very important that a parser output an AST that can be
pretty-printed exactly to same sequence of bytes that were in the parsed file,
as this makes tests and diagnostics much easier to write.

## Pretty-printing

Currently there is a rudimentary pretty-printer in `Language.Ninja.Pretty`.
It simply outputs text such that if that text is parsed and the parsed data
is pretty-printed again, the resulting text will be identical to the original
text (this is tested on a variety of Ninja files in the test suite).

## Compiling

The `Ninja` type from `Language.Ninja.IR.Ninja` contains precisely the data
that must be acted on dynamically in a Ninja. In converting from the parsed
AST to the intermediate representation using `Language.Ninja.Compile.compile`,
you are eliminating all statically-dischargeable language features in Ninja,
like variables. It also "monomorphizes" Ninja `rule`s, since rule-level `$out`
references are a kind of parametric polymorphism. This IR is thus far more
suitable for processing than the original parsed AST.

## Miscellaneous

The `staging` branch is used for active development; i.e.: force pushes may
happen on `staging` but will not happen on `master`.

To build this, I recommend installing the Nix package manager and running
`nix-build release.nix -A language-ninja`.

[hackage-badge]:
    https://img.shields.io/hackage/v/language-ninja.svg?label=Hackage
[hackage-link]:
    https://hackage.haskell.org/package/language-ninja
[stackage-badge]:
    https://www.stackage.org/package/language-ninja/badge/lts?label=Stackage
[stackage-link]:
    https://www.stackage.org/package/language-ninja
[license-badge]:
    https://img.shields.io/badge/License-Apache%202.0-blue.svg
[license-link]:
    https://spdx.org/licenses/Apache-2.0.html
[ninja2nix]:
    https://github.com/awakesecurity/ninja2nix
[cabal2ninja]:
    https://github.com/awakesecurity/cabal2ninja