Skip to content

Build your first project

In this tutorial you build a small project with a library and a program that uses it, run the program, change the library, and add a second library that reprobuild finds from an import line.

What you need

  • repro on your PATH (Install reprobuild).
  • git.
  • A Nim compiler on your PATH that satisfies the uses: lines you see in step 2. Check it with nim --version.

1. Get the example

Clone the examples repository at the revision this tutorial was checked against, and enter the example:

git clone https://github.com/metacraft-labs/reprobuild-examples
git -C reprobuild-examples checkout 6387d33bdaed57da72867f99fd6108f19c45a233
cd reprobuild-examples/nim/mode3-pilot

The directory holds a project file, repro.nim, a file reprobuild writes for you, repro.scanned-deps.nim, and two source files under src/.

2. Read the project file

Open repro.nim. Below its header comment it declares two packages:

<!-- generated:begin include reprobuild-examples/nim/mode3-pilot/repro.nim from="import repro_project_dsl" -->

import repro_project_dsl

package mode3PilotGreet:
  uses:
    "nim >=2.2 <3.0"

  library greet

package mode3PilotHello:
  uses:
    "nim >=2.2 <3.0"

  executable hello:
    discard

# Workspace-internal dependencies, regenerated by `repro deps refresh`.
# The scanner emits the `mode3PilotHello -> mode3PilotGreet` edge
# (proved by `src/hello.nim`'s `import greet` line).
include "repro.scanned-deps.nim"

<!-- generated:end -->

mode3PilotGreet holds a library named greet, and mode3PilotHello holds a program named hello. The file names no source files and no compiler flags: the Nim convention finds src/greet.nim and src/hello.nim from their names. The last line pulls in the dependencies reprobuild found in your sources.

3. Build the project

Run:

repro build --tool-provisioning=path

--tool-provisioning=path tells reprobuild to use the Nim on your PATH.

<!-- generated:begin capture first-build build --> <!-- generated:end -->

4. Run the program

Run the program you built:

.repro/build/hello/hello

<!-- generated:begin capture first-build run --> <!-- generated:end -->

5. Build again

Run the same command without changing anything:

repro build --tool-provisioning=path

Nothing has changed, so reprobuild reuses every result from step 3 and runs no compiler.

<!-- generated:begin capture first-build rebuild-unchanged --> <!-- generated:end -->

6. Change the library

Open src/greet.nim and change the text it returns:

proc greet*(name: string): string =
  ## Return a friendly greeting for ``name``.
  "hi there, " & name

Build, then run the program:

repro build --tool-provisioning=path
.repro/build/hello/hello

The actions that read src/greet.nim run again, and so does the link of hello, which uses the library.

<!-- generated:begin capture first-build rebuild-changed --> <!-- generated:end -->

7. Add a library that reprobuild finds for you

Create src/logger.nim:

proc log*(message: string) =
  ## Print ``message`` with a prefix.
  echo "[log] ", message

Add a package for it to repro.nim, above the include line:

package mode3PilotLogger:
  uses:
    "nim >=2.2 <3.0"

  library logger

Use it from src/hello.nim:

import greet
import logger

log(greet("mode3-pilot"))

Let reprobuild find the new dependency:

repro deps refresh

It rewrites repro.scanned-deps.nim with a second edge, found from the import logger line:

<!-- generated:begin capture first-build deps-refresh file=repro.scanned-deps.nim --> <!-- generated:end -->

Build and run:

repro build --tool-provisioning=path
.repro/build/hello/hello

<!-- generated:begin capture first-build add-library --> <!-- generated:end -->

What you learned

  • A project file names packages and the tools they use; the language convention finds the source files.
  • reprobuild runs an action again only when something it read has changed.
  • repro deps refresh writes the dependencies between your packages from the import lines in your sources, into a file you do not edit by hand.

Next