From 8e711a4b0b89c766bf00fa7ba9a273ac653da2c0 Mon Sep 17 00:00:00 2001 From: Puck Meerburg Date: Sat, 26 Jul 2025 15:42:17 +0000 Subject: [PATCH] (zilch lang ninja build): add support for secondary VFS roots These are used for implementing cross-project incremental builds. --- lang/ninja/src/build.sld | 44 ++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/lang/ninja/src/build.sld b/lang/ninja/src/build.sld index 2f54ada..0469b54 100644 --- a/lang/ninja/src/build.sld +++ b/lang/ninja/src/build.sld @@ -40,14 +40,15 @@ (phony-inputs built-edge-phony-inputs)) (define-record-type - (make-build-env config vfs header-files build-dir parsed-depfiles collected-deps) + (make-build-env config vfs header-files build-dir parsed-depfiles collected-deps secondary-vfs-setup) build-env? (config build-env-config) (vfs build-env-vfs set-build-env-vfs!) (header-files build-env-header-files set-build-env-header-files!) (build-dir build-env-build-dir) (parsed-depfiles build-env-parsed-depfiles) - (collected-deps build-env-collected-deps set-build-env-collected-deps!)) + (collected-deps build-env-collected-deps set-build-env-collected-deps!) + (secondary-vfs-setup build-env-secondary-vfs-setup)) ;; normalize a POSIX-y path. Ninja doesn't have an internal concept of path normalisation, ;; so this is necessary for proper file-finding behavior. @@ -98,6 +99,7 @@ (cond ; if input-file is 'base, this is part of the base vfs; we don't filter that right now. ((eq? input-file 'base) #f) + ((and (pair? input-file) (eq? (car input-file) 'base-vfs)) #f) ; Phony rule; pass through the inputs literally. ((eq? input-file 'phony) (for-each append-file (built-edge-phony-inputs input-edge))) @@ -105,7 +107,9 @@ ; This file is produced by another build edge. Add it to our input vfs. (input-file (let ((prev-copy-input-files copy-input-files)) - (set! copy-input-files #~,(string-append #$prev-copy-input-files "\n" "$COREUTILS/mkdir -p bdir/" (build-env-build-dir env) "/$($COREUTILS/dirname " path "); $COREUTILS/cp -rf --preserve=timestamps " #$(force input-file) " bdir/" (build-env-build-dir env) "/" path)))) + (if (string-prefix? "/nix/store" path) + (set! copy-input-files #~,(string-append #$prev-copy-input-files "\n" "$COREUTILS/mkdir -p $($COREUTILS/dirname " path "); $COREUTILS/cp -rf --preserve=timestamps " #$(force input-file) " /" path)) + (set! copy-input-files #~,(string-append #$prev-copy-input-files "\n" "$COREUTILS/mkdir -p bdir/" (build-env-build-dir env) "/$($COREUTILS/dirname " path "); $COREUTILS/cp -rf --preserve=timestamps " #$(force input-file) " bdir/" (build-env-build-dir env) "/" path))))) (else (unless (string-prefix? "/nix/store" path) @@ -215,7 +219,7 @@ #$coreutils "/bin/chmod ugo+rw -R bdir\n" ; Copy over the other input files. - "(COREUTILS=" #$coreutils "/bin; " #$copy-input-files ")\n" + "(COREUTILS=" #$coreutils "/bin; " #$(build-env-secondary-vfs-setup env) #$copy-input-files ")\n" #$coreutils "/bin/chmod ugo+rw -R bdir\n" ; Run any patches we have received. @@ -242,7 +246,13 @@ (define parsed-depfile (parse-depfile depfile-bytes)) (define data (cdar (mapping->alist parsed-depfile))) (define filtered '()) - (for-each (lambda (item) (unless (string-prefix? "/nix/store/" item) (set! filtered (cons item filtered)))) data) + (for-each + (lambda (item) + (define is-in-store (string-prefix? "/nix/store" item)) + (when is-in-store (set! item (normalize-path item))) + (when (or (not is-in-store) (member item (build-env-header-files env) string=?)) + (set! filtered (cons item filtered)))) + data) (set-build-env-collected-deps! env (mapping-set! (build-env-collected-deps env) depfile filtered))))) outpath) @@ -335,11 +345,19 @@ ;; 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) + ;; - `secondary-roots`: A list of (store-path-map finalized base-vfs-store-path-map (overlay-path-0 . promise-to-store-path) ... . (overlay-path-n . promise-to-store-path)) alists. i _guess_. + (define (process-ninja-file file conf relative-to secondary-roots) (unless (or (string=? relative-to "") (string-suffix? "/" relative-to)) (set! relative-to (string-append relative-to "/"))) (define edges (mapping (make-default-comparator))) + (define (setup-secondary-vfs k v) + #~,(string-append + "$COREUTILS/cp -rf --no-preserve=ownership " #$v " " k "; " + "$COREUTILS/chmod ugo+rw -R " k "; ")) + (define all-rewrites (apply append (map (lambda (v) (mapping-map->list setup-secondary-vfs (car (cddr v)))) secondary-roots))) + (define secondary-vfs-setup #~,(apply string-append #$all-rewrites)) + (define path-to-vfs (mapping (make-default-comparator))) (mapping-for-each @@ -358,7 +376,7 @@ (set! path-to-vfs (mapping-set! path-to-vfs path kv))) (vfs-contents (ninja-build-config-root-dir conf))) (define filtered-vfs (mapping-copy (vfs-contents (ninja-build-config-root-dir conf)))) - (define env (make-build-env conf #f '() relative-to (or (ninja-build-config-depfile conf) (mapping (make-default-comparator))) (mapping (make-default-comparator)))) + (define env (make-build-env conf #f '() relative-to (or (ninja-build-config-depfile conf) (mapping (make-default-comparator))) (mapping (make-default-comparator)) secondary-vfs-setup)) (define (elide-vfs rel-path kv) (define vfs-path (if (string=? (car kv) "") (cdr kv) (string-append (car kv) "/" (cdr kv)))) @@ -425,6 +443,16 @@ all-outputs))) (build-file-build-edges file)) + ; Register elided header files from secondary roots + (for-each + (lambda (secondary-root) + (for-each + (lambda (path-promise-pair) + (set! edges (mapping-set! edges (car path-promise-pair) (cons (cdr path-promise-pair) #f))) + (set-build-env-header-files! env (cons (car path-promise-pair) (build-env-header-files env)))) + (cdr (cddr secondary-root)))) + secondary-roots) + ; Finish VFS filtering by taking out everything under build/meson-private. ; This operates on the absolute VFS paths. (set! filtered-vfs @@ -440,7 +468,7 @@ (define edge-ref (lambda (path) - (define edge (mapping-ref edges path (lambda () (error "Target doesn't exist" path)))) + (define edge (mapping-ref edges path (lambda () (mapping-ref edges (normalize-path path) (lambda () (error "Target doesn't exist" path)))))) (cons (if (promise? (car edge)) (force (car edge)) (car edge)) (force (cdr edge))))) (define defaults (build-file-default-targets file)) (values edge-ref defaults (lambda () (build-env-collected-deps env))))))