summaryrefslogtreecommitdiff
path: root/guix/build
diff options
context:
space:
mode:
authorMaxim Cournoyer <maxim.cournoyer@gmail.com>2022-01-25 23:36:11 -0500
committerMaxim Cournoyer <maxim.cournoyer@gmail.com>2022-01-25 23:48:37 -0500
commit0d41fe4855588fb659b8adafe215d5573517a79b (patch)
tree38b274bd03375f4fa5b7d3a9fb3f64a19786bef2 /guix/build
parent7c57821c68d199ad56a8ed750b36eccc7ef238dd (diff)
parent1a5302435ff0d2822b823f5a6fe01faa7a85c629 (diff)
Merge branch 'staging' into core-updates.
With "conflicts" resolved in (mostly in favor of master/staging): gnu/packages/admin.scm gnu/packages/gnuzilla.scm gnu/packages/gtk.scm gnu/packages/kerberos.scm gnu/packages/linux.scm guix/lint.scm
Diffstat (limited to 'guix/build')
-rw-r--r--guix/build/clojure-build-system.scm43
-rw-r--r--guix/build/clojure-utils.scm12
-rw-r--r--guix/build/compile.scm32
-rw-r--r--guix/build/gnu-build-system.scm2
-rw-r--r--guix/build/go-build-system.scm26
-rw-r--r--guix/build/julia-build-system.scm33
-rw-r--r--guix/build/node-build-system.scm236
-rw-r--r--guix/build/syscalls.scm2
-rw-r--r--guix/build/utils.scm8
9 files changed, 331 insertions, 63 deletions
diff --git a/guix/build/clojure-build-system.scm b/guix/build/clojure-build-system.scm
index d8f7c89f85..7d494078ea 100644
--- a/guix/build/clojure-build-system.scm
+++ b/guix/build/clojure-build-system.scm
@@ -34,8 +34,24 @@
;;
;; Code:
+(define* (compile-java #:key
+ java-source-dirs java-compile-dir
+ #:allow-other-keys)
+ "Compile java sources for use in clojure-build-system."
+ (let ((java-files (append-map (lambda (dir)
+ (find-files dir "\\.java$"))
+ java-source-dirs)))
+ (mkdir-p java-compile-dir)
+ (when (not (null? java-files))
+ (apply invoke
+ "javac"
+ "-verbose"
+ "-d" java-compile-dir
+ java-files))))
+
(define* (build #:key
- source-dirs compile-dir
+ source-dirs java-source-dirs
+ compile-dir java-compile-dir
jar-names main-class omit-source?
aot-include aot-exclude
#:allow-other-keys)
@@ -46,19 +62,24 @@
#:all-list libs)))
(mkdir-p compile-dir)
(eval-with-clojure `(run! compile ',libs*)
- source-dirs)
+ (cons* compile-dir
+ java-compile-dir
+ source-dirs))
(let ((source-dir-files-alist (map (lambda (dir)
(cons dir (find-files* dir)))
- source-dirs))
+ (append source-dirs
+ java-source-dirs)))
;; workaround transitive compilation in Clojure
(classes (filter (lambda (class)
(any (cut compiled-from? class <>)
libs*))
(find-files* compile-dir))))
- (for-each (cut create-jar <> (cons (cons compile-dir classes)
- (if omit-source?
- '()
- source-dir-files-alist))
+ (for-each (cut create-jar <> (cons* (cons compile-dir classes)
+ (cons java-compile-dir
+ (find-files* java-compile-dir))
+ (if omit-source?
+ '()
+ source-dir-files-alist))
#:main-class main-class)
jar-names)
#t)))
@@ -78,8 +99,11 @@ priority over TEST-INCLUDE."
(for-each (lambda (jar)
(eval-with-clojure `(do (apply require
'(clojure.test ,@libs*))
- (apply clojure.test/run-tests
- ',libs*))
+ (if (clojure.test/successful?
+ (apply clojure.test/run-tests
+ ',libs*))
+ (System/exit 0)
+ (System/exit 1)))
(cons jar test-dirs)))
jar-names)))
#t)
@@ -91,6 +115,7 @@ priority over TEST-INCLUDE."
(define-with-docs %standard-phases
"Standard build phases for clojure-build-system."
(modify-phases %standard-phases@ant
+ (add-before 'build 'compile-java compile-java)
(replace 'build build)
(replace 'check check)
(replace 'install install)
diff --git a/guix/build/clojure-utils.scm b/guix/build/clojure-utils.scm
index a9ffad3c8f..c5322141d3 100644
--- a/guix/build/clojure-utils.scm
+++ b/guix/build/clojure-utils.scm
@@ -32,8 +32,10 @@
install-doc
%source-dirs
+ %java-source-dirs
%test-dirs
%compile-dir
+ %java-compile-dir
package-name->jar-names
%main-class
%omit-source?
@@ -101,6 +103,10 @@ DOC-REGEX can be compiled or uncompiled."
"A default list of source directories."
'("src/"))
+(define-with-docs %java-source-dirs
+ "A default list of java source directories."
+ '())
+
(define-with-docs %test-dirs
"A default list of test directories."
'("test/"))
@@ -109,6 +115,10 @@ DOC-REGEX can be compiled or uncompiled."
"Default directory for holding class files."
"classes/")
+(define-with-docs %java-compile-dir
+ "Default directory for holding java class files."
+ "java-classes/")
+
(define (package-name->jar-names name)
"Given NAME, a package name like \"foo-0.9.1b\",
return the list of default jar names: (\"foo-0.9.1b.jar\" \"foo.jar\")."
@@ -135,7 +145,7 @@ all libraries found under the source directories."
(define-with-docs %aot-exclude
"A default list of symbols deciding what not to compile.
See the doc string of '%aot-include' for more details."
- '())
+ '(data-readers))
(define-with-docs %tests?
"Enable tests by default."
diff --git a/guix/build/compile.scm b/guix/build/compile.scm
index b86ec3b743..5b27b55d02 100644
--- a/guix/build/compile.scm
+++ b/guix/build/compile.scm
@@ -1,5 +1,5 @@
;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2013, 2014, 2016, 2017, 2018, 2019, 2020 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2013-2014, 2016-2020, 2022 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2015 Taylan Ulrich Bayırlı/Kammer <taylanbayirli@gmail.com>
;;;
;;; This file is part of GNU Guix.
@@ -37,6 +37,21 @@
;;;
;;; Code:
+(define (clear-keyword-arguments keywords args)
+ "Set to #f the value associated with each of the KEYWORDS in ARGS."
+ (let loop ((args args)
+ (result '()))
+ (match args
+ (()
+ (reverse result))
+ (((? keyword? kw) arg . rest)
+ (loop rest
+ (if (memq kw keywords)
+ (cons* #f kw result)
+ (cons* arg kw result))))
+ ((head . tail)
+ (loop tail (cons head result))))))
+
(define optimizations-for-level
(or (and=> (false-if-exception
(resolve-interface '(system base optimize)))
@@ -60,9 +75,18 @@
(loop rest `(#f ,kw ,@result))))))
(lambda (level)
- (if (<= level 1)
- %lightweight-optimizations
- %default-optimizations)))))
+ ;; In the upcoming Guile 3.0.8, .go files include code of their
+ ;; inlinable exports and free variables are resolved at compile time
+ ;; (both are enabled at -O1) to permit cross-module inlining
+ ;; (enabled at -O2). Unfortunately, this currently leads to
+ ;; non-reproducible and more expensive builds, so we turn it off
+ ;; here:
+ ;; <https://wingolog.org/archives/2021/05/13/cross-module-inlining-in-guile>.
+ (clear-keyword-arguments '(#:inlinable-exports? #:resolve-free-vars?
+ #:cross-module-inlining?)
+ (if (<= level 1)
+ %lightweight-optimizations
+ %default-optimizations))))))
(define (supported-warning-type? type)
"Return true if TYPE, a symbol, denotes a supported warning type."
diff --git a/guix/build/gnu-build-system.scm b/guix/build/gnu-build-system.scm
index d0f7413268..d84411c090 100644
--- a/guix/build/gnu-build-system.scm
+++ b/guix/build/gnu-build-system.scm
@@ -598,6 +598,8 @@ and 'man/'. This phase moves directories to the right place if needed."
(string-suffix? ".tgz" file))
(gzip-file? file)))
#:stat lstat)))
+ ;; Ensure the files are writable.
+ (for-each make-file-writable files)
(for-each reset-gzip-timestamp files)))
(match outputs
diff --git a/guix/build/go-build-system.scm b/guix/build/go-build-system.scm
index 4768ee8562..7f25e05d0d 100644
--- a/guix/build/go-build-system.scm
+++ b/guix/build/go-build-system.scm
@@ -5,6 +5,7 @@
;;; Copyright © 2020 Jack Hill <jackhill@jackhill.us>
;;; Copyright © 2020 Jakub Kądziołka <kuba@kadziolka.net>
;;; Copyright © 2020, 2021 Efraim Flashner <efraim@flashner.co.il>
+;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -138,9 +139,28 @@ of the package being built and its dependencies, and GOBIN, which determines
where executables (\"commands\") are installed to. This phase is sometimes used
by packages that use (guix build-system gnu) but have a handful of Go
dependencies, so it should be self-contained."
- ;; The Go cache is required starting in Go 1.12. We don't actually use it but
- ;; we need it to be a writable directory.
- (setenv "GOCACHE" "/tmp/go-cache")
+ (define (search-input-directories dir)
+ (filter directory-exists?
+ (map (match-lambda
+ ((name . directory)
+ (string-append directory "/" dir)))
+ inputs)))
+
+ ;; Seed the Go build cache with the build caches from input packages.
+ (let ((cache (string-append (getcwd) "/go-build")))
+ (setenv "GOCACHE" cache)
+ (union-build cache
+ (search-input-directories "/var/cache/go/build")
+ ;; Creating all directories isn't that bad, because there are
+ ;; only ever 256 of them.
+ #:create-all-directories? #t
+ #:log-port (%make-void-port "w"))
+
+ ;; Tell Go that the cache was recently trimmed, so it doesn't try to.
+ (call-with-output-file (string-append cache "/trim.txt")
+ (lambda (port)
+ (format port "~a" (current-time)))))
+
;; Using the current working directory as GOPATH makes it easier for packagers
;; who need to manipulate the unpacked source code.
(setenv "GOPATH" (getcwd))
diff --git a/guix/build/julia-build-system.scm b/guix/build/julia-build-system.scm
index b4e0044567..03d669be64 100644
--- a/guix/build/julia-build-system.scm
+++ b/guix/build/julia-build-system.scm
@@ -1,7 +1,7 @@
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2019, 2020 Nicolò Balzarotti <nicolo@nixo.xyz>
;;; Copyright © 2021 Jean-Baptiste Volatier <jbv@pm.me>
-;;; Copyright © 2021 Simon Tournier <zimon.toutoune@gmail.com>
+;;; Copyright © 2021, 2022 Simon Tournier <zimon.toutoune@gmail.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -27,8 +27,8 @@
#:use-module (ice-9 regex)
#:use-module (ice-9 rdelim)
#:use-module (ice-9 popen)
+ #:use-module (srfi srfi-1)
#:export (%standard-phases
- julia-create-package-toml
julia-build))
;; Commentary:
@@ -138,6 +138,8 @@ Project.toml)."
(define* (link-depot #:key source inputs outputs
julia-package-name julia-package-uuid #:allow-other-keys)
(let* ((out (assoc-ref outputs "out"))
+ (name+version (strip-store-file-name out))
+ (version (last (string-split name+version #\-)))
(package-name (or
julia-package-name
(project.toml->name "Project.toml")))
@@ -148,6 +150,14 @@ Project.toml)."
println(Base.version_slug(Base.UUID(\"~a\"),
Base.SHA1(Pkg.GitTools.tree_hash(\".\"))))" uuid)))
(slug (string-trim-right (get-string-all pipe))))
+ ;; Few packages do not have the regular Project.toml file, then when they
+ ;; are propagated, dependencies do not find them and an raise error.
+ (unless (file-exists? "Project.toml")
+ (julia-create-package-toml (getcwd)
+ julia-package-name julia-package-uuid
+ version
+ #:file "Project.toml"))
+
;; When installing a package, julia looks first at in the JULIA_DEPOT_PATH
;; for a path like packages/PACKAGE/XXXX
;; Where XXXX is a slug encoding the package UUID and SHA1 of the files
@@ -157,17 +167,16 @@ println(Base.version_slug(Base.UUID(\"~a\"),
(symlink package-dir (string-append out "/share/julia/packages/"
package-name "/" slug))))
-(define (julia-create-package-toml outputs source
- name uuid version
- deps)
- "Some packages are not using the new Package.toml dependency specifications.
-Write this file manually, so that Julia can find its dependencies."
+(define* (julia-create-package-toml location
+ name uuid version
+ #:optional
+ (deps '())
+ #:key
+ (file "Project.toml"))
+ "Some packages are not using the new Project.toml dependency specifications.
+Write this FILE manually, so that Julia can find its dependencies."
(let ((f (open-file
- (string-append
- (assoc-ref outputs "out")
- %package-path
- (string-append
- name "/Project.toml"))
+ (string-append location "/" file)
"w")))
(display (string-append
"
diff --git a/guix/build/node-build-system.scm b/guix/build/node-build-system.scm
index 70a367618e..bee3792e93 100644
--- a/guix/build/node-build-system.scm
+++ b/guix/build/node-build-system.scm
@@ -2,6 +2,8 @@
;;; Copyright © 2015 David Thompson <davet@gnu.org>
;;; Copyright © 2016, 2020 Jelle Licht <jlicht@fsfe.org>
;;; Copyright © 2019, 2021 Timothy Sample <samplet@ngyro.com>
+;;; Copyright © 2021, 2022 Philip McGrath <philip@philipmcgrath.com>
+;;; Copyright © 2022 Liliana Marie Prikler <liliana.prikler@gmail.com>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -23,16 +25,108 @@
#:use-module (guix build utils)
#:use-module (guix build json)
#:use-module (ice-9 ftw)
+ #:use-module (ice-9 regex)
#:use-module (ice-9 match)
#:use-module (srfi srfi-1)
+ #:use-module (srfi srfi-71)
#:export (%standard-phases
+ with-atomic-json-file-replacement
+ delete-dependencies
node-build))
-;; Commentary:
-;;
-;; Builder-side code of the standard Node/NPM package install procedure.
-;;
-;; Code:
+(define (with-atomic-json-file-replacement file proc)
+ "Like 'with-atomic-file-replacement', but PROC is called with a single
+argument---the result of parsing FILE's contents as json---and should a value
+to be written as json to the replacement FILE."
+ (with-atomic-file-replacement file
+ (lambda (in out)
+ (write-json (proc (read-json in)) out))))
+
+(define* (assoc-ref* alist key #:optional default)
+ "Like assoc-ref, but return DEFAULT instead of #f if no value exists."
+ (match (assoc key alist)
+ (#f default)
+ ((_ . value) value)))
+
+(define* (jsobject-ref obj key #:optional default)
+ (match obj
+ (('@ . alist) (assoc-ref* alist key default))))
+
+(define* (alist-pop alist key #:optional (= equal?))
+ "Return two values, the first pair in ALIST with key KEY, and the other
+elements. Equality calls are made as (= KEY ALISTCAR)."
+ (define (found? pair)
+ (= key (car pair)))
+
+ (let ((before after (break found? alist)))
+ (if (pair? after)
+ (values (car after) (append before (cdr after)))
+ (values #f before))))
+
+(define* (alist-update alist key proc #:optional default (= equal?))
+ "Return an association list like ALIST, but with KEY mapped to the result of
+PROC applied to the first value found under the comparison (= KEY ALISTCAR).
+If no such value exists, use DEFAULT instead.
+Unlike acons, this removes the previous association of KEY (assuming it is
+unique), but the result may still share storage with ALIST."
+ (let ((pair rest (alist-pop alist key =)))
+ (acons key
+ (proc (if (pair? pair)
+ (cdr pair)
+ default))
+ rest)))
+
+(define (jsobject-update* js . updates)
+ "Return a json object like JS, but with all UPDATES applied. Each update is
+a list (KEY PROC [DEFAULT]), so that KEY is mapped to the result of PROC
+applied to the value to which KEY is mapped in JS. If no such mapping exists,
+PROC is instead applied to DEFAULT, or to '#f' is no DEFAULT is specified.
+The update takes place from left to right, so later UPDATERs will receive the
+values returned by earlier UPDATERs for the same KEY."
+ (match js
+ (('@ . alist)
+ (let loop ((alist alist)
+ (updates updates))
+ (match updates
+ (() (cons '@ alist))
+ (((key proc) . updates)
+ (loop (alist-update alist key proc #f equal?) updates))
+ (((key proc default) . updates)
+ (loop (alist-update alist key proc default equal?) updates)))))))
+
+(define (jsobject-union combine seed . objects)
+ "Merge OBJECTS into SEED by applying (COMBINE KEY VAL0 VAL), where VAL0
+is the value found in the (possibly updated) SEED and VAL is the new value
+found in one of the OBJECTS."
+ (match seed
+ (('@ . aseed)
+ (match objects
+ (() seed)
+ ((('@ . alists) ...)
+ (cons
+ '@
+ (fold (lambda (alist aseed)
+ (if (null? aseed) alist
+ (fold
+ (match-lambda*
+ (((k . v) aseed)
+ (let ((pair tail (alist-pop alist k)))
+ (match pair
+ (#f (acons k v aseed))
+ ((_ . v0) (acons k (combine k v0 v) aseed))))))
+ aseed
+ alist)))
+ aseed
+ alists)))))))
+
+;; Possibly useful helper functions:
+;; (define (newest key val0 val) val)
+;; (define (unkeyed->keyed proc) (lambda (_key val0 val) (proc val0 val)))
+
+
+;;;
+;;; Phases.
+;;;
(define (set-home . _)
(with-directory-excursion ".."
@@ -49,7 +143,7 @@
(define (module-name module)
(let* ((package.json (string-append module "/package.json"))
(package-meta (call-with-input-file package.json read-json)))
- (assoc-ref package-meta "name")))
+ (jsobject-ref package-meta "name")))
(define (index-modules input-paths)
(define (list-modules directory)
@@ -73,27 +167,58 @@
(define index (index-modules (map cdr inputs)))
- (define (resolve-dependencies package-meta meta-key)
- (fold (lambda (key+value acc)
- (match key+value
- ('@ acc)
- ((key . value) (acons key (hash-ref index key value) acc))))
- '()
- (or (assoc-ref package-meta meta-key) '())))
+ (define resolve-dependencies
+ (match-lambda
+ (('@ . alist)
+ (cons '@ (map (match-lambda
+ ((key . value)
+ (cons key (hash-ref index key value))))
+ alist)))))
- (with-atomic-file-replacement "package.json"
- (lambda (in out)
- (let ((package-meta (read-json in)))
- (assoc-set! package-meta "dependencies"
- (append
- '(@)
- (resolve-dependencies package-meta "dependencies")
- (resolve-dependencies package-meta "peerDependencies")))
- (assoc-set! package-meta "devDependencies"
- (append
- '(@)
- (resolve-dependencies package-meta "devDependencies")))
- (write-json package-meta out))))
+ (with-atomic-json-file-replacement "package.json"
+ (lambda (pkg-meta)
+ (jsobject-update*
+ pkg-meta
+ `("devDependencies" ,resolve-dependencies (@))
+ `("dependencies" ,(lambda (deps)
+ (resolve-dependencies
+ (jsobject-union
+ (lambda (k a b) b)
+ (jsobject-ref pkg-meta "peerDependencies" '(@))
+ deps)))
+ (@)))))
+ #t)
+
+(define (delete-dependencies absent)
+ "Rewrite 'package.json' to allow the build to proceed without packages
+listed in ABSENT, a list of strings naming npm packages.
+
+To prevent the deleted dependencies from being reintroduced, use this function
+only after the 'patch-dependencies' phase."
+ (define delete-from-jsobject
+ (match-lambda
+ (('@ . alist)
+ (cons '@ (filter (match-lambda
+ ((k . _)
+ (not (member k absent))))
+ alist)))))
+
+ (with-atomic-json-file-replacement "package.json"
+ (lambda (pkg-meta)
+ (jsobject-update*
+ pkg-meta
+ `("devDependencies" ,delete-from-jsobject (@))
+ `("dependencies" ,delete-from-jsobject (@))))))
+
+(define* (delete-lockfiles #:key inputs #:allow-other-keys)
+ "Delete 'package-lock.json', 'yarn.lock', and 'npm-shrinkwrap.json', if they
+exist."
+ (for-each (lambda (pth)
+ (when (file-exists? pth)
+ (delete-file pth)))
+ '("package-lock.json"
+ "yarn.lock"
+ "npm-shrinkwrap.json"))
#t)
(define* (configure #:key outputs inputs #:allow-other-keys)
@@ -103,9 +228,7 @@
(define* (build #:key inputs #:allow-other-keys)
(let ((package-meta (call-with-input-file "package.json" read-json)))
- (if (and=> (assoc-ref package-meta "scripts")
- (lambda (scripts)
- (assoc-ref scripts "build")))
+ (if (jsobject-ref (jsobject-ref package-meta "scripts" '(@)) "build" #f)
(let ((npm (string-append (assoc-ref inputs "node") "/bin/npm")))
(invoke npm "run" "build"))
(format #t "there is no build script to run~%"))
@@ -142,15 +265,68 @@
"install" "../package.tgz")
#t))
+(define* (avoid-node-gyp-rebuild #:key outputs #:allow-other-keys)
+ "Adjust the installed 'package.json' to remove an 'install' script that
+would try to run 'node-gyp rebuild'."
+ ;; We want to take advantage of `npm install`'s automatic support for
+ ;; building native addons with node-gyp: in particular, it helps us avoid
+ ;; hard-coding the specifics of how npm's internal copy of node-gyp is
+ ;; currently packaged. However, the mechanism by which the automatic support
+ ;; is implemented causes problems for us.
+ ;;
+ ;; If a package contains a 'binding.gyp' file and does not define an
+ ;; 'install' or 'preinstall' script, 'npm install' runs a default install
+ ;; script consisting of 'node-gyp rebuild'. In our 'install' phase, this
+ ;; implicit 'install' script, if it is applicable, is explicitly added to
+ ;; the "package.json" file. However, if another Guix package were to use a
+ ;; Node.js package with such an 'install' script, the dependent package's
+ ;; build process would fail, because 'node-gyp rebuild' would try to write
+ ;; to the store.
+ ;;
+ ;; Here, if the installed "package.json" defines scripts.install as
+ ;; "node-gyp rebuild", we replace it with a no-op. Importantly, deleting the
+ ;; install script definition would not be enough, because the default
+ ;; install script would cause the same problem.
+ ;;
+ ;; For further details, see:
+ ;; - https://docs.npmjs.com/cli/v8/configuring-npm/package-json#default-values
+ ;; - https://docs.npmjs.com/cli/v8/using-npm/scripts#best-practices
+ (define installed-package.json
+ (search-input-file outputs (string-append "/lib/node_modules/"
+ (module-name ".")
+ "/package.json")))
+ ;; We don't want to use an atomic replacement here, because we often don't
+ ;; even need to overwrite this file. Therefore, let's use some helpers
+ ;; that we'd otherwise not need.
+ (define pkg-meta
+ (call-with-input-file installed-package.json read-json))
+ (define scripts
+ (jsobject-ref pkg-meta "scripts" '(@)))
+ (define (jsobject-set js key val)
+ (jsobject-update* js (list key (const val))))
+
+ (when (equal? "node-gyp rebuild" (jsobject-ref scripts "install" #f))
+ (call-with-output-file installed-package.json
+ (lambda (out)
+ (write-json
+ (jsobject-set pkg-meta
+ "scripts"
+ (jsobject-set scripts
+ "install"
+ "echo Guix: avoiding node-gyp rebuild"))
+ out)))))
+
(define %standard-phases
(modify-phases gnu:%standard-phases
(add-after 'unpack 'set-home set-home)
(add-before 'configure 'patch-dependencies patch-dependencies)
+ (add-after 'patch-dependencies 'delete-lockfiles delete-lockfiles)
(replace 'configure configure)
(replace 'build build)
(replace 'check check)
(add-before 'install 'repack repack)
- (replace 'install install)))
+ (replace 'install install)
+ (add-after 'install 'avoid-node-gyp-rebuild avoid-node-gyp-rebuild)))
(define* (node-build #:key inputs (phases %standard-phases)
#:allow-other-keys #:rest args)
diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm
index 45f95c509d..a7401fd73f 100644
--- a/guix/build/syscalls.scm
+++ b/guix/build/syscalls.scm
@@ -132,6 +132,7 @@
CLONE_CHILD_CLEARTID
CLONE_CHILD_SETTID
+ CLONE_NEWCGROUP
CLONE_NEWNS
CLONE_NEWUTS
CLONE_NEWIPC
@@ -1025,6 +1026,7 @@ caller lacks root privileges."
;; Linux clone flags, from linux/sched.h
(define CLONE_CHILD_CLEARTID #x00200000)
(define CLONE_CHILD_SETTID #x01000000)
+(define CLONE_NEWCGROUP #x02000000)
(define CLONE_NEWNS #x00020000)
(define CLONE_NEWUTS #x04000000)
(define CLONE_NEWIPC #x08000000)
diff --git a/guix/build/utils.scm b/guix/build/utils.scm
index 39e581b0fa..b822caf619 100644
--- a/guix/build/utils.scm
+++ b/guix/build/utils.scm
@@ -8,6 +8,7 @@
;;; Copyright © 2020 Efraim Flashner <efraim@flashner.co.il>
;;; Copyright © 2020, 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com>
;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
+;;; Copyright © 2021 Brendan Tildesley <mail@brendan.scot>
;;;
;;; This file is part of GNU Guix.
;;;
@@ -1473,10 +1474,9 @@ not supported."
`(let ((cl (command-line)))
(apply execl ,interpreter
(car cl)
- (cons (car cl)
- (append
- ',(string-split args #\space)
- cl))))))
+ (append
+ ',(string-tokenize args char-set:graphic)
+ cl)))))
(template (string-append prog ".XXXXXX"))
(out (mkstemp! template))
(st (stat prog))