# Installation Nupp is written in Nupp. A checkout carries a stage-0 compiler already lowered to Lua, so building the real one takes a LuaJIT and nothing else. ## What you need **LuaJIT 2.1.1784535649 or newer.** Generated Nupp is written in the LuaJIT 3.0 syntax that 2.1 backported — `?.`, `??`, `?:`, the bit operators, compound assignment — rather than in a lowering of it. That rolling version is the first build carrying those extensions. `bin/nupp` reads `luajit -v` and says which build is wanted, so an older interpreter fails with a sentence instead of a syntax error on a line nobody wrote. Everything else is optional and buys one feature each: ``` Component Needed for Installed by ───────────── ──────────────────────────────── ───────────────────── lua-cjson --json output and the LSP server luarocks install lunamark nupp doc nupp doc Scintillua highlighting in generated sites nupp doc Rust toolchain building the binary host stub rustup ``` That table is about a **checkout**. A stamped binary carries all three of the first ones already — see [the binary](#a-self-contained-binary) — and needs nothing installed to check, compile, run or document a project. ## From a checkout ```bash git clone https://github.com/nupp-lang/nupp cd nupp ./bin/nupp build ``` `bin/nupp` is the entry point and it builds on demand: it runs `build/nupp/compiler` when that exists and no source is newer, and compiles the compiler first when it does not. An edit to the compiler is picked up by the next command rather than by the next person who remembers to build. The one thing it cannot do is start from nothing, since compiling Nupp needs a Nupp compiler. `bootstrap/nupp.lua` is that compiler, tracked in the repository, and it is what a fresh clone uses for its first build. ## Optional libraries Nothing to run: lunamark and Scintillua are declared in `nupp.lua` as dependencies of the documentation target, so the command that needs them installs them. ```bash ./bin/nupp doc ``` That installs both and their declared rocks into a project-local `.rocks` tree that `bin/nupp` and `tests/run` put on the search path. Nupp's own binaries use their pure PEG compatibility frontend for the LPeg calls in those libraries; they do not carry LPeg's C module. Two checkouts can hold different versions without either disturbing the other, and nothing lands in a global tree. See [rock dependencies](../tooling/build.md#rock-dependencies) for declaring your own. `nupp doc` needs lunamark and stops with a message when it cannot install or load it. Scintillua degrades instead: a fence in a language it cannot load renders as escaped text without highlighting. `lua-cjson` comes from wherever your LuaJIT already looks: ```bash luarocks install lua-cjson ``` Every command's `--json` output and the language server read it. ## Putting `nupp` on PATH Inside a checkout, run `./bin/nupp`. Everywhere else, either put the checkout's `bin` on your path, or build a self-contained binary. ## A self-contained binary ```bash ./bin/nupp build --target dist ``` That writes `build/dist/nupp`, a single file carrying the compiler, its standard library, and what it documents with, needing no LuaJIT installed alongside: ``` Carried How For ─────────────────── ─────────────────────────── ────────────────────── LuaJIT linked into the stub running anything lua-cjson detected and linked --json and the LSP Nupp PEG frontend emitted in the payload legacy LPeg pattern calls luautf8 detected and linked nupp doc's entities lunamark in the payload nupp doc's markdown Scintillua (45) in the payload highlighting fences ``` The lexers are a chosen set rather than all hundred and sixty Scintillua ships — the languages a technical document actually fences, listed at the top of `nupp.lua`. A fence in something else renders as escaped text, which is what it does with no Scintillua at all. See [distribution](../distribution.md) for the stub-and-payload format, and [rock dependencies](../tooling/build.md#carrying-a-rock-into-a-bundle) for carrying your own. ## Checking that it works ```bash ./bin/nupp check ./bin/nupp test ``` `check` type-checks the project configured in `nupp.lua`. `test` builds and runs the suite, which is plain LuaJIT with no framework behind it. ## Your first project Two files: ```text hello/ ├── nupp.lua └── src/ └── app/ └── main.nupp ``` `src/app/main.nupp`: ```nupp local function greetingFor(name: string): string return "Hello, " .. name .. "!" end print(greetingFor("Nupp")) ``` `nupp.lua`, the project manifest: ```lua return { include = { "src" }, build = { outDir = "build", default = "app", targets = { app = { kind = "modules", entries = { "app.main" }, }, }, }, } ``` `include` names the roots where modules live, so `app.main` resolves to `src/app/main.nupp`, and generated Lua keeps that path under `build/`. Then, from the project root: ```bash nupp check # type-check the project, writing nothing nupp build # compile the default target nupp run src/app/main.nupp # compile and run one file ``` Check the whole project rather than the file you just edited. That is what lets Nupp verify module boundaries, ownership contracts, and lint settings together. [Build system](../tooling/build.md) documents every manifest key. ## Next - [A tour of Nupp](tour.md) — the whole language in one pass. - [Reasons to use Nupp](why.md) — what each feature is for.