diff options
Diffstat (limited to 'guix/build/julia-build-system.scm')
-rw-r--r-- | guix/build/julia-build-system.scm | 115 |
1 files changed, 88 insertions, 27 deletions
diff --git a/guix/build/julia-build-system.scm b/guix/build/julia-build-system.scm index d74acf2a05..03d669be64 100644 --- a/guix/build/julia-build-system.scm +++ b/guix/build/julia-build-system.scm @@ -1,5 +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, 2022 Simon Tournier <zimon.toutoune@gmail.com> ;;; ;;; This file is part of GNU Guix. ;;; @@ -20,11 +22,13 @@ (define-module (guix build julia-build-system) #:use-module ((guix build gnu-build-system) #:prefix gnu:) #:use-module (guix build utils) + #:use-module (rnrs io ports) #:use-module (ice-9 match) #: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: @@ -37,7 +41,7 @@ (invoke "julia" "-e" code)) ;; subpath where we store the package content -(define %package-path "/share/julia/packages/") +(define %package-path "/share/julia/loadpath/") (define (project.toml->name file) "Look for Julia package name in the TOML file FILE (usually named @@ -51,6 +55,18 @@ Project.toml)." (if m (match:substring m 1) (loop (read-line in 'concat))))))))) +(define (project.toml->uuid file) + "Look for Julia package uuid in the TOML file FILE (usually named +Project.toml)." + (call-with-input-file file + (lambda (in) + (let loop ((line (read-line in 'concat))) + (if (eof-object? line) + #f + (let ((m (string-match "uuid\\s*=\\s*\"(.*)\"" line))) + (if m (match:substring m 1) + (loop (read-line in 'concat))))))))) + (define* (install #:key source inputs outputs julia-package-name #:allow-other-keys) (let* ((out (assoc-ref outputs "out")) @@ -59,8 +75,7 @@ Project.toml)." julia-package-name (project.toml->name "Project.toml"))))) (mkdir-p package-dir) - (copy-recursively (getcwd) package-dir)) - #t) + (copy-recursively (getcwd) package-dir))) (define* (precompile #:key source inputs outputs julia-package-name #:allow-other-keys) @@ -73,7 +88,7 @@ Project.toml)." (setenv "JULIA_DEPOT_PATH" builddir) ;; Add new package dir to the load path. (setenv "JULIA_LOAD_PATH" - (string-append builddir "packages/" ":" + (string-append builddir "loadpath/" ":" (or (getenv "JULIA_LOAD_PATH") ""))) ;; Actual precompilation: @@ -84,39 +99,84 @@ Project.toml)." ;; element of DEPOT_PATH. Once the cache file exists, this hack is not ;; needed anymore (like in the check phase). If the user install new ;; packages, those will be installed and precompiled in the home dir. - (string-append "pushfirst!(DEPOT_PATH, pop!(DEPOT_PATH)); using " package))) - #t) + (string-append "pushfirst!(DEPOT_PATH, pop!(DEPOT_PATH)); using " + package)))) (define* (check #:key tests? source inputs outputs julia-package-name - #:allow-other-keys) + parallel-tests? #:allow-other-keys) (when tests? (let* ((out (assoc-ref outputs "out")) (package (or julia-package-name (project.toml->name "Project.toml"))) - (builddir (string-append out "/share/julia/"))) + (builddir (string-append out "/share/julia/")) + (job-count (if parallel-tests? + (parallel-job-count) + 1)) + ;; The --proc argument of Julia *adds* extra processors rather than + ;; specify the exact count to use, so zero must be specified to + ;; disable parallel processing... + (additional-procs (max 0 (1- job-count)))) ;; With a patch, SOURCE_DATE_EPOCH is honored (setenv "SOURCE_DATE_EPOCH" "1") (setenv "JULIA_DEPOT_PATH" builddir) (setenv "JULIA_LOAD_PATH" - (string-append builddir "packages/" ":" + (string-append builddir "loadpath/" ":" (or (getenv "JULIA_LOAD_PATH") ""))) + (setenv "JULIA_CPU_THREADS" (number->string job-count)) (setenv "HOME" "/tmp") - (invoke "julia" "--depwarn=yes" - (string-append builddir "packages/" - package "/test/runtests.jl")))) - #t) + (apply invoke "julia" + `("--depwarn=yes" + ,@(if parallel-tests? + ;; XXX: ... but '--procs' doesn't accept 0 as a valid + ;; value, so just omit the argument entirely. + (list (string-append "--procs=" + (number->string additional-procs))) + '()) + ,(string-append builddir "loadpath/" + package "/test/runtests.jl")))))) + +(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"))) + (package-dir (string-append out %package-path package-name)) + (uuid (or julia-package-uuid (project.toml->uuid "Project.toml"))) + (pipe (open-pipe* OPEN_READ "julia" "-e" + (format #f "using Pkg; +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 + ;; Here we create a link with the correct path to enable julia to find the + ;; package + (mkdir-p (string-append out "/share/julia/packages/" package-name)) + (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 " @@ -130,14 +190,14 @@ version = \"" version "\" (display (string-append (car (car dep)) " = \"" (cdr (car dep)) "\"\n") f)) deps)) - (close-port f)) - #t) + (close-port f))) (define %standard-phases (modify-phases gnu:%standard-phases (delete 'check) ; tests must be run after installation (replace 'install install) (add-after 'install 'precompile precompile) + (add-after 'unpack 'link-depot link-depot) (add-after 'install 'check check) ;; TODO: In the future we could add a "system-image-generation" phase ;; where we use PackageCompiler.jl to speed up package loading times @@ -146,11 +206,12 @@ version = \"" version "\" (delete 'patch-usr-bin-file) (delete 'build))) -(define* (julia-build #:key inputs julia-package-name +(define* (julia-build #:key inputs julia-package-name julia-package-uuid (phases %standard-phases) #:allow-other-keys #:rest args) "Build the given Julia package, applying all of PHASES in order." (apply gnu:gnu-build #:inputs inputs #:phases phases #:julia-package-name julia-package-name + #:julia-package-uuid julia-package-uuid args)) |