= Using Zilch as a library
:page-pagination: prev

Zilch is able to be used as a library; provided you have knowledge of Chicken
Scheme. 

Once the Zilch libraries are installed (or inside a `nix-shell` inside the
Zilch repo), open an interpreter (or an editor).

These examples assume you are running in an interpreter with
`(scheme base)`, `(zilch zexpr)`, and `(zilch magic)` in scope.

== Creating and building derivations

To start off, creating an arbitrary derivation can be done with one call:

[,scheme,line-comment=;]
----
(define normal-derivation
 (store-path-for-drv
  "hello" ; <1>
  "x86_64-linux" ; <2>
  '("/bin/sh" "-c" "echo hi > $out") ; <3>
  '() ; <4>
  '("out"))) ; <5>
;; (("out" . #<store path /nix/store/mjs27ix6ig2bkbi3s3sm470vrv4lf7ic-hello
;;             (/nix/store/76w21n1f03fs5kw8fnffphx7qrqffw6r-hello.drv!out)>))
----
<1> Name for the derivation (used in output store paths)
<2> Architecture that this derivation needs to be built on.
<3> Derivation builder and its arguments (unlike Nix, these are considered one list)
<4> Any environment variables to set whilst executing the builder
<5> The list of output names to use for this derivation.

This procedure returns an alist of `<store-path>` records, which refer to
derivation store paths. These derivations may or may not exist in the Nix
store, however, as Zilch only writes them to the store when necessary, or when
requested. To do this manually, call `store-path-materialize`: 

[,scheme]
----
(store-path-materialize (cdar normal-derivation))
----

After materialization, it's now possible to build this derivation, both
inside Zilch and outside it.

[,console]
----
$ nix-build '/nix/store/76w21n1f03fs5kw8fnffphx7qrqffw6r-hello.drv!out'
this derivation will be built:
  /nix/store/76w21n1f03fs5kw8fnffphx7qrqffw6r-hello.drv
building '/nix/store/76w21n1f03fs5kw8fnffphx7qrqffw6r-hello.drv'...
/nix/store/mjs27ix6ig2bkbi3s3sm470vrv4lf7ic-hello

$ cat /nix/store/mjs27ix6ig2bkbi3s3sm470vrv4lf7ic-hello
hi
----

[,scheme]
----
(store-path-build (cdar normal-derivation))
;> [..building "/nix/store/76w21n1f03fs5kw8fnffphx7qrqffw6r-hello.drv"]
;> [0/1 builds, 1 running]
;; 1
----

These store paths are a type of ``<zexp>``; a format used to describe data that
depends on paths from the Nix store.

== Zexpressions
While it's possible to manually build every store paths you need, and handle
them as plain strings, this is cumbersome and error-prone. It also doesn't work
when you have to deal with placeholders, which are used for content-addressed
derivations. So, to handle these, the `store-path` concept is extended to
generic Scheme expressions. These use `zexp` (or `++#~++`) and you can use
`zexp-unquote` (or `++#$++`) to read out the contents of one `zexp` inside another.
Finally, to read out a `zexp` outside another `zexp`, you can use `zexp-unwrap`:

[,scheme]
----
(define example-zexp
 (zexp (zexp-unquote (cdar normal-derivation))))
;; #<zexp val: (zexp-unquote (cdar normal-derivation))>

(define unwrapped (zexp-unwrap example-zexp))
;; #<zexp-evaluation val: "/nix/store/mjs27ix6ig2bkbi3s3sm470vrv4lf7ic-hello",
;;  drvs: ((#<derivation "hello" …> "out")),
;;  srcs: ()>
----

A `zexp` represents an arbitrary S-expression. It's also possible to run code
when a `zexp` is used, similarly to `quasiquote`. Like `quasiquote`, this uses
`unquote` (or its syntax sugar). Doing this also retains the context of any
``zexp-unquote``d value:

[,scheme]
----
(define more-complex
 (zexp ,(string-append
         "The store path is at "
         (zexp-unquote example-zexp))))

(zexp-unwrap more-complex)
;; #<zexp-evaluation
;;   val: "The store path is at /nix/store/mjs27ix6ig2bkbi3s3sm470vrv4lf7ic-hello",
;;   drvs: ((#<derivation "hello" …> "out")),
;;   srcs: ()>
----

These expressions can then be used in derivations (e.g. through
`store-path-for-drv`) too:

[,scheme]
----
(define another-derivation
 (store-path-for-drv "hello2" "x86_64-linux"
  '("/bin/sh" "-c" "echo \"$foo\" > $out")
  (list (cons "foo" more-complex))
  '("out")))
;; (("out" . #<store path /nix/store/nz1fv397b3cix74d58i8kh2nj8knvb72-hello2
;;             (/nix/store/gvglnwmalgdnri3zwzmkscg61ll8nas1-hello2.drv!out)>))

(store-path-materialize (cdar another-derivation))

(store-path-build (cdar another-derivation))
;! /nix/store/nz1fv397b3cix74d58i8kh2nj8knvb72-hello2 contains
;! "The store path is at /nix/store/mjs27ix6ig2bkbi3s3sm470vrv4lf7ic-hello"
----

As ``zexp``s aren't limited to strings, it's possible to write expressive
derivations relatively easy.

[,scheme]
----
(define another-derivation
 (store-path-for-drv "hello2" "x86_64-linux"
  #~("/bin/sh" "-c" ,(string-append "echo \"" #$more-complex "\" > $out"))
  '()
  '("out")))
;; (("out" . #<store path /nix/store/91v91bmyyjl04ccirp9x1bb1ync3c0f5-hello2
;;             (/nix/store/a2315xkzjssicyxgf0ji0j8a3y085hkm-hello2.drv!out)>))

(store-path-materialize (cdar another-derivation))
----

== Content-addressed derivations
Zilch implements xref:./derivations.adoc[its own content-addressed derivations],
which can be used almost as easily as input-addressed derivations. However,
they have an important caveat: Their output store paths are only known at build
time. To improve performance, the store paths render as a "placeholder", which
gets substituted at build time.

[,scheme]
----
(define content-addressed-derivation
 (store-path-for-ca-drv "hello" "x86_64-linux"
  '("/bin/sh" "-c" "echo hi > $out")
  '()
  '("out")))
;; (("out" . #<store path /106ghhc6jy33ycylgj3ndzwb1l6sdkm75likgd7fm5pr7fjfx5cv
;;             (ca~ /nix/store/bl3mp0i3kd2rssjgynga84gwzx5cj653-hello.drv!out)>))
----

Content addressed store paths can be determined by the output path not starting
with the Nix store, and the `ca~` marker in their representation. These
derivations also cannot be materialized; `store-path-materialize` will ignore
them.

When these store paths are used in other content-addressed derivations, they
will work as intended. Their output, when ``zexp-unwrap``ed, however, will
still contain placeholders:

[,scheme]
----
(zexp-unwrap (cdar content-addressed-derivation))
;; #<zexp-evaluation val: "/106ghhc6jy33ycylgj3ndzwb1l6sdkm75likgd7fm5pr7fjfx5cv",
;;   drvs: ((#<derivation "hello" …> "out")),
;;   srcs: ()>
----

To resolve their placeholders, you need to use `store-path-realised`. This will
evaluate the `zexp` or `store-path`, and resolve placeholders:

[,scheme]
----
(store-path-realised (cdar content-addressed-derivation))
;; "/nix/store/a5izqk5bgpxcrrnrm1m8n1fvyq2jlc52-hello"
----

Alternatively, it's possible to use `store-path-devirtualise`. This does the
same thing, but returns a `zexp`, which can then be used in an input-addressed
derivation.
