(zilch lang ninja): document

Change-Id: I6a6a6964dcc713504ec57f40981a601696a573af
This commit is contained in:
puck 2025-07-03 18:57:48 +00:00
parent 154ba9be1c
commit 93a1ebba00
11 changed files with 329 additions and 43 deletions

View file

@ -1,3 +1,4 @@
;; Turns a Ninja file into a set of binaries.
(define-library (zilch lang ninja build)
(import
(scheme base) (scheme lazy) (scheme file)
@ -8,7 +9,10 @@
(srfi 128) (srfi 146) (srfi 152)
(zilch lang ninja) (zilch lang ninja config) (zilch lang ninja depfile))
(export process-ninja-file
(export
process-ninja-file
<built-edge>
built-edge-edge built-edge-out-drv
built-edge-lib-placeholder built-edge-phony-inputs)
@ -17,6 +21,16 @@
(define patchelf (cdr (assoc "out" (nixpkgs "patchelf"))))
(define llvm-bintools (cdr (assoc "out" (nixpkgs-eval "llvmPackages_latest.bintools-unwrapped"))))
;; Represents a single built `<build-edge>`.
;;
;; - `edge`: The `<build-edge>` that this `<built-edge>` represents.
;; - `out-drv`: A store-path that contains all output files of this edge.
;; - `lib-placeholder`: If set, this built edge represents a library. This
;; field will then contain a store path that represents the same library as
;; output in `out-drv`, but with all infnormation other than symbol names
;; removed. This can be used as a stub while linking other binaries.
;; - `phony-inputs`: a list of strings representing the edges that make up
;; this edge. Only set if this edge is phony.
(define-record-type <built-edge>
(make-built-edge edge out-drv lib-placeholder phony-inputs)
built-edge?
@ -315,11 +329,19 @@
(string-suffix? ".h" path)))
;; process a ninja file and corresponding vfs, and return two values:
;; - `edge-ref`, a lambda that lets one fetch any build edge;
;; - `defaults`, a list containing the default build edges.
;;
;; If the `environment` is a <derivation> or a <store-path>, it is considered
;; to be a nixpkgs-style derivation, the same way `nix-shell` works.
;; - `edge-ref`: A lambda that lets one look up a pair of
;; `(<zexp> . <built-edge>)` representing the path of an output, and the
;; edge that produced that output.
;; - `defaults`: A list containing the names of the default build edges.
;;
;; This procedure takes three arguments:
;;
;; - `file`: The parsed `<build-file>`.
;; - `conf`: A `<ninja-build-config>` record describing the details on how to
;; handle this Ninja file.
;; - `relative-to`: The directory in which the Ninja file was found. Used to
;; resolve relative references in the Ninja file.
(define (process-ninja-file file conf relative-to)
(unless (or (string=? relative-to "") (string-suffix? "/" relative-to)) (set! relative-to (string-append relative-to "/")))

View file

@ -1,3 +1,4 @@
;; Parses the Zilch-specific Ninja configuration.
(define-library (zilch lang ninja config)
(import
(scheme base) (scheme eval)
@ -6,7 +7,7 @@
(prefix (only scheme eval) scheme-))
(export
ninja-build-config?
<ninja-build-config> ninja-build-config?
ninja-build-config-environment ninja-build-config-environment-drv
ninja-build-config-root-dir ninja-build-config-patches ninja-build-config-targets
ninja-build-config-override-source ninja-build-config-depfile ninja-build-config-depfile-path
@ -17,6 +18,8 @@
parse-ninja-config)
(begin
;; Represents a parsed Ninja build configuration.
;; See `parse-ninja-config` for the definition of these fields.
(define-record-type <ninja-build-config>
(make-ninja-build-config environment environment-drv root-dir patches targets override-source depfile depfile-path disallow-elide)
ninja-build-config?
@ -86,7 +89,35 @@
(set-ninja-build-config-targets! conf (append list-val (ninja-build-config-targets conf))))
(parse-config-inner conf (cddr data)))
(else (error (string-append "Unknown directive " (keyword->string (car data)) " parsing Zilch Ninja config")))))))
;; Parses a Zilch Ninja configuration file.
;;
;; A Zilch Ninja configuration file is a list containing repeated keys and values.
;;
;; - `env:`/`environment: ...`: The environment to be used when processing
;; the Ninja file. If the environment is a string, it is assumed to be a
;; Nix expression resolving to a derivation, and will be evaluated in the
;; context of Nixpkgs. Otherwise, it is assumed to be a (optionally
;; `zexp`) alist of environment variables.
;; - `root: dir`: The root directory that contains both the source and
;; necessary Ninja build files. If string, assumed to be a directory
;; relative to the working directory; assumed to be a `<vfs>` otherwise.
;; - `override-source: dir`: The source override directory. Only used by
;; `build-nixpkgs-drv-reproducibly`, ignored otherwise.
;; - `depfile-path: path`: The location of a depfile cache to use, as a
;; string relative to the current working directory. Only used by
;; `zilch-cli-ninja`.
;; - `depfile: #<mapping>`: An SRFI146 mapping output file names to a list
;; of input dependencies. Used to elide inputs where possible.
;; - `patch: proc`: A patch procedure (or a list which evaluates to one).
;; A patch procedure takes a `<build-edge>, and outputs `#f` or a string
;; of shell commands to run before evaluating the rule's command.
;; - `disallow-elide: proc`: A procedure that takes the path of a file and
;; can return `#t` to reject its elision. Used to special-case files that
;; would normally be elided, but shouldn't, in cases where the depfile is
;; incorrect.
;; - `target: "foo"`/`targets: '("foo" "bar")`: Build these targets instead
;; of the default specified in the Ninja file.
(define (parse-ninja-config config)
(unless (list? config)
(error "expected Zilch Ninja config to be a list"))

View file

@ -1,3 +1,5 @@
;; Implements the bare minimum Makefile parser to read `.d` files generated by
;; GCC, rustc, and more.
(define-library (zilch lang ninja depfile)
(import
(scheme base)
@ -7,6 +9,8 @@
parse-depfile)
(begin
;; Parse a depfile. Takes a bytevector representing the depfile, and returns
;; a mapping of output path to input dependencies.
(define (parse-depfile bytes)
(define buf (make-bytevector 1024 0))
(define buf-i 0)

View file

@ -1,3 +1,8 @@
;; Processes Ninja files into Scheme records.
;;
;; This library uses a special format to store strings that contain variables.
;; If a string can contain variables, it may be represented as a list, where
;; each value of the list is either a string, or a pair `'(varname . "variable_name")`.
(define-library (zilch lang ninja)
(import
(scheme base) (scheme write) (scheme process-context) (scheme lazy)
@ -12,7 +17,6 @@
(export
<build-file> make-build-file build-file?
build-file-global-variables build-file-default-targets build-file-rules build-file-build-edges
build-file-pools
<build-rule> make-build-rule build-rule?
build-rule-name build-rule-command build-rule-depfile build-rule-deps build-rule-description
@ -121,14 +125,20 @@
(define (pr out name value) (unless (eq? value #f) (fprintf out " ~A = ~A\n" name (render-evalstring value #f))))
;; Represents a Ninja build file.
;;
;; - `global-variables`: An SRFI146 mapping containing all variables defined
;; globally.
;; - `default-targets`: A list of target names that should be built if no
;; specific target is requested.
;; - `rules`: A mapping of rule names to `<build-rule>` records.
;; - `build-edges`: A list of `<build-edge>` records.
(define-record-type <build-file>
(make-build-file global-variables default-targets rules build-edges pools)
(make-build-file global-variables default-targets rules build-edges)
build-file?
(global-variables build-file-global-variables set-build-file-global-variables!)
(default-targets build-file-default-targets set-build-file-default-targets!)
(rules build-file-rules set-build-file-rules!)
(build-edges build-file-build-edges set-build-file-build-edges!)
(pools build-file-pools set-build-file-pools!))
(build-edges build-file-build-edges set-build-file-build-edges!))
(define-record-printer (<build-file> file out)
(fprintf out "# debug build file\n")
@ -141,7 +151,8 @@
(for-each (lambda (edge) (fprintf out "~S" edge)) (build-file-build-edges file)))
;; Represents a Ninja build rule.
; variables that are ignored for now: dyndep, generator, pool, msvc_deps_prefix
;; Each of the fields of this record represent a variable that can be set
;; in a Ninja build rule.
(define-record-type <build-rule>
(make-build-rule name command depfile deps description restat rspfile rspfile-content)
build-rule?
@ -165,7 +176,14 @@
(pr out "rspfile-content" (build-rule-rspfile-content rule))
(fprintf out "\n"))
;; Represents a Ninja build edge (aka one or more files built by this Ninja file)
;; Represents a Ninja build edge (aka a Ninja build statement).
;;
;; - `rule`: The name of the build rule to use for this edge.
;; - `outputs`/`inputs`/`implicit-dependencies`/`order-only-dependencies`/`validations`/`implicit-outputs`:
;; The corresponding parsed part of the build statement, represented as a
;; possibly-variable-containing string.
;; - `variables`: A mapping of variable name to a possibly-variable-containing string.
;; - `resolved`: A `<build-rule>` record where each value has its variables already resolved.
(define-record-type <build-edge>
(make-build-edge rule outputs inputs implicit-dependencies order-only-dependencies validations implicit-outputs variables resolved)
build-edge?
@ -230,7 +248,6 @@
#f
(inner-loop 0)))
;; Reads a full Ninja file, returning a <build-file> record.
(define (read-ninja-file-inner strval into read-other-file)
(define i 0)
(define (eat-whitespace)
@ -463,7 +480,15 @@
(read-toplevel file)))
file)
(read-toplevel into))
;; Parses a full Ninja file from a string, returning a <build-file> record
;; representing the file.
;;
;; `read-other-file` is a procedure used to read a Ninja file relative to
;; this one, used to implement the `include` keyword. It is expected to take
;; a string representing the path to read, and to return a string containing
;; the full contents of said Ninja file.
(define (read-ninja-file strval read-other-file)
(define out-file (read-ninja-file-inner strval (make-build-file (mapping (make-default-comparator)) '() (mapping (make-default-comparator)) '() (mapping (make-default-comparator))) read-other-file))
(define out-file (read-ninja-file-inner strval (make-build-file (mapping (make-default-comparator)) '() (mapping (make-default-comparator)) '()) read-other-file))
(for-each (lambda (f) (unless (string=? (build-edge-rule f) "phony") (set-build-edge-resolved! f (build-rule-resolve (mapping-ref (build-file-rules out-file) (build-edge-rule f)) f out-file)))) (build-file-build-edges out-file))
out-file)))

View file

@ -1,3 +1,4 @@
;; Helpers to work with Zilch around Nixpkgs derivations.
(define-library (zilch lang ninja nixpkgs)
(import
(scheme base) (chicken format) (scheme lazy)
@ -74,7 +75,23 @@
(set! output (string-copy output 0 32)))
(string-append "/nix/store/" output (string-copy base-placeholder (string-length output)) name (if (string=? output "out") "" (string-append "-" output))))
;; Takes a `<ninja-build-config>` representing a Nixpkgs derivation, and
;; preprocesses the derivation such that it can be reconstituted once Zilch
;; has taken over the Ninja build requirements.
;;
;; This procedure is used internally, and shouldn't be relied upon; it
;; encodes many specific parts that are unlikely to be useful by external
;; parties.
;;
;; Returns 6 values:
;;
;; - The initial Nixpkgs derivation as `<derivation>`
;; - The Nixpkgs derivation after running all phases up to and including
;; configuration
;; - An alist of output names to placeholder store paths
;; - The `edge-ref`, `defaults`, and `export-depfile` values from calling
;; `process-ninja-file`
(define (setup-ninja-environment conf)
(define initial-drv (ninja-build-config-environment-drv conf))
(when (store-path? initial-drv)
@ -125,7 +142,17 @@
(define-values (edge-ref defaults export-depfile) (process-ninja-file ninja-file conf "build"))
(values initial-drv configured-drv placeholders edge-ref defaults export-depfile))
;; Takes a `<ninja-build-config>` representing a Nixpkgs derivation, and
;; build it using Zilch.
;;
;; Returns two values:
;;
;; - An alist of output name to store paths, representing the built
;; derivation
;; - A procedure that, when called, returns a mapping of output path to
;; necessary inputs generated from the depfile data. This can be stored in
;; a file for later rebuilds.
(define (build-nixpkgs-drv-reproducibly conf)
(define-values (initial-drv configured-drv placeholders edge-ref defaults export-depfile) (setup-ninja-environment conf))