diff options
author | Liliana Marie Prikler <liliana.prikler@gmail.com> | 2024-01-21 09:59:52 +0100 |
---|---|---|
committer | Liliana Marie Prikler <liliana.prikler@gmail.com> | 2024-01-21 09:59:55 +0100 |
commit | ff1ec930e5baa00b483f1ce43fa8bec18c797c03 (patch) | |
tree | 1c102408d5d79e12b70fe81f97602d3856ed334e /guix | |
parent | 60c97924e9519361494aaf0686e28eb831a42315 (diff) | |
parent | c7f937cfdd9a08bad81705fe731e9fa5937cf562 (diff) | |
download | guix-ff1ec930e5baa00b483f1ce43fa8bec18c797c03.tar guix-ff1ec930e5baa00b483f1ce43fa8bec18c797c03.tar.gz |
Merge branch 'master' into emacs-team
Diffstat (limited to 'guix')
72 files changed, 3023 insertions, 448 deletions
diff --git a/guix/build-system/ant.scm b/guix/build-system/ant.scm index e191fd3c99..84bf951fab 100644 --- a/guix/build-system/ant.scm +++ b/guix/build-system/ant.scm @@ -103,6 +103,7 @@ (build-target "jar") (jar-name #f) (main-class #f) + (use-java-modules? #f) (test-include (list "**/*Test.java")) (test-exclude (list "**/Abstract*.java")) (source-dir "src") @@ -131,6 +132,7 @@ #:build-target #$build-target #:jar-name #$jar-name #:main-class #$main-class + #:use-java-modules? #$use-java-modules? #:test-include (list #$@test-include) #:test-exclude (list #$@test-exclude) #:source-dir #$source-dir diff --git a/guix/build-system/cargo.scm b/guix/build-system/cargo.scm index 912400a191..c029cc1dda 100644 --- a/guix/build-system/cargo.scm +++ b/guix/build-system/cargo.scm @@ -55,12 +55,18 @@ to NAME and VERSION." (string-append crate-url name "/" version "/download")) -(define (default-rust) +(define (default-rust target) "Return the default Rust package." ;; Lazily resolve the binding to avoid a circular dependency. (let ((rust (resolve-interface '(gnu packages rust)))) (module-ref rust 'rust))) +(define (default-rust-sysroot target) + "Return the default Rust sysroot for <target>." + ;; Lazily resolve the binding to avoid a circular dependency. + (let ((module (resolve-interface '(gnu packages rust)))) + (module-ref module 'make-rust-sysroot))) + (define %cargo-utils-modules ;; Build-side modules imported by default. `((guix build cargo-utils) @@ -126,6 +132,69 @@ to NAME and VERSION." #:graft? #f #:guile-for-build guile)) +(define* (cargo-cross-build name + #:key + source target + build-inputs target-inputs host-inputs + (tests? #f) + (test-target #f) + (vendor-dir "guix-vendor") + (cargo-build-flags ''("--release")) + (cargo-test-flags ''("--release")) + (cargo-package-flags ''("--no-metadata" "--no-verify")) + (features ''()) + (skip-build? #f) + (install-source? (not (target-mingw? target))) + (phases '%standard-phases) + (outputs '("out")) + (search-paths '()) + (native-search-paths '()) + (system (%current-system)) + (guile #f) + (imported-modules %cargo-build-system-modules) + (modules '((guix build cargo-build-system) + (guix build utils)))) + "Cross-build SOURCE using CARGO, and with INPUTS." + + (define builder + (with-imported-modules imported-modules + #~(begin + (use-modules #$@(sexp->gexp modules)) + + (cargo-build #:name #$name + #:source #+source + #:target #+target + #:system #$system + #:test-target #$test-target + #:vendor-dir #$vendor-dir + #:cargo-build-flags #$(sexp->gexp cargo-build-flags) + #:cargo-test-flags #$(sexp->gexp cargo-test-flags) + #:cargo-package-flags #$(sexp->gexp cargo-package-flags) + #:features #$(sexp->gexp features) + #:skip-build? #$skip-build? + #:install-source? #$install-source? + #:tests? #$(and tests? (not skip-build?)) + #:phases #$(if (pair? phases) + (sexp->gexp phases) + phases) + #:outputs #$(outputs->gexp outputs) + #:inputs (append #$(input-tuples->gexp host-inputs) + #+(input-tuples->gexp target-inputs)) + #:native-inputs #+(input-tuples->gexp build-inputs) + #:make-dynamic-linker-cache? #f ;cross-compiling + #:search-paths '#$(sexp->gexp + (map search-path-specification->sexp + search-paths)) + #:native-search-paths '#$(sexp->gexp + (map search-path-specification->sexp + native-search-paths)))))) + + (gexp->derivation name builder + #:system system + #:target target + #:graft? #f + #:guile-for-build guile)) + (define (package-cargo-inputs p) (apply (lambda* (#:key (cargo-inputs '()) #:allow-other-keys) @@ -235,7 +304,8 @@ any dependent crates. This can be a benefits: (define* (lower name #:key source inputs native-inputs outputs system target - (rust (default-rust)) + (rust (default-rust target)) + (rust-sysroot (default-rust-sysroot target)) (cargo-inputs '()) (cargo-development-inputs '()) #:allow-other-keys @@ -243,28 +313,49 @@ any dependent crates. This can be a benefits: "Return a bag for NAME." (define private-keywords - '(#:target #:rust #:inputs #:native-inputs #:outputs - #:cargo-inputs #:cargo-development-inputs)) - - (and (not target) ;; TODO: support cross-compilation - (bag - (name name) - (system system) - (target target) - (host-inputs `(,@(if source - `(("source" ,source)) - '()) - ,@inputs - - ;; Keep the standard inputs of 'gnu-build-system' - ,@(standard-packages))) - (build-inputs `(("cargo" ,rust "cargo") - ("rustc" ,rust) - ,@(expand-crate-sources cargo-inputs cargo-development-inputs) - ,@native-inputs)) - (outputs outputs) - (build cargo-build) - (arguments (strip-keyword-arguments private-keywords arguments))))) + `(#:rust #:inputs #:native-inputs #:outputs + #:cargo-inputs #:cargo-development-inputs + #:rust-sysroot + ,@(if target '() '(#:target)))) + + (bag + (name name) + (system system) + (target target) + (host-inputs `(,@(if source + `(("source" ,source)) + '()) + + ;,@(if target '() inputs) + ,@(if target inputs '()) + + ,@(expand-crate-sources cargo-inputs cargo-development-inputs))) + (build-inputs `(("cargo" ,rust "cargo") + ("rustc" ,rust) + + ,@native-inputs + ;,@(if target inputs '()) + ,@(if target '() inputs) + ;,@inputs + + ,@(if target + ;; Use the standard cross inputs of + ;; 'gnu-build-system'. + (standard-cross-packages target 'host) + '()) + ;; Keep the standard inputs of 'gnu-build-system' + ,@(standard-packages))) + (target-inputs `(,@(if target + (standard-cross-packages target 'target) + '()) + + ;; This provides a separate sysroot for the regular rustc + ,@(if target + `(("rust-sysroot" ,(rust-sysroot target))) + '()))) + (outputs outputs) + (build (if target cargo-cross-build cargo-build)) + (arguments (strip-keyword-arguments private-keywords arguments)))) (define cargo-build-system (build-system diff --git a/guix/build-system/clojure.scm b/guix/build-system/clojure.scm index fb897356bc..037fcaf21d 100644 --- a/guix/build-system/clojure.scm +++ b/guix/build-system/clojure.scm @@ -83,8 +83,8 @@ #:clojure #:jdk #:zip))) (if target - (error "No cross-compilation for clojure-build-system yet: LOWER" - target) ; FIXME + #f ; FIXME: No cross-compilation for + ; clojure-build-system yet (bag (name name) (system system) (host-inputs `(,@(if source diff --git a/guix/build-system/composer.scm b/guix/build-system/composer.scm new file mode 100644 index 0000000000..2ad7bbb36a --- /dev/null +++ b/guix/build-system/composer.scm @@ -0,0 +1,166 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu> +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. + +(define-module (guix build-system composer) + #:use-module (guix store) + #:use-module (guix utils) + #:use-module (guix derivations) + #:use-module (guix search-paths) + #:use-module (guix build-system) + #:use-module (guix build-system gnu) + #:use-module (guix gexp) + #:use-module (guix packages) + #:use-module (gnu packages) + #:use-module (ice-9 match) + #:use-module (srfi srfi-1) + #:export (%composer-build-system-modules + lower + composer-build + composer-build-system)) + +;; Commentary: +;; +;; Standard build procedure for PHP packages using Composer. This is implemented +;; as an extension of `gnu-build-system'. +;; +;; Code: + +(define (default-php) + "Return the default PHP package." + + ;; Do not use `@' to avoid introducing circular dependencies. + (let ((module (resolve-interface '(gnu packages php)))) + (module-ref module 'php))) + +(define (default-findclass) + "Return the default findclass script." + (search-auxiliary-file "findclass.php")) + +(define (default-composer-classloader) + "Return the default composer-classloader package." + + ;; Do not use `@' to avoid introducing circular dependencies. + (let ((module (resolve-interface '(gnu packages php-xyz)))) + (module-ref module 'composer-classloader))) + +(define %composer-build-system-modules + ;; Build-side modules imported by default. + `((guix build composer-build-system) + (guix build union) + ,@%gnu-build-system-modules)) + +(define* (lower name + #:key source inputs native-inputs outputs system target + (php (default-php)) + (composer-classloader (default-composer-classloader)) + (findclass (default-findclass)) + #:allow-other-keys + #:rest arguments) + "Return a bag for NAME." + (define private-keywords + '(#:target #:php #:composer-classloader #:findclass #:inputs #:native-inputs)) + + (and (not target) ;XXX: no cross-compilation + (bag + (name name) + (system system) + (host-inputs `(,@(if source + `(("source" ,source)) + '()) + ,@inputs + + ;; Keep the standard inputs of 'gnu-build-system'. + ,@(standard-packages))) + (build-inputs `(("php" ,php) + ("findclass.php" ,findclass) + ("composer-classloader" ,composer-classloader) + ,@native-inputs)) + (outputs outputs) + (build composer-build) + (arguments (strip-keyword-arguments private-keywords arguments))))) + +(define* (composer-build name inputs + #:key + guile source + (outputs '("out")) + (configure-flags ''()) + (search-paths '()) + (out-of-source? #t) + (composer-file "composer.json") + (tests? #t) + (test-target "test") + (test-flags ''()) + (install-target "install") + (validate-runpath? #t) + (patch-shebangs? #t) + (strip-binaries? #t) + (strip-flags #~'("--strip-debug")) + (strip-directories #~'("lib" "lib64" "libexec" + "bin" "sbin")) + (phases '(@ (guix build composer-build-system) + %standard-phases)) + (system (%current-system)) + (imported-modules %composer-build-system-modules) + (modules '((guix build composer-build-system) + (guix build utils)))) + "Build SOURCE using PHP, and with INPUTS. This assumes that SOURCE provides +a 'composer.json' file as its build system." + (define guile-json + (module-ref (resolve-interface '(gnu packages guile)) + 'guile-json-4)) + + (define builder + (with-extensions (list guile-json) + (with-imported-modules imported-modules + #~(begin + (use-modules #$@(sexp->gexp modules)) + + #$(with-build-variables inputs outputs + #~(composer-build + #:source #$source + #:system #$system + #:outputs %outputs + #:inputs %build-inputs + #:search-paths '#$(map search-path-specification->sexp + search-paths) + #:phases #$phases + #:out-of-source? #$out-of-source? + #:composer-file #$composer-file + #:tests? #$tests? + #:test-target #$test-target + #:test-flags #$test-flags + #:install-target #$install-target + #:validate-runpath? #$validate-runpath? + #:patch-shebangs? #$patch-shebangs? + #:strip-binaries? #$strip-binaries? + #:strip-flags #$strip-flags + #:strip-directories #$strip-directories)))))) + + (gexp->derivation name builder + #:system system + #:target #f + #:graft? #f + #:guile-for-build guile)) + +(define composer-build-system + (build-system + (name 'composer) + (description "The standard Composer build system") + (lower lower))) + +;;; composer.scm ends here diff --git a/guix/build-system/gnu.scm b/guix/build-system/gnu.scm index c1aa187c42..cdbb547773 100644 --- a/guix/build-system/gnu.scm +++ b/guix/build-system/gnu.scm @@ -460,10 +460,13 @@ is one of `host' or `target'." `(("cross-gcc" ,(gcc target #:xbinutils (binutils target) #:libc libc)) - ("cross-libc" ,libc) + ;; Some targets don't have a libc. (e.g. *-elf targets). + ,@(if libc + `(("cross-libc" ,libc)) + '()) ;; MinGW's libc doesn't have a "static" output. - ,@(if (member "static" (package-outputs libc)) + ,@(if (and libc (member "static" (package-outputs libc))) `(("cross-libc:static" ,libc "static")) '())))))))) diff --git a/guix/build-system/guile.scm b/guix/build-system/guile.scm index 1bd292e267..bd3bb1c870 100644 --- a/guix/build-system/guile.scm +++ b/guix/build-system/guile.scm @@ -88,7 +88,8 @@ (compile-flags %compile-flags) (imported-modules %guile-build-system-modules) (modules '((guix build guile-build-system) - (guix build utils)))) + (guix build utils))) + (substitutable? #t)) "Build SOURCE using Guile taken from the native inputs, and with INPUTS." (define builder (with-imported-modules imported-modules @@ -114,6 +115,7 @@ #:system system #:target #f #:graft? #f + #:substitutable? substitutable? #:guile-for-build guile))) (define* (guile-cross-build name @@ -133,7 +135,8 @@ (compile-flags %compile-flags) (imported-modules %guile-build-system-modules) (modules '((guix build guile-build-system) - (guix build utils)))) + (guix build utils))) + (substitutable? #t)) (define builder (with-imported-modules imported-modules #~(begin @@ -173,6 +176,7 @@ #:system system #:target target #:graft? #f + #:substitutable? substitutable? #:guile-for-build guile))) (define guile-build-system diff --git a/guix/build-system/meson.scm b/guix/build-system/meson.scm index 7c617bffb0..bf9ca15ecc 100644 --- a/guix/build-system/meson.scm +++ b/guix/build-system/meson.scm @@ -49,11 +49,13 @@ for TRIPLET." `((system . ,(cond ((target-hurd? triplet) "gnu") ((target-linux? triplet) "linux") ((target-mingw? triplet) "windows") + ((target-avr? triplet) "none") (#t (error "meson: unknown operating system")))) (cpu_family . ,(cond ((target-x86-32? triplet) "x86") ((target-x86-64? triplet) "x86_64") ((target-arm32? triplet) "arm") ((target-aarch64? triplet) "aarch64") + ((target-avr? triplet) "avr") ((target-mips64el? triplet) "mips64") ((target-powerpc? triplet) (if (target-64bit? triplet) @@ -66,6 +68,7 @@ for TRIPLET." ((target-x86-64? triplet) "x86_64") ((target-aarch64? triplet) "armv8-a") ((target-arm32? triplet) "armv7") + ((target-avr? triplet) "avr") ;; According to #mesonbuild on OFTC, there does not appear ;; to be an official-ish list of CPU types recognised by ;; Meson, the "cpu" field is not used by Meson itself and @@ -89,6 +92,13 @@ TRIPLET." (ld . ,(string-append triplet "-ld")) (strip . ,(string-append triplet "-strip")))) +(define (make-built-in-options-alist triplet) + (if (target-avr? triplet) + `((b_pie . #f) + (b_staticpic . #f) + (default_library . "static")) + '())) + (define (make-cross-file triplet) (computed-file "cross-file" (with-imported-modules '((guix build meson-configuration)) @@ -99,7 +109,9 @@ TRIPLET." (write-section-header port "host_machine") (write-assignments port '#$(make-machine-alist triplet)) (write-section-header port "binaries") - (write-assignments port '#$(make-binaries-alist triplet)))))))) + (write-assignments port '#$(make-binaries-alist triplet)) + (write-section-header port "built-in options") + (write-assignments port '#$(make-built-in-options-alist triplet)))))))) (define %meson-build-system-modules ;; Build-side modules imported by default. @@ -182,6 +194,7 @@ TRIPLET." (imported-modules %meson-build-system-modules) (modules '((guix build meson-build-system) (guix build utils))) + (substitutable? #t) allowed-references disallowed-references) "Build SOURCE using MESON, and with INPUTS, assuming that SOURCE @@ -266,6 +279,7 @@ has a 'meson.build' file." (imported-modules %meson-build-system-modules) (modules '((guix build meson-build-system) (guix build utils))) + (substitutable? #t) allowed-references disallowed-references) "Cross-build SOURCE for TARGET using MESON, and with INPUTS, assuming that diff --git a/guix/build-system/mix.scm b/guix/build-system/mix.scm new file mode 100644 index 0000000000..1b04053d70 --- /dev/null +++ b/guix/build-system/mix.scm @@ -0,0 +1,186 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2023 Pierre-Henry Fröhring <contact@phfrohring.com> +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. + +;; Commentary: +;; +;; Standard build procedure for Elixir packages using 'mix'. This is +;; implemented as an extension of 'gnu-build-system'. +;; +;; Code: + +(define-module (guix build-system mix) + #:use-module (guix build mix-build-system) + #:use-module (guix build-system gnu) + #:use-module (guix build-system) + #:use-module (guix gexp) + #:use-module (guix monads) + #:use-module (guix packages) + #:use-module (guix search-paths) + #:use-module (guix store) + #:use-module (guix utils) + #:use-module (ice-9 match) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) + #:export (mix-build-system hexpm-uri)) + +;; Lazily resolve bindings to avoid circular dependencies. +(define (default-glibc-utf8-locales) + (let* ((base (resolve-interface '(gnu packages base)))) + (module-ref base 'glibc-utf8-locales))) + +(define (default-elixir-hex) + (let ((elixir (resolve-interface '(gnu packages elixir)))) + (module-ref elixir 'elixir-hex))) + +(define (default-rebar3) + (let ((erlang (resolve-interface '(gnu packages erlang)))) + (module-ref erlang 'rebar3))) + +(define (default-elixir) + (let ((elixir (resolve-interface '(gnu packages elixir)))) + (module-ref elixir 'elixir))) + +(define* (strip-prefix name #:optional (prefix "elixir-")) + "Return NAME without the prefix PREFIX." + (if (string-prefix? prefix name) + (string-drop name (string-length prefix)) + name)) + +(define (hexpm-uri name version) + "Return the URI where to fetch the sources of a Hex package NAME at VERSION. +NAME is the name of the package which should look like: elixir-pkg-name-X.Y.Z +See: https://github.com/hexpm/specifications/blob/main/endpoints.md" + ((compose + (cute string-append "https://repo.hex.pm/tarballs/" <> "-" version ".tar") + (cute string-replace-substring <> "-" "_") + strip-prefix) + name)) + +;; A number of environment variables specific to the Mix build system are +;; reflected here. They are documented at +;; https://hexdocs.pm/mix/1.15.7/Mix.html#module-environment-variables. Other +;; parameters located in mix.exs are defined at +;; https://hexdocs.pm/mix/1.15.7/Mix.Project.html#module-configuration +(define* (mix-build name + inputs + #:key + source + (tests? #t) + (mix-path #f) ;See MIX_PATH. + (mix-exs "mix.exs") ;See MIX_EXS. + (build-per-environment #t) ;See :build_per_environment. + (phases '%standard-phases) + (outputs '("out")) + (search-paths '()) + (system (%current-system)) + (guile #f) + (imported-modules `((guix build mix-build-system) + ,@%gnu-build-system-modules)) + (modules '((guix build mix-build-system) + (guix build utils)))) + "Build SOURCE using Elixir, and with INPUTS." + + ;; Check the documentation of :build_per_environment here: + ;; https://hexdocs.pm/mix/1.15.7/Mix.Project.html#module-configuration And + ;; "Environments" here: + ;; https://hexdocs.pm/mix/1.15.7/Mix.html#module-environments + (define mix-environments + (if build-per-environment + `("prod" ,@(if tests? '("test") '())) + '("shared"))) + + (define builder + (with-imported-modules imported-modules + #~(begin + + (use-modules #$@(sexp->gexp modules)) + + #$(with-build-variables inputs outputs + #~(mix-build #:name #$name + #:source #+source + #:system #$system + #:tests? #$tests? + #:mix-path #$mix-path + #:mix-exs #$mix-exs + #:mix-environments '#$mix-environments + #:build-per-environment #$build-per-environment + #:phases #$(if (pair? phases) + (sexp->gexp phases) + phases) + #:outputs %outputs + #:search-paths '#$(sexp->gexp + (map + search-path-specification->sexp + search-paths)) + #:inputs + %build-inputs))))) + + (mlet %store-monad ((guile (package->derivation (or guile (default-guile)) + system + #:graft? #f))) + (gexp->derivation name + builder + #:system system + #:graft? #f ;consistent with 'gnu-build' + #:target #f + #:guile-for-build guile))) + +(define* (lower name + #:key + (elixir (default-elixir)) + (elixir-hex (default-elixir-hex)) + (glibc-utf8-locales (default-glibc-utf8-locales)) + (inputs '()) + (native-inputs '()) + (propagated-inputs '()) + (rebar3 (default-rebar3)) + (tests? #t) + outputs + source + system + target + #:allow-other-keys #:rest arguments) + "Return a bag for NAME." + (let ((private-keywords + '(#:inputs #:native-inputs + #:outputs #:system #:target + #:elixir #:elixir-hex #:glibc-utf8-locales + #:rebar3 #:erlang)) + (build-inputs + `(,@(standard-packages) + ("glibc-utf8-locales" ,glibc-utf8-locales) + ("erlang" ,(lookup-package-input elixir "erlang")) + ("rebar3" ,rebar3) + ("elixir" ,elixir) + ("elixir-hex" ,elixir-hex) + ,@inputs + ,@native-inputs))) + (bag (name name) + (system system) + (build-inputs build-inputs) + (host-inputs (if target inputs '())) + (outputs outputs) + (build mix-build) + (arguments (strip-keyword-arguments private-keywords arguments))))) + +(define mix-build-system + (build-system (name 'mix) + (description "The standard Mix build system") + (lower lower))) + +;;; mix.scm ends here diff --git a/guix/build-system/perl.scm b/guix/build-system/perl.scm index 7c6deb34bf..0d5493ab90 100644 --- a/guix/build-system/perl.scm +++ b/guix/build-system/perl.scm @@ -133,7 +133,9 @@ provides a `Makefile.PL' file as its build system." search-paths)) #:make-maker? #$make-maker? #:make-maker-flags #$make-maker-flags - #:module-build-flags #$(sexp->gexp module-build-flags) + #:module-build-flags #$(if (pair? module-build-flags) + (sexp->gexp module-build-flags) + module-build-flags) #:phases #$(if (pair? phases) (sexp->gexp phases) phases) diff --git a/guix/build-system/r.scm b/guix/build-system/r.scm index 657346bea3..7ab4db82b6 100644 --- a/guix/build-system/r.scm +++ b/guix/build-system/r.scm @@ -60,7 +60,7 @@ release corresponding to NAME and VERSION." "/src/contrib/" name "_" version ".tar.gz") ;; TODO: use %bioconductor-version from (guix import cran) - (string-append "https://bioconductor.org/packages/3.17" + (string-append "https://bioconductor.org/packages/3.18" type-url-part "/src/contrib/" name "_" version ".tar.gz")))) diff --git a/guix/build-system/vim.scm b/guix/build-system/vim.scm new file mode 100644 index 0000000000..dddf7ea14b --- /dev/null +++ b/guix/build-system/vim.scm @@ -0,0 +1,170 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2022 Jonathan Scoresby <me@jonscoresby.com> +;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il> +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. + +(define-module (guix build-system vim) + #:use-module (guix store) + #:use-module (guix utils) + #:use-module (guix gexp) + #:use-module (guix monads) + #:use-module (guix packages) + #:use-module (guix search-paths) + #:use-module (guix build-system) + #:use-module (guix build-system copy) + #:use-module (guix build-system gnu) + #:export (%vim-build-system-modules vim-build vim-build-system)) + +;; Commentary: +;; +;; Standard package installer for vim and neovim plugins. +;; This is implemented as an extension of the `copy-build-system' +;; and takes advantage of vim and neovim's built-in package manager. +;; It extends the installation procedure from the copy-build-system +;; to put files in the correct place and then generates help tags. +;; +;; Code: + +(define %vim-build-system-modules + ;; Build-side modules imported by default. + `((guix build vim-build-system) + ,@%copy-build-system-modules)) + +(define (default-vim) + "Return the default Vim package." + ;; Lazily resolve the binding to avoid a circular dependency. + (let ((vim (resolve-interface '(gnu packages vim)))) + (module-ref vim 'vim))) + +(define (default-neovim) + "Return the default Neovim package." + (let ((vim (resolve-interface '(gnu packages vim)))) + (module-ref vim 'neovim))) + +(define* (lower name + #:key source + inputs + native-inputs + outputs + system + target + (vim? #f) + (neovim? #f) + (plugin-name name) + (vim (default-vim)) + (neovim (default-neovim)) + #:allow-other-keys #:rest arguments) + "Return a bag for NAME." + (let* ((private-keywords '(#:target #:vim #:neovim #:inputs #:native-inputs)) + (vim? (or (string-prefix? "vim-" name) + vim?)) + (neovim? (or (string-prefix? "neovim-" name) + neovim?)) + (vim-inputs (append (if vim? + `(("vim" ,vim)) + '()) + (if neovim? + `(("neovim" ,neovim)) + '()))) + (vim-arguments (append arguments + `(#:vim? ,vim? + #:neovim? ,neovim?)))) + (bag (name name) + (system system) + (host-inputs `(,@(if source + `(("source" ,source)) + '()) ,@inputs + + ;; Keep the standard inputs of 'gnu-build-system'. + ,@(standard-packages))) + (build-inputs `(,@vim-inputs ,@native-inputs)) + (outputs outputs) + (build vim-build) + (arguments (strip-keyword-arguments private-keywords vim-arguments))))) + +(define* (vim-build name inputs + #:key guile + source + (vim? #f) + (neovim? #f) + (mode "start") + (plugin-name name) + (install-plan ''()) + (phases '(@ (guix build vim-build-system) %standard-phases)) + (outputs '("out")) + (out-of-source? #t) + (tests? #t) + (validate-runpath? #t) + (patch-shebangs? #t) + (strip-binaries? #t) + (strip-flags %strip-flags) + (strip-directories %strip-directories) + (search-paths '()) + (system (%current-system)) + (substitutable? #t) + (imported-modules %vim-build-system-modules) + (modules '((guix build vim-build-system) + (guix build utils)))) + + (define build + (with-imported-modules imported-modules + #~(begin + (use-modules #$@modules) + #$(with-build-variables inputs outputs + #~(vim-build #:name #$name + #:vim? #$vim? + #:neovim? #$neovim? + #:mode #$mode + #:plugin-name #$plugin-name + #:install-plan #$(if (pair? install-plan) + (sexp->gexp install-plan) + install-plan) + #:source #+source + #:system #$system + #:phases #$(if (pair? phases) + (sexp->gexp phases) + phases) + #:outputs %outputs + #:search-paths '#$(sexp->gexp + (map search-path-specification->sexp + search-paths)) + #:inputs %build-inputs + #:out-of-source? #$out-of-source? + #:tests? #$tests? + #:validate-runpath? #$validate-runpath? + #:patch-shebangs? #$patch-shebangs? + #:strip-binaries? #$strip-binaries? + #:strip-flags #$strip-flags + #:strip-directories #$strip-directories))))) + + (mlet %store-monad + ((guile (package->derivation (or guile (default-guile)) + system #:graft? #f))) + (gexp->derivation name + build + #:system system + #:target #f + #:graft? #f + #:substitutable? substitutable? + #:guile-for-build guile))) + +(define vim-build-system + (build-system (name 'vim) + (description "The standard Vim build system") + (lower lower))) + +;;; vim.scm ends here diff --git a/guix/build-system/zig.scm b/guix/build-system/zig.scm index 16b8a712cc..1fa4782a2e 100644 --- a/guix/build-system/zig.scm +++ b/guix/build-system/zig.scm @@ -39,7 +39,6 @@ (define %zig-build-system-modules ;; Build-side modules imported by default. `((guix build zig-build-system) - (guix build syscalls) ,@%gnu-build-system-modules)) (define* (zig-build name inputs @@ -84,6 +83,79 @@ #:system system #:guile-for-build guile))) +(define* (zig-cross-build name + #:key + source target + build-inputs target-inputs host-inputs + (phases '%standard-phases) + (outputs '("out")) + (search-paths '()) + (native-search-paths '()) + (tests? #t) + (test-target #f) + (zig-build-flags ''()) + (zig-test-flags ''()) + (zig-destdir "out") + (zig-test-destdir "test-out") + (zig-release-type #f) + (system (%current-system)) + (guile #f) + (imported-modules %zig-build-system-modules) + (modules '((guix build zig-build-system) + (guix build utils)))) + "Build SOURCE using Zig, and with INPUTS." + (define builder + (with-imported-modules imported-modules + #~(begin + (use-modules #$@(sexp->gexp modules)) + + (define %build-host-inputs + #+(input-tuples->gexp build-inputs)) + + (define %build-target-inputs + (append #$(input-tuples->gexp host-inputs) + #+(input-tuples->gexp target-inputs))) + + (define %build-inputs + (append %build-host-inputs %build-target-inputs)) + + (define %outputs + #$(outputs->gexp outputs)) + + (zig-build #:name #$name + #:source #+source + #:system #$system + #:phases #$phases + #:outputs %outputs + #:target #$target + #:test-target #$test-target + #:inputs %build-target-inputs + #:native-inputs %build-host-inputs + #:search-paths '#$(map search-path-specification->sexp + search-paths) + #:native-search-paths '#$(map + search-path-specification->sexp + native-search-paths) + #:zig-build-flags #$zig-build-flags + #:zig-test-flags #$zig-test-flags + #:zig-release-type #$zig-release-type + #:zig-destdir #$zig-destdir + #:zig-test-destdir #$zig-test-destdir + #:tests? #$tests? + #:search-paths '#$(sexp->gexp + (map search-path-specification->sexp + search-paths)))))) + + (mlet %store-monad ((guile (package->derivation (or guile (default-guile)) + system #:graft? #f))) + (gexp->derivation name builder + #:system system + #:target target + #:graft? #f + #:substitutable? substitutable? + #:guile-for-build guile))) + + (define* (lower name #:key source inputs native-inputs outputs system target (zig (default-zig)) @@ -94,27 +166,30 @@ (define private-keywords '(#:target #:zig #:inputs #:native-inputs #:outputs)) - ;; TODO: support cross-compilation - ;; It's as simple as adding some build flags to `zig-build-flags` - ;; -Dtarget=aarch64-linux-musl, for example. - (and (not target) - (bag - (name name) - (system system) - (target target) - (host-inputs `(,@(if source - `(("source" ,source)) - '()) - ,@inputs - - ;; Keep the standard inputs of 'gnu-build-system' - ;; TODO: do we need this? - ,@(standard-packages))) - (build-inputs `(("zig" ,zig) - ,@native-inputs)) - (outputs outputs) - (build zig-build) - (arguments (strip-keyword-arguments private-keywords arguments))))) + (bag + (name name) + (system system) + (target target) + (build-inputs `(,@(if source + `(("source" ,source)) + '()) + ,@`(("zig" ,zig)) + ,@native-inputs + ,@(if target '() inputs) + ,@(if target + ;; Use the standard cross inputs of + ;; 'gnu-build-system'. + (standard-cross-packages target 'host) + '()) + ;; Keep the standard inputs of 'gnu-build-system'. + ,@(standard-packages))) + (host-inputs (if target inputs '())) + (target-inputs (if target + (standard-cross-packages target 'target) + '())) + (outputs outputs) + (build (if target zig-cross-build zig-build)) + (arguments (strip-keyword-arguments private-keywords arguments)))) (define zig-build-system (build-system diff --git a/guix/build/ant-build-system.scm b/guix/build/ant-build-system.scm index d29912bf59..ced34177f4 100644 --- a/guix/build/ant-build-system.scm +++ b/guix/build/ant-build-system.scm @@ -37,6 +37,7 @@ (define* (default-build.xml jar-name prefix #:optional (source-dir ".") (test-dir "./test") (main-class #f) + (use-java-modules? #f) (test-include '("**/*Test.java")) (test-exclude '("**/Abstract*Test.java"))) "Create a simple build.xml with standard targets for Ant." @@ -65,7 +66,7 @@ (value "first"))) (property (@ (environment "env"))) (path (@ (id "classpath")) - (pathelement (@ (location "${env.CLASSPATH}")))) + (pathelement (@ (path "${env.CLASSPATH}")))) (target (@ (name "manifest")) (mkdir (@ (dir "${manifest.dir}"))) @@ -79,18 +80,30 @@ (mkdir (@ (dir "${classes.dir}"))) (javac (@ (includeantruntime "false") (srcdir ,source-dir) - (destdir "${classes.dir}") - (classpath (@ (refid "classpath")))))) + (destdir "${classes.dir}")) + ,(if use-java-modules? + `((modulepath (@ (refid "classpath")))) + '()) + (classpath (@ (refid "classpath"))))) (target (@ (name "compile-tests")) (mkdir (@ (dir "${test.classes.dir}"))) (javac (@ (includeantruntime "false") (srcdir ,test-dir) (destdir "${test.classes.dir}")) - (classpath - (pathelement (@ (path "${env.CLASSPATH}"))) - (pathelement (@ (location "${classes.dir}"))) - (pathelement (@ (location "${test.classes.dir}")))))) + ,(if use-java-modules? + `((classpath + (pathelement + (@ (path "${env.CLASSPATH}"))) + (pathelement + (@ (location "${classes.dir}"))) + (pathelement + (@ (location "${test.classes.dir}"))))) + '()) + (classpath + (pathelement (@ (path "${env.CLASSPATH}"))) + (pathelement (@ (location "${classes.dir}"))) + (pathelement (@ (location "${test.classes.dir}")))))) (target (@ (name "check") (depends "compile-tests")) @@ -156,13 +169,15 @@ to the default GNU unpack strategy." (source-dir "src") (test-dir "src/test") (main-class #f) + (use-java-modules? #f) (test-include '("**/*Test.java")) (test-exclude '("**/Abstract*.java")) #:allow-other-keys) (when jar-name (default-build.xml jar-name (string-append (assoc-ref outputs "out") "/share/java") - source-dir test-dir main-class test-include test-exclude)) + source-dir test-dir main-class use-java-modules? + test-include test-exclude)) (setenv "JAVA_HOME" (assoc-ref inputs "jdk")) (setenv "CLASSPATH" (generate-classpath inputs)) #t) diff --git a/guix/build/cargo-build-system.scm b/guix/build/cargo-build-system.scm index 505c0b4b01..ffb2ec898e 100644 --- a/guix/build/cargo-build-system.scm +++ b/guix/build/cargo-build-system.scm @@ -119,6 +119,7 @@ libraries or executables." (error "Possible pre-generated files found:" pregenerated-files)))) (define* (configure #:key inputs + target (vendor-dir "guix-vendor") #:allow-other-keys) "Vendor Cargo.toml dependencies as guix inputs." @@ -146,27 +147,75 @@ libraries or executables." (invoke "tar" "xf" path "-C" crate-dir "--strip-components" "1"))))) inputs) - ;; Configure cargo to actually use this new directory. + ;; For cross-building + (when target + (setenv "CARGO_BUILD_TARGET" + ;; Can this be replaced with platform-rust-architecture? + ;; Keep this synchronized with (guix platforms *) + (match target + ("aarch64-linux-gnu" "aarch64-unknown-linux-gnu") + ("arm-linux-gnueabihf" "armv7-unknown-linux-gnueabihf") + ("i686-linux-gnu" "i686-unknown-linux-gnu") + ("mips64el-linux-gnu" "mips64el-unknown-linux-gnuabi64") + ("powerpc-linux-gnu" "powerpc-unknown-linux-gnu") + ("powerpc64-linux-gnu" "powerpc64-unknown-linux-gnu") + ("powerpc64le-linux-gnu" "powerpc64le-unknown-linux-gnu") + ("riscv64-linux-gnu" "riscv64gc-unknown-linux-gnu") + ("x86_64-linux-gnu" "x86_64-unknown-linux-gnu") + ("i586-pc-gnu" "i686-unknown-hurd-gnu") + ("i686-w64-mingw32" "i686-pc-windows-gnu") + ("x86_64-w64-mingw32" "x86_64-pc-windows-gnu") + (else #f))) + (setenv "RUSTFLAGS" (string-append + (or (getenv "RUSTFLAGS") "") + " --sysroot " (assoc-ref inputs "rust-sysroot"))) + + (setenv "PKG_CONFIG" (string-append target "-pkg-config")) + + ;; We've removed all the bundled libraries, don't look for them. + (setenv "WINAPI_NO_BUNDLED_LIBRARIES" "1") + + ;; Prevent targeting the build machine. + (setenv "CRATE_CC_NO_DEFAULTS" "1")) + + ;; Configure cargo to actually use this new directory with all the crates. (setenv "CARGO_HOME" (string-append (getcwd) "/.cargo")) (mkdir-p ".cargo") + ;; Not .cargo/config.toml, rustc/cargo will generate .cargo/config otherwise. (let ((port (open-file ".cargo/config" "w" #:encoding "utf-8"))) - (display " + ;; Placed here so it doesn't cause random rebuilds. Neither of these work. + ;; sysroot = '" (assoc-ref inputs "rust-sysroot") "' + ;; rustflags = ['--sysroot', '" (assoc-ref inputs "rust-sysroot") "'] + (when target + (display (string-append " +[target." (getenv "CARGO_BUILD_TARGET") "] +linker = '" target "-gcc' + +[build] +target = ['" (getenv "CARGO_BUILD_TARGET") "']") port)) + (display (string-append " [source.crates-io] replace-with = 'vendored-sources' [source.vendored-sources] -directory = '" port) - (display (string-append (getcwd) "/" vendor-dir) port) - (display "' -" port) +directory = '" vendor-dir "'") port) (close-port port)) ;; Lift restriction on any lints: a crate author may have decided to opt ;; into stricter lints (e.g. #![deny(warnings)]) during their own builds ;; but we don't want any build failures that could be caused later by ;; upgrading the compiler for example. - (setenv "RUSTFLAGS" "--cap-lints allow") - (setenv "CC" (string-append (assoc-ref inputs "gcc") "/bin/gcc")) + (setenv "RUSTFLAGS" (string-append (or (getenv "RUSTFLAGS") "") + " --cap-lints allow")) + + (if (assoc-ref inputs "cross-gcc") + (begin + (setenv "HOST_CC" "gcc") + (setenv "TARGET_CC" (string-append target "-gcc")) + (setenv "TARGET_AR" (string-append target "-ar")) + (setenv "TARGET_PKG_CONFIG" (string-append target "-pkg-config"))) + (setenv "CC" (string-append (assoc-ref inputs "gcc") "/bin/gcc"))) + (setenv "LIBGIT2_SYS_USE_PKG_CONFIG" "1") (setenv "LIBSSH2_SYS_USE_PKG_CONFIG" "1") (when (assoc-ref inputs "openssl") @@ -264,7 +313,11 @@ directory = '" port) (unless (eq? (stat:type s) 'symlink) (utime file 0 0 0 0)))) (find-files dir #:directories? #t)) + (apply invoke "tar" "czf" (string-append dir ".crate") + ;; avoid non-determinism in the archive + "--sort=name" "--mtime=@0" + "--owner=root:0" "--group=root:0" (find-files dir #:directories? #t)) (delete-file-recursively dir))) (find-files "." "\\.crate$"))))) diff --git a/guix/build/composer-build-system.scm b/guix/build/composer-build-system.scm new file mode 100644 index 0000000000..8896384e0a --- /dev/null +++ b/guix/build/composer-build-system.scm @@ -0,0 +1,301 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu> +;;; Copyright © 2023 Nicolas Graves <ngraves@ngraves.fr> +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. + +(define-module (guix build composer-build-system) + #:use-module ((guix build gnu-build-system) #:prefix gnu:) + #:use-module (guix build utils) + #:use-module (ice-9 match) + #:use-module (json) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) + #:export (%standard-phases + composer-build)) + +;; Commentary: +;; +;; Builder-side code of the standard composer build procedure. +;; +;; Code: + +(define (json->require dict) + (if dict + (let loop ((result '()) (require dict)) + (match require + (() result) + ((((? (cut string-contains <> "/") name) . _) + require ...) + (loop (cons name result) require)) + ((_ require ...) (loop result require)) + (_ result))) + '())) + +(define (if-specified-to-list fn) + (match-lambda + ((? unspecified?) '()) + (arg (fn arg)) + (_ '()))) + +(define-json-mapping <composer-autoload> make-composer-autoload + composer-autoload? + json->composer-autoload + (psr-4 composer-autoload-psr-4 "psr-4" + (match-lambda + ((? unspecified?) '()) + ((? (lambda (al) + (and (list? al) (pair? (car al)) (vector? (cdar al)))) al) + (append-map + (lambda (vect-el) + (list (cons (caar al) vect-el))) + (vector->list (cdar al)))) + ((? list? l) l) + (_ '()))) + (psr-0 composer-autoload-psr-0 "psr-0" (if-specified-to-list identity)) + (classmap composer-autoload-classmap "classmap" + (if-specified-to-list vector->list)) + (files composer-autoload-files "files" + (if-specified-to-list vector->list))) + +(define-json-mapping <composer-package> make-composer-package composer-package? + json->composer-package + (name composer-package-name) + (autoload composer-package-autoload "autoload" + (if-specified-to-list json->composer-autoload)) + (autoload-dev composer-package-autoload-dev "autoload-dev" + (if-specified-to-list json->composer-autoload)) + (require composer-package-require "require" json->require) + (dev-require composer-package-dev-require "require-dev" json->require) + (scripts composer-package-scripts "scripts" + (if-specified-to-list identity)) + (binaries composer-package-binaries "bin" + (if-specified-to-list vector->list))) + +(define* (read-package-data #:key (filename "composer.json")) + (call-with-input-file filename + (lambda (port) + (json->composer-package (json->scm port))))) + +(define* (create-test-autoload #:key composer-file inputs outputs tests? + #:allow-other-keys) + "Create the autoload.php file for tests. This is a standalone phase so that +the autoload.php file can be edited before the check phase." + (when tests? + (mkdir-p "vendor") + (create-autoload (string-append (getcwd) "/vendor") composer-file + inputs #:dev-dependencies? #t))) + +(define (find-bin script inputs) + (search-input-file inputs + (string-append + "bin/" + (string-drop script (string-length "vendor/bin/"))))) + +(define* (check #:key composer-file inputs + tests? test-target test-flags #:allow-other-keys) + "Test the given package. +Please note that none of the PHP packages at the time of the rewrite of the +build-system did use the test-script field. This means that the @code{match +test-script} part is not tested on a real example and relies on the original +implementation." + (if tests? + (let* ((package-data (read-package-data #:filename composer-file)) + (scripts (composer-package-scripts package-data)) + (test-script (assoc-ref scripts test-target))) + (match test-script + ((? string? bin) + (let ((command (find-bin bin inputs))) + (unless (zero? (apply system command test-flags)) + (throw 'failed-command command)))) + (('@ (? string? bins) ...) + (for-each + (lambda (c) + (let ((command (find-bin c inputs))) + (unless (zero? (apply system command test-flags)) + (throw 'failed-command command)))) + bins)) + (_ (if (file-exists? "phpunit.xml.dist") + (apply invoke + (with-exception-handler + (lambda (exn) + (if (search-error? exn) + (error "\ +Missing php-phpunit-phpunit native input.~%") + (raise exn))) + (lambda () + (search-input-file (or inputs '()) "bin/phpunit"))) + test-flags)) + (format #t "No test suite found.~%")))) + (format #t "Test suite not run.~%"))) + +(define* (create-autoload vendor composer-file inputs #:key dev-dependencies?) + "creates an autoload.php file that sets up the class locations for this package, +so it can be autoloaded by PHP when the package classes are required." + (with-output-to-file (string-append vendor "/autoload.php") + (lambda _ + (display (string-append + "<?php +// autoload.php @generated by Guix +$psr4map = $classmap = array(); +require_once '" vendor "/autoload_conf.php'; +require_once '" (assoc-ref inputs "composer-classloader") "/share/web/composer/ClassLoader.php'; +$loader = new \\Composer\\Autoload\\ClassLoader(); +foreach ($psr4map as $namespace => $paths) { + foreach ($paths as $path) { + $loader->addPsr4($namespace, $path); + } +} +$loader->addClassMap($classmap); +$loader->register(); +")))) + ;; Now, create autoload_conf.php that contains the actual data, as a set + ;; of arrays + (let* ((package-data (read-package-data #:filename composer-file)) + (autoload (composer-package-autoload package-data)) + (autoload-dev (composer-package-autoload-dev package-data)) + (dependencies (composer-package-require package-data)) + (dependencies-dev (composer-package-dev-require package-data))) + (with-output-to-file (string-append vendor "/autoload_conf.php") + (lambda _ + (format #t "<?php~%") + (format #t "// autoload_conf.php @generated by Guix~%") + (force-output) + (for-each + (match-lambda + ((key . value) + (let ((vals (if (list? value) + (reverse value) + (list value)))) + (apply + format + #t + (string-append + "$psr4map['~a'][] = [" + (string-join + (make-list (length vals) "'~a/../~a'") ",") + "];~%") + (cons* (string-join (string-split key #\\) "\\\\") + (append-map (lambda (v) (list vendor v)) vals))))) + (_ (format #t ""))) + (delete-duplicates + (append + (composer-autoload-psr-4 autoload) + (if (and dev-dependencies? (not (null? autoload-dev))) + (composer-autoload-psr-4 autoload-dev) + '())) + '())) + (for-each + (lambda (psr0) + (match psr0 + ((key . value) + (format #t "$psr4map['~a'][] = ['~a/../~a/~a'];~%" + (string-join (string-split key #\\) "\\\\") + vendor + value + (string-join (string-split key #\\) "/"))) + (_ (format #t "")))) + (append + (composer-autoload-psr-0 autoload) + (if (and dev-dependencies? (not (null? autoload-dev))) + (composer-autoload-psr-0 autoload-dev) + '()))) + (for-each + (lambda (classmap) + (for-each + (lambda (file) + (invoke "php" (assoc-ref inputs "findclass.php") + "-i" (string-append vendor "/..") "-f" file)) + (find-files classmap ".(php|hh|inc)$"))) + (append + (composer-autoload-classmap autoload) + (if (and dev-dependencies? (not (null? autoload-dev))) + (composer-autoload-classmap autoload-dev) + '()))) + (for-each + (lambda (file) + (format #t "require_once '~a/../~a';~%" vendor file)) + (append + (composer-autoload-files autoload) + (if (and dev-dependencies? (not (null? autoload-dev))) + (composer-autoload-files autoload-dev) + '()))) + (for-each + (lambda (dep) + (format + #t "require_once '~a';~%" + (search-input-file + inputs + (string-append "/share/web/" dep "/vendor/autoload_conf.php")))) + dependencies) + ;; Also add native-inputs that are not necessarily given in the + ;; composer.json. This allows to simply add a package in tests by + ;; adding it in native-inputs, without the need to patch composer.json. + (for-each + (match-lambda + ((name . loc) + (match (find-files loc "autoload_conf\\.php$") + (() #t) + (((? string? conf) . ()) + (format #t "require_once '~a';~%" conf)) + (_ #t))) + (_ #t)) + (or inputs '())))))) + +(define* (install #:key inputs outputs composer-file #:allow-other-keys) + "Install the given package." + (let* ((out (assoc-ref outputs "out")) + (package-data (read-package-data #:filename composer-file)) + (name (composer-package-name package-data)) + (php-dir (string-append out "/share/web/" name)) + (bin-dir (string-append php-dir "/vendor/bin")) + (bin (string-append out "/bin")) + (binaries (composer-package-binaries package-data))) + (mkdir-p php-dir) + (copy-recursively "." php-dir) + (mkdir-p (string-append php-dir "/vendor")) + (when binaries + (mkdir-p bin-dir) + (mkdir-p bin) + (for-each + (lambda (file) + (let ((installed-file (string-append bin-dir "/" (basename file))) + (bin-file (string-append bin "/" (basename file))) + (original-file (string-append php-dir "/" file))) + (symlink original-file installed-file) + (symlink original-file bin-file))) + binaries)) + (create-autoload (string-append php-dir "/vendor") + composer-file inputs))) + +(define %standard-phases + ;; Everything is as with the GNU Build System except for the `configure' + ;; , `build', `check' and `install' phases. + (modify-phases gnu:%standard-phases + (delete 'bootstrap) + (delete 'configure) + (delete 'build) + (delete 'check) + (replace 'install install) + (add-after 'install 'check check) + (add-after 'install 'create-test-autoload create-test-autoload))) + +(define* (composer-build #:key inputs (phases %standard-phases) + #:allow-other-keys #:rest args) + "Build the given package, applying all of PHASES in order." + (apply gnu:gnu-build #:inputs inputs #:phases phases args)) + +;;; composer-build-system.scm ends here diff --git a/guix/build/git.scm b/guix/build/git.scm index 0ff263c81b..867cade2c4 100644 --- a/guix/build/git.scm +++ b/guix/build/git.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2014, 2016, 2019, 2023 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com> ;;; ;;; This file is part of GNU Guix. ;;; @@ -33,10 +34,13 @@ ;;; Code: (define* (git-fetch url commit directory - #:key (git-command "git") recursive?) + #:key (git-command "git") + lfs? recursive?) "Fetch COMMIT from URL into DIRECTORY. COMMIT must be a valid Git commit -identifier. When RECURSIVE? is true, all the sub-modules of URL are fetched, -recursively. Return #t on success, #f otherwise." +identifier. When LFS? is true, configure Git to also fetch Large File +Storage (LFS) files; it assumes that the @code{git-lfs} extension is available +in the environment. When RECURSIVE? is true, all the sub-modules of URL are +fetched, recursively. Return #t on success, #f otherwise." ;; Disable TLS certificate verification. The hash of the checkout is known ;; in advance anyway. @@ -57,6 +61,11 @@ recursively. Return #t on success, #f otherwise." (with-directory-excursion directory (invoke git-command "init" "--initial-branch=main") (invoke git-command "remote" "add" "origin" url) + + (when lfs? + (setenv "HOME" "/tmp") + (invoke git-command "lfs" "install")) + (if (zero? (system* git-command "fetch" "--depth" "1" "origin" commit)) (invoke git-command "checkout" "FETCH_HEAD") (begin @@ -81,11 +90,13 @@ recursively. Return #t on success, #f otherwise." (define* (git-fetch-with-fallback url commit directory - #:key (git-command "git") recursive?) + #:key (git-command "git") + lfs? recursive?) "Like 'git-fetch', fetch COMMIT from URL into DIRECTORY, but fall back to alternative methods when fetching from URL fails: attempt to download a nar, and if that also fails, download from the Software Heritage archive." (or (git-fetch url commit directory + #:lfs? lfs? #:recursive? recursive? #:git-command git-command) (download-nar directory) diff --git a/guix/build/guile-build-system.scm b/guix/build/guile-build-system.scm index 32a431d347..e7e7f2d0be 100644 --- a/guix/build/guile-build-system.scm +++ b/guix/build/guile-build-system.scm @@ -28,6 +28,7 @@ #:use-module (ice-9 format) #:use-module (guix build utils) #:export (target-guile-effective-version + target-guile-scm+go %standard-phases guile-build)) @@ -44,7 +45,17 @@ Return #false if it cannot be determined." (string? line) line))) -(define (file-sans-extension file) ;TODO: factorize +(define* (target-guile-scm+go output #:optional guile) + "Return paths under `output' for scm and go files for effective version of +GUILE or whichever `guile' is in $PATH. Raises an error if they cannot be +determined." + (let* ((version (or (target-guile-effective-version guile) + (error "Cannot determine the effective target guile version."))) + (scm (string-append output "/share/guile/site/" version)) + (go (string-append output "/lib/guile/" version "/site-ccache"))) + (values scm go))) + +(define (file-sans-extension file) ;TODO: factorize "Return the substring of FILE without its extension, if any." (let ((dot (string-rindex file #\.))) (if dot diff --git a/guix/build/minetest-build-system.scm b/guix/build/minetest-build-system.scm index 4a7a87ab83..3bf083e004 100644 --- a/guix/build/minetest-build-system.scm +++ b/guix/build/minetest-build-system.scm @@ -126,7 +126,8 @@ If it is unknown, make an educated guess." (/ total-old-size (expt 1024 2)) (/ total-new-size (expt 1024 2))))))) -(define name-regexp (make-regexp "^name[ ]*=(.+)$")) +(define name-regexp + (make-regexp "^name[[:space:]]*=[[:space:]]*([[:graph:]]+)[[:space:]]*$")) (define* (read-mod-name mod.conf #:optional not-found) "Read the name of a mod from MOD.CONF. If MOD.CONF diff --git a/guix/build/mix-build-system.scm b/guix/build/mix-build-system.scm new file mode 100644 index 0000000000..fe2e36d184 --- /dev/null +++ b/guix/build/mix-build-system.scm @@ -0,0 +1,161 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2023 Pierre-Henry Fröhring <contact@phfrohring.com> +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. + +;; Commentary: +;; +;; Code: + +(define-module (guix build mix-build-system) + #:use-module ((guix build gnu-build-system) #:prefix gnu:) + #:use-module (guix build utils) + #:use-module (ice-9 ftw) + #:use-module (ice-9 match) + #:use-module (ice-9 regex) + #:use-module (ice-9 string-fun) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) + #:use-module (srfi srfi-71) + #:export (mix-build + %standard-phases)) + +;; The Elixir version is constant as soon as it is computable from the current +;; execution. It is a X.Y string where X and Y are respectively the major and +;; minor version number of the Elixir used in the build. +(define %elixir-version (make-parameter "X.Y")) + +(define* (elixir-libdir path #:optional (version (%elixir-version))) + "Return the path where all libraries under PATH for a specified Elixir +VERSION are installed." + (string-append path "/lib/elixir/" version)) + +(define* (strip-prefix name #:optional (prefix "elixir-")) + "Return NAME without the prefix PREFIX." + (if (string-prefix? prefix name) + (string-drop name (string-length prefix)) + name)) + +(define (mix-build-dir mix-build-root mix-env) + "Return the directory where build artifacts are to be installed according to +en environment MIX-ENV in the current directory. MIX-BUILD-ROOT depends on the +package arguments. See: https://hexdocs.pm/mix/1.15/Mix.html#module-environment-variables" + (string-append mix-build-root "/" mix-env "/lib")) + +(define (elixir-version inputs) + "Return an X.Y string where X and Y are respectively the major and minor version number of PACKAGE. +Example: /gnu/store/…-elixir-1.14.0 → 1.14" + ((compose + (cute string-join <> ".") + (cute take <> 2) + (cute string-split <> #\.) + strip-prefix + strip-store-file-name) + (assoc-ref inputs "elixir"))) + +(define* (unpack #:key source mix-path #:allow-other-keys) + "Unpack SOURCE in the working directory, and change directory within the +source. When SOURCE is a directory, copy it in a sub-directory of the current +working directory." + (let ((gnu-unpack (assoc-ref gnu:%standard-phases 'unpack))) + (gnu-unpack #:source source) + (when (file-exists? "contents.tar.gz") + (invoke "tar" "xvf" "contents.tar.gz")))) + +(define (list-directories dir) + "List absolute paths of directories directly under the directory DIR." + (map (cute string-append dir "/" <>) + (scandir dir (lambda (filename) + (and (not (member filename '("." ".."))) + (directory-exists? (string-append dir "/" filename))))))) + +(define* (set-mix-env #:key inputs mix-path mix-exs #:allow-other-keys) + "Set environment variables. +See: https://hexdocs.pm/mix/1.15.7/Mix.html#module-environment-variables" + (setenv "MIX_ARCHIVES" "archives") + (setenv "MIX_BUILD_ROOT" "_build") + (setenv "MIX_DEPS_PATH" "deps") + (setenv "MIX_EXS" mix-exs) + (setenv "MIX_HOME" (getcwd)) + (setenv "MIX_PATH" (or mix-path "")) + (setenv "MIX_REBAR3" (string-append (assoc-ref inputs "rebar3") "/bin/rebar3"))) + +(define* (set-elixir-version #:key inputs #:allow-other-keys) + "Store the version number of the Elixir input in a parameter." + (%elixir-version (elixir-version inputs)) + (format #t "Elixir version: ~a~%" (%elixir-version))) + +(define* (build #:key mix-environments #:allow-other-keys) + "Builds the Mix project." + (for-each (lambda (mix-env) + (setenv "MIX_ENV" mix-env) + (invoke "mix" "compile" "--no-deps-check")) + mix-environments)) + +(define* (check #:key (tests? #t) #:allow-other-keys) + "Test the Mix project." + (if tests? + (invoke "mix" "test" "--no-deps-check") + (format #t "tests? = ~a~%" tests?))) + +(define* (remove-mix-dirs . _) + "Remove all .mix/ directories. +We do not want to copy them to the installation directory." + (for-each delete-file-recursively + (find-files "." (file-name-predicate "\\.mix$") #:directories? #t))) + +(define (package-name->elixir-name name+ver) + "Convert the Guix package NAME-VER to the corresponding Elixir name-version +format. Example: elixir-a-pkg-1.2.3 -> a_pkg" + ((compose + (cute string-join <> "_") + (cute drop-right <> 1) + (cute string-split <> #\-)) + (strip-prefix name+ver))) + +(define* (install #:key + inputs + outputs + name + build-per-environment + #:allow-other-keys) + "Install build artifacts in the store." + (let* ((lib-name (package-name->elixir-name name)) + (lib-dir (string-append (elixir-libdir (assoc-ref outputs "out")) "/" lib-name)) + (root (getenv "MIX_BUILD_ROOT")) + (env (if build-per-environment "prod" "shared"))) + (mkdir-p lib-dir) + (copy-recursively (string-append (mix-build-dir root env) "/" lib-name) lib-dir + #:follow-symlinks? #t))) + +(define %standard-phases + (modify-phases gnu:%standard-phases + (delete 'bootstrap) + (delete 'configure) + (add-after 'install-locale 'set-mix-env set-mix-env) + (add-after 'set-mix-env 'set-elixir-version set-elixir-version) + (replace 'unpack unpack) + (replace 'build build) + (replace 'check check) + (add-before 'install 'remove-mix-dirs remove-mix-dirs) + (replace 'install install))) + +(define* (mix-build #:key inputs (phases %standard-phases) + #:allow-other-keys #:rest args) + "Build the given Mix package, applying all of PHASES in order." + (apply gnu:gnu-build #:inputs inputs #:phases phases args)) + +;;; mix-build-system.scm ends here diff --git a/guix/build/syscalls.scm b/guix/build/syscalls.scm index b845b8aab9..b2871c3c10 100644 --- a/guix/build/syscalls.scm +++ b/guix/build/syscalls.scm @@ -192,6 +192,7 @@ terminal-window-size terminal-columns terminal-rows + terminal-string-width openpty login-tty @@ -1097,6 +1098,7 @@ Turning finalization off shuts down the finalization thread as a side effect." ("armv7l" 120) ("aarch64" 220) ("ppc64le" 120) + ("riscv64" 220) (_ #f)))) (lambda (flags) "Create a new child process by duplicating the current parent process. @@ -2336,6 +2338,26 @@ PORT, trying to guess a reasonable value if all else fails. The result is always a positive integer." (terminal-dimension window-size-rows port (const 25))) +(define terminal-string-width + (let ((mbstowcs (and=> (false-if-exception + (dynamic-func "mbstowcs" (dynamic-link))) + (cute pointer->procedure int <> (list '* '* size_t)))) + (wcswidth (and=> (false-if-exception + (dynamic-func "wcswidth" (dynamic-link))) + (cute pointer->procedure int <> (list '* size_t))))) + (if (and mbstowcs wcswidth) + (lambda (str) + "Return the width of a string as it would be printed on the terminal. +This procedure accounts for characters that have a different width than 1, such +as CJK double-width characters." + (let ((wchar (make-bytevector (* (+ (string-length str) 1) 4)))) + (mbstowcs (bytevector->pointer wchar) + (string->pointer str) + (string-length str)) + (wcswidth (bytevector->pointer wchar) + (string-length str)))) + string-length))) ;using a statically-linked Guile + (define openpty (let ((proc (syscall->procedure int "openpty" '(* * * * *) #:library "libutil"))) diff --git a/guix/build/vim-build-system.scm b/guix/build/vim-build-system.scm new file mode 100644 index 0000000000..e11965cc27 --- /dev/null +++ b/guix/build/vim-build-system.scm @@ -0,0 +1,119 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2022 Jonathan Scoresby <me@jonscoresby.com> +;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il> +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. + +(define-module (guix build vim-build-system) + #:use-module ((guix build copy-build-system) + #:prefix copy:) + #:use-module (guix build utils) + #:use-module (ice-9 match) + #:use-module (ice-9 ftw) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) + #:export (%standard-phases vim-build)) + +;; Commentary: +;; +;; System for installing vim and neovim plugins. It downloads +;; the source and copies the appropriate files to vim and nvim +;; packpaths. It then generates helptags. +;; +;; Code: + +(define copy:install + (assoc-ref copy:%standard-phases 'install)) + +(define vim-path + "/share/vim/vimfiles/pack/guix/") +(define nvim-path + "/share/nvim/site/pack/guix/") + +(define* (install #:key plugin-name + install-plan + neovim? + vim? + mode + outputs + #:allow-other-keys) + + (let* ((include-regexp '(".*\\/.*\\/.*")) + (exclude-regexp '("^scripts/.*" + "tests?/.*" "^t/.*" + "assets/.*" + ".*\\/\\..*")) + (vim-install + (if vim? + `(("." ,(string-append vim-path mode "/" plugin-name "/") + #:include-regexp ,include-regexp + #:exclude-regexp ,exclude-regexp)) + '())) + (neovim-install + (if neovim? + `(("." ,(string-append nvim-path mode "/" plugin-name "/") + #:include-regexp ,include-regexp + #:exclude-regexp ,exclude-regexp)) + '()))) + (copy:install #:outputs outputs + #:install-plan (append vim-install + neovim-install + install-plan)))) + +(define* (generate-helptags #:key plugin-name + neovim? + vim? + mode + outputs + #:allow-other-keys) + + (define (vim-generate-helptags output) + (invoke "vim" "--clean" "-en" "--cmd" + (string-append "helptags " + output vim-path mode "/" plugin-name "/doc") + "--cmd" "q")) + + (define (neovim-generate-helptags output) + (invoke "nvim" "--clean" "--headless" "-en" "--cmd" + (string-append "helptags " + output nvim-path mode "/" plugin-name "/doc") + "--cmd" "q")) + + (when (scandir "./doc") + (let ((out (assoc-ref outputs "out"))) + (when vim? + (vim-generate-helptags out)) + (when neovim? + (neovim-generate-helptags out))))) + +(define %standard-phases + ;; Everything is as with the Copy Build System except for + ;; the addition of the generate-helptags phase and a few + ;; custom actions are added to the install phase + (modify-phases copy:%standard-phases + (replace 'install install) + (add-after 'install 'generate-helptags generate-helptags))) + +(define* (vim-build #:key inputs + (phases %standard-phases) + #:allow-other-keys #:rest args) + "Build the given package, applying all of PHASES in order." + (apply copy:copy-build + #:inputs inputs + #:phases phases + args)) + +;;; vim-build-system.scm ends here diff --git a/guix/build/zig-build-system.scm b/guix/build/zig-build-system.scm index d414ebfb17..8352a73324 100644 --- a/guix/build/zig-build-system.scm +++ b/guix/build/zig-build-system.scm @@ -47,6 +47,7 @@ zig-build-flags zig-release-type ;; "safe", "fast" or "small" empty for a ;; debug build" + target #:allow-other-keys) "Build a given Zig package." @@ -56,6 +57,9 @@ "--prefix-lib-dir" "lib" "--prefix-exe-dir" "bin" "--prefix-include-dir" "include" + ,@(if target + (list (string-append "-Dtarget=" target)) + '()) ,@(if zig-release-type (list (string-append "-Drelease-" zig-release-type)) '()) @@ -65,9 +69,10 @@ (define* (check #:key tests? zig-test-flags + target #:allow-other-keys) "Run all the tests" - (when tests? + (when (and tests? (not target)) (let ((old-destdir (getenv "DESTDIR"))) (setenv "DESTDIR" "test-out") ;; Avoid colisions with the build output (let ((call `("zig" "build" "test" diff --git a/guix/deprecation.scm b/guix/deprecation.scm index 8147a01e24..47e653dfb2 100644 --- a/guix/deprecation.scm +++ b/guix/deprecation.scm @@ -103,7 +103,7 @@ This will write a deprecation warning to GUIX-WARNING-PORT." #'(define-deprecated variable alias alias))))) (define-syntax-rule (define-deprecated/public body ...) - "Like 'define/deprecated', but export all the newly introduced bindings." + "Like 'define-deprecated', but export all the newly introduced bindings." (define-deprecated public body ...)) (define-syntax-rule (define-deprecated/alias deprecated replacement) diff --git a/guix/docker.scm b/guix/docker.scm index 5e6460f43f..1c6f59568f 100644 --- a/guix/docker.scm +++ b/guix/docker.scm @@ -3,6 +3,7 @@ ;;; Copyright © 2017, 2018, 2019, 2021 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2018 Chris Marusich <cmmarusich@gmail.com> ;;; Copyright © 2021 Maxim Cournoyer <maxim.cournoyer@gmail.com> +;;; Copyright © 2023 Oleg Pykhalov <go.wigust@gmail.com> ;;; ;;; This file is part of GNU Guix. ;;; @@ -29,16 +30,27 @@ with-directory-excursion invoke)) #:use-module (gnu build install) + #:use-module ((guix build store-copy) + #:select (file-size)) #:use-module (json) ;guile-json #:use-module (srfi srfi-1) #:use-module (srfi srfi-19) #:use-module (srfi srfi-26) + #:use-module (srfi srfi-71) #:use-module ((texinfo string-utils) #:select (escape-special-chars)) #:use-module (rnrs bytevectors) #:use-module (ice-9 ftw) #:use-module (ice-9 match) - #:export (build-docker-image)) + #:export (%docker-image-max-layers + build-docker-image)) + +;; The maximum number of layers allowed in a Docker image is typically around +;; 128, although it may vary depending on the Docker daemon. However, we +;; recommend setting the limit to 100 to ensure sufficient room for future +;; extensions. +(define %docker-image-max-layers + #f) ;; Generate a 256-bit identifier in hexadecimal encoding for the Docker image. (define docker-id @@ -92,12 +104,12 @@ Return a version of TAG that follows these rules." (make-string (- min-length l) padding-character))) (_ normalized-name)))) -(define* (manifest path id #:optional (tag "guix")) +(define* (manifest path layers #:optional (tag "guix")) "Generate a simple image manifest." (let ((tag (canonicalize-repository-name tag))) `#(((Config . "config.json") (RepoTags . #(,(string-append tag ":latest"))) - (Layers . #(,(string-append id "/layer.tar"))))))) + (Layers . ,(list->vector layers)))))) ;; According to the specifications this is required for backwards ;; compatibility. It duplicates information provided by the manifest. @@ -106,8 +118,8 @@ Return a version of TAG that follows these rules." `((,(canonicalize-repository-name tag) . ((latest . ,id))))) ;; See https://github.com/opencontainers/image-spec/blob/master/config.md -(define* (config layer time arch #:key entry-point (environment '())) - "Generate a minimal image configuration for the given LAYER file." +(define* (config layers-diff-ids time arch #:key entry-point (environment '())) + "Generate a minimal image configuration for the given LAYERS files." ;; "architecture" must be values matching "platform.arch" in the ;; runtime-spec at ;; https://github.com/opencontainers/runtime-spec/blob/v1.0.0-rc2/config.md#platform @@ -125,7 +137,7 @@ Return a version of TAG that follows these rules." (container_config . #nil) (os . "linux") (rootfs . ((type . "layers") - (diff_ids . #(,(layer-diff-id layer))))))) + (diff_ids . ,(list->vector layers-diff-ids)))))) (define directive-file ;; Return the file or directory created by a 'evaluate-populate-directive' @@ -136,6 +148,26 @@ Return a version of TAG that follows these rules." (('directory name _ ...) (string-trim name #\/)))) +(define (size-sorted-store-items items max-layers) + "Split list of ITEMS at %MAX-LAYERS and sort by disk usage." + (let* ((items-length (length items)) + (head tail + (split-at + (map (match-lambda ((size . item) item)) + (sort (map (lambda (item) + (cons (file-size item) item)) + items) + (lambda (item1 item2) + (< (match item2 ((size . _) size)) + (match item1 ((size . _) size)))))) + (if (>= items-length max-layers) + (- max-layers 2) + (1- items-length))))) + (list head tail))) + +(define (create-empty-tar file) + (invoke "tar" "-cf" file "--files-from" "/dev/null")) + (define* (build-docker-image image paths prefix #:key (repository "guix") @@ -146,11 +178,13 @@ Return a version of TAG that follows these rules." entry-point (environment '()) compressor - (creation-time (current-time time-utc))) - "Write to IMAGE a Docker image archive containing the given PATHS. PREFIX -must be a store path that is a prefix of any store paths in PATHS. REPOSITORY -is a descriptive name that will show up in \"REPOSITORY\" column of the output -of \"docker images\". + (creation-time (current-time time-utc)) + max-layers + root-system) + "Write to IMAGE a layerer Docker image archive containing the given PATHS. +PREFIX must be a store path that is a prefix of any store paths in PATHS. +REPOSITORY is a descriptive name that will show up in \"REPOSITORY\" column of +the output of \"docker images\". When DATABASE is true, copy it to /var/guix/db in the image and create /var/guix/gcroots and friends. @@ -172,7 +206,14 @@ non-empty directory, then its contents will be recursively added, as well. SYSTEM is a GNU triplet (or prefix thereof) of the system the binaries in PATHS are for; it is used to produce metadata in the image. Use COMPRESSOR, a command such as '(\"gzip\" \"-9n\"), to compress IMAGE. Use CREATION-TIME, a -SRFI-19 time-utc object, as the creation time in metadata." +SRFI-19 time-utc object, as the creation time in metadata. + +When MAX-LAYERS is not false build layered image, providing a Docker +image with store paths splitted in their own layers to improve sharing +between images. + +ROOT-SYSTEM is a directory with a provisioned root file system, which will be +added to image as a layer." (define (sanitize path-fragment) (escape-special-chars ;; GNU tar strips the leading slash off of absolute paths before applying @@ -203,6 +244,59 @@ SRFI-19 time-utc object, as the creation time in metadata." (if (eq? '() transformations) '() `("--transform" ,(transformations->expression transformations)))) + (define (seal-layer) + ;; Add 'layer.tar' to 'image.tar' under the right name. Return its hash. + (let* ((file-hash (layer-diff-id "layer.tar")) + (file-name (string-append file-hash "/layer.tar"))) + (mkdir file-hash) + (rename-file "layer.tar" file-name) + (invoke "tar" "-rf" "image.tar" file-name) + (delete-file file-name) + file-hash)) + (define layers-hashes + ;; Generate a tarball that includes container image layers as tarballs, + ;; along with a manifest.json file describing the layer and config file + ;; locations. + (match-lambda + (((head ...) (tail ...) id) + (create-empty-tar "image.tar") + (let* ((head-layers + (map + (lambda (file) + (invoke "tar" "cf" "layer.tar" file) + (seal-layer)) + head)) + (tail-layer + (begin + (create-empty-tar "layer.tar") + (for-each (lambda (file) + (invoke "tar" "-rf" "layer.tar" file)) + tail) + (let* ((file-hash (layer-diff-id "layer.tar")) + (file-name (string-append file-hash "/layer.tar"))) + (mkdir file-hash) + (rename-file "layer.tar" file-name) + (invoke "tar" "-rf" "image.tar" file-name) + (delete-file file-name) + file-hash))) + (customization-layer + (let* ((file-id (string-append id "/layer.tar")) + (file-hash (layer-diff-id file-id)) + (file-name (string-append file-hash "/layer.tar"))) + (mkdir file-hash) + (rename-file file-id file-name) + (invoke "tar" "-rf" "image.tar" file-name) + file-hash)) + (all-layers + (append head-layers (list tail-layer customization-layer)))) + (with-output-to-file "manifest.json" + (lambda () + (scm->json (manifest prefix + (map (cut string-append <> "/layer.tar") + all-layers) + repository)))) + (invoke "tar" "-rf" "image.tar" "manifest.json") + all-layers)))) (let* ((directory "/tmp/docker-image") ;temporary working directory (id (docker-id prefix)) (time (date->string (time-utc->date creation-time) "~4")) @@ -229,26 +323,39 @@ SRFI-19 time-utc object, as the creation time in metadata." (with-output-to-file "json" (lambda () (scm->json (image-description id time)))) - ;; Create a directory for the non-store files that need to go into the - ;; archive. - (mkdir "extra") + (if root-system + (let ((directory (getcwd))) + (with-directory-excursion root-system + (apply invoke "tar" + "-cf" (string-append directory "/layer.tar") + `(,@transformation-options + ,@(tar-base-options) + ,@(scandir "." + (lambda (file) + (not (member file '("." ".."))))))))) + (begin + ;; Create a directory for the non-store files that need to go + ;; into the archive. + (mkdir "extra") - (with-directory-excursion "extra" - ;; Create non-store files. - (for-each (cut evaluate-populate-directive <> "./") - extra-files) + (with-directory-excursion "extra" + ;; Create non-store files. + (for-each (cut evaluate-populate-directive <> "./") + extra-files) - (when database - ;; Initialize /var/guix, assuming PREFIX points to a profile. - (install-database-and-gc-roots "." database prefix)) + (when database + ;; Initialize /var/guix, assuming PREFIX points to a + ;; profile. + (install-database-and-gc-roots "." database prefix)) - (apply invoke "tar" "-cf" "../layer.tar" - `(,@transformation-options - ,@(tar-base-options) - ,@paths - ,@(scandir "." - (lambda (file) - (not (member file '("." "..")))))))) + (apply invoke "tar" "-cf" "../layer.tar" + `(,@transformation-options + ,@(tar-base-options) + ,@(if max-layers '() paths) + ,@(scandir "." + (lambda (file) + (not (member file '("." "..")))))))) + (delete-file-recursively "extra"))) ;; It is possible for "/" to show up in the archive, especially when ;; applying transformations. For example, the transformation @@ -261,24 +368,37 @@ SRFI-19 time-utc object, as the creation time in metadata." ;; error messages. (with-error-to-port (%make-void-port "w") (lambda () - (system* "tar" "--delete" "/" "-f" "layer.tar"))) - - (delete-file-recursively "extra")) + (system* "tar" "--delete" "/" "-f" "layer.tar")))) (with-output-to-file "config.json" (lambda () - (scm->json (config (string-append id "/layer.tar") - time arch - #:environment environment - #:entry-point entry-point)))) - (with-output-to-file "manifest.json" - (lambda () - (scm->json (manifest prefix id repository)))) - (with-output-to-file "repositories" - (lambda () - (scm->json (repositories prefix id repository))))) - - (apply invoke "tar" "-cf" image "-C" directory - `(,@(tar-base-options #:compressor compressor) - ".")) + (scm->json + (config (if max-layers + (layers-hashes + (append (size-sorted-store-items paths max-layers) + (list id))) + (list (layer-diff-id (string-append id "/layer.tar")))) + time arch + #:environment environment + #:entry-point entry-point)))) + (if max-layers + (begin + (invoke "tar" "-rf" "image.tar" "config.json") + (if compressor + (begin + (apply invoke `(,@compressor "image.tar")) + (copy-file "image.tar.gz" image)) + (copy-file "image.tar" image))) + (begin + (with-output-to-file "manifest.json" + (lambda () + (scm->json (manifest prefix + (list (string-append id "/layer.tar")) + repository)))) + (with-output-to-file "repositories" + (lambda () + (scm->json (repositories prefix id repository)))) + (apply invoke "tar" "-cf" image + `(,@(tar-base-options #:compressor compressor) + "."))))) (delete-file-recursively directory))) diff --git a/guix/download.scm b/guix/download.scm index 31a41e8183..21d02ab203 100644 --- a/guix/download.scm +++ b/guix/download.scm @@ -117,11 +117,9 @@ "http://internode.dl.sourceforge.net/project/" "http://jaist.dl.sourceforge.net/project/" "http://liquidtelecom.dl.sourceforge.net/project/" - ;; "http://nbtelecom.dl.sourceforge.net/project/" ;never returns 404s "http://nchc.dl.sourceforge.net/project/" "http://netcologne.dl.sourceforge.net/project/" "http://netix.dl.sourceforge.net/project/" - "http://pilotfiber.dl.sourceforge.net/project/" "http://tenet.dl.sourceforge.net/project/") (netfilter.org ; https://www.netfilter.org/mirrors.html "http://ftp.netfilter.org/pub/" @@ -129,23 +127,25 @@ "ftp://ftp.hu.netfilter.org/" "ftp://www.lt.netfilter.org/pub/") (kernel.org - "http://linux-kernel.uio.no/pub/" + "https://cdn.kernel.org/pub/" "http://ftp.be.debian.org/pub/" "https://mirrors.edge.kernel.org/pub/" "ftp://ftp.funet.fi/pub/mirrors/ftp.kernel.org/pub/") - (apache ; from http://www.apache.org/mirrors/dist.html - "http://www.eu.apache.org/dist/" - "http://www.us.apache.org/dist/" - "https://ftp.nluug.nl/internet/apache/" + (apache + "https://dlcdn.apache.org/" + "https://downloads.apache.org/" + "https://mirrors.sonic.net/apache/" + "https://apache.osuosl.org/" + "https://mirrors.ircam.fr/pub/apache/" + "https://apache-mirror.rbc.ru/pub/apache/" + "https://mirrors.ibiblio.org/apache/" + + ;; No HTTPS. "http://apache.mirror.iweb.ca/" - "http://mirrors.ircam.fr/pub/apache/" "http://apache.mirrors.ovh.net/ftp.apache.org/dist/" - "http://apache-mirror.rbc.ru/pub/apache/" - "ftp://ftp.osuosl.org/pub/apache/" - "http://mirrors.ibiblio.org/apache/" ;; As a last resort, try the archive. - "http://archive.apache.org/dist/") + "https://archive.apache.org/dist/") (xorg ; from http://www.x.org/wiki/Releases/Download "http://www.x.org/releases/" ; main mirrors "http://mirror.csclub.uwaterloo.ca/x.org/" ; North America @@ -271,7 +271,6 @@ "https://mirror.kumi.systems/kde/ftp/" "https://mirrors.ircam.fr/pub/KDE/" "https://ftp.gwdg.de/pub/linux/kde/" - "https://mirrors.gethosted.online/kde/pub/kde/" "https://fr2.rpmfind.net/linux/KDE/" "https://mirror.faigner.de/kde/ftp/" "https://www.mirrorservice.org/sites/download.kde.org/" @@ -288,7 +287,6 @@ "https://mirrors.nav.ro/kde/" "https://mirrors.xtom.ee/kde/" "https://ftp.funet.fi/pub/mirrors/ftp.kde.org/pub/kde/" - "https://kde.ip-connect.vn.ua/" "https://mirrors.netix.net/kde/" "https://ftp.cc.uoc.gr/mirrors/kde/" ;; North America @@ -307,7 +305,7 @@ "https://mirrors.xtom.jp/kde/" "https://mirrors.xtom.hk/kde/" ;; Africa - "http://mirror.retentionrange.co.bw/kde/" + "https://mirror.dimensiondata.com/mirror/ftp.kde.org/" ;; Oceania "https://mirrors.xtom.au/kde/") (openbsd diff --git a/guix/gexp.scm b/guix/gexp.scm index 0fe4f1c98a..29819878fa 100644 --- a/guix/gexp.scm +++ b/guix/gexp.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2014-2022 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2014-2023 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2018 Clément Lassieur <clement@lassieur.org> ;;; Copyright © 2018 Jan Nieuwenhuizen <janneke@gnu.org> ;;; Copyright © 2019, 2020 Mathieu Othacehe <m.othacehe@gmail.com> @@ -775,6 +775,23 @@ x86_64-linux when COREUTILS is lowered." whether this should be considered a \"native\" input or not." (%gexp-input thing output native?)) +;; Allow <gexp-input>s to be used within gexps. This is useful when willing +;; to force a specific reference to an object, as in (gexp-input hwloc "bin"), +;; which forces a reference to the "bin" output of 'hwloc' instead of leaving +;; it up to the recipient to pick the right output. +(define-gexp-compiler gexp-input-compiler <gexp-input> + compiler => (lambda (obj system target) + (match obj + (($ <gexp-input> thing output native?) + (lower-object thing system + #:target (and (not native?) target))))) + expander => (lambda (obj lowered output/ignored) + (match obj + (($ <gexp-input> thing output native?) + (let ((expand (or (lookup-expander thing) + (lookup-expander lowered)))) + (expand thing lowered output)))))) + ;; Reference to one of the derivation's outputs, for gexps used in ;; derivations. (define-record-type <gexp-output> @@ -917,6 +934,11 @@ When TARGET is true, use it as the cross-compilation target triplet." corresponding <derivation-input> or store item." (define tuple->gexp-input (match-lambda + (((? gexp-input? input)) + ;; This case lets users specify the output of interest more + ;; conveniently, for instance by passing (gexp-input hwloc "lib") to + ;; the 'references-file' procedure. + input) ((thing) (%gexp-input thing "out" (not target))) ((thing output) @@ -1135,10 +1157,9 @@ applicable. When REFERENCES-GRAPHS is true, it must be a list of tuples of one of the following forms: - (FILE-NAME PACKAGE) - (FILE-NAME PACKAGE OUTPUT) - (FILE-NAME DERIVATION) - (FILE-NAME DERIVATION OUTPUT) + (FILE-NAME OBJ) + (FILE-NAME OBJ OUTPUT) + (FILE-NAME GEXP-INPUT) (FILE-NAME STORE-ITEM) The right-hand-side of each element of REFERENCES-GRAPHS is automatically made diff --git a/guix/git-download.scm b/guix/git-download.scm index 5d5d73dc6b..3de6ae970d 100644 --- a/guix/git-download.scm +++ b/guix/git-download.scm @@ -4,6 +4,7 @@ ;;; Copyright © 2017 Christopher Baines <mail@cbaines.net> ;;; Copyright © 2020 Jakub Kądziołka <kuba@kadziolka.net> ;;; Copyright © 2023 Simon Tournier <zimon.toutoune@gmail.com> +;;; Copyright © 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com> ;;; ;;; This file is part of GNU Guix. ;;; @@ -54,6 +55,7 @@ git-reference-recursive? git-fetch + git-fetch/lfs git-version git-file-name git-predicate)) @@ -79,30 +81,36 @@ (let ((distro (resolve-interface '(gnu packages version-control)))) (module-ref distro 'git-minimal))) -(define* (git-fetch/in-band ref hash-algo hash - #:optional name - #:key (system (%current-system)) - (guile (default-guile)) - (git (git-package))) - "Return a fixed-output derivation that performs a Git checkout of REF, using -GIT and GUILE (thus, said derivation depends on GIT and GUILE). +(define (git-lfs-package) + "Return the default 'git-lfs' package." + (let ((distro (resolve-interface '(gnu packages version-control)))) + (module-ref distro 'git-lfs))) -This method is deprecated in favor of the \"builtin:git-download\" builder. -It will be removed when versions of guix-daemon implementing -\"builtin:git-download\" will be sufficiently widespread." +(define* (git-fetch/in-band* ref hash-algo hash + #:optional name + #:key (system (%current-system)) + (guile (default-guile)) + (git (git-package)) + git-lfs) + "Shared implementation code for git-fetch/in-band & friends. Refer to their +respective documentation." (define inputs - `(("git" ,(or git (git-package))) - - ;; When doing 'git clone --recursive', we need sed, grep, etc. to be - ;; available so that 'git submodule' works. + `(,(or git (git-package)) + ,@(if git-lfs + (list git-lfs) + '()) ,@(if (git-reference-recursive? ref) - (standard-packages) + ;; TODO: remove (standard-packages) after + ;; 48e528a26f9c019eeaccf5e3de3126aa02c98d3b is merged into master; + ;; currently when doing 'git clone --recursive', we need sed, grep, + ;; etc. to be available so that 'git submodule' works. + (map second (standard-packages)) ;; The 'swh-download' procedure requires tar and gzip. - `(("gzip" ,(module-ref (resolve-interface '(gnu packages compression)) - 'gzip)) - ("tar" ,(module-ref (resolve-interface '(gnu packages base)) - 'tar)))))) + (list (module-ref (resolve-interface '(gnu packages compression)) + 'gzip) + (module-ref (resolve-interface '(gnu packages base)) + 'tar))))) (define guile-json (module-ref (resolve-interface '(gnu packages guile)) 'guile-json-4)) @@ -126,7 +134,7 @@ It will be removed when versions of guix-daemon implementing (define build (with-imported-modules modules - (with-extensions (list guile-json gnutls ;for (guix swh) + (with-extensions (list guile-json gnutls ;for (guix swh) guile-lzlib) #~(begin (use-modules (guix build git) @@ -134,6 +142,9 @@ It will be removed when versions of guix-daemon implementing #:select (set-path-environment-variable)) (ice-9 match)) + (define lfs? + (call-with-input-string (getenv "git lfs?") read)) + (define recursive? (call-with-input-string (getenv "git recursive?") read)) @@ -144,18 +155,17 @@ It will be removed when versions of guix-daemon implementing #+(file-append glibc-locales "/lib/locale")) (setlocale LC_ALL "en_US.utf8") - ;; The 'git submodule' commands expects Coreutils, sed, - ;; grep, etc. to be in $PATH. - (set-path-environment-variable "PATH" '("bin") - (match '#+inputs - (((names dirs outputs ...) ...) - dirs))) + ;; The 'git submodule' commands expects Coreutils, sed, grep, + ;; etc. to be in $PATH. This also ensures that git extensions are + ;; found. + (set-path-environment-variable "PATH" '("bin") '#+inputs) (setvbuf (current-output-port) 'line) (setvbuf (current-error-port) 'line) (git-fetch-with-fallback (getenv "git url") (getenv "git commit") #$output + #:lfs? lfs? #:recursive? recursive? #:git-command "git"))))) @@ -175,18 +185,49 @@ It will be removed when versions of guix-daemon implementing (git-reference-url ref)))) ("git commit" . ,(git-reference-commit ref)) ("git recursive?" . ,(object->string - (git-reference-recursive? ref)))) + (git-reference-recursive? ref))) + ("git lfs?" . ,(if git-lfs "#t" "#f"))) #:leaked-env-vars '("http_proxy" "https_proxy" "LC_ALL" "LC_MESSAGES" "LANG" "COLUMNS") #:system system - #:local-build? #t ;don't offload repo cloning + #:local-build? #t ;don't offload repo cloning #:hash-algo hash-algo #:hash hash #:recursive? #t #:guile-for-build guile))) +(define* (git-fetch/in-band ref hash-algo hash + #:optional name + #:key (system (%current-system)) + (guile (default-guile)) + (git (git-package))) + "Return a fixed-output derivation that performs a Git checkout of REF, using +GIT and GUILE (thus, said derivation depends on GIT and GUILE). + +This method is deprecated in favor of the \"builtin:git-download\" builder. +It will be removed when versions of guix-daemon implementing +\"builtin:git-download\" will be sufficiently widespread." + (git-fetch/in-band* ref hash-algo hash name + #:system system + #:guile guile + #:git git)) + +(define* (git-fetch/lfs ref hash-algo hash + #:optional name + #:key (system (%current-system)) + (guile (default-guile)) + (git (git-package)) + (git-lfs (git-lfs-package))) + "Like git-fetch/in-band, but with support for the Git Large File +Storage (LFS) extension." + (git-fetch/in-band* ref hash-algo hash name + #:system system + #:guile guile + #:git git + #:git-lfs git-lfs)) + (define* (git-fetch/built-in ref hash-algo hash #:optional name #:key (system (%current-system))) diff --git a/guix/git.scm b/guix/git.scm index b7182305cf..cbcdb1904b 100644 --- a/guix/git.scm +++ b/guix/git.scm @@ -1,6 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2017, 2020 Mathieu Othacehe <m.othacehe@gmail.com> -;;; Copyright © 2018-2022 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2018-2023 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2021 Kyle Meyer <kyle@kyleam.com> ;;; Copyright © 2021 Marius Bakke <marius@gnu.org> ;;; Copyright © 2022 Maxime Devos <maximedevos@telenet.be> @@ -29,15 +29,18 @@ #:use-module (guix cache) #:use-module (gcrypt hash) #:use-module ((guix build utils) - #:select (mkdir-p delete-file-recursively)) + #:select (mkdir-p delete-file-recursively invoke/quiet)) #:use-module (guix store) #:use-module (guix utils) #:use-module (guix records) + #:use-module ((guix build syscalls) + #:select (terminal-string-width)) #:use-module (guix gexp) #:autoload (guix git-download) (git-reference-url git-reference-commit git-reference-recursive?) + #:autoload (guix config) (%git) #:use-module (guix sets) - #:use-module ((guix diagnostics) #:select (leave warning)) + #:use-module ((guix diagnostics) #:select (leave warning info)) #:use-module (guix progress) #:autoload (guix swh) (swh-download commit-id?) #:use-module (rnrs bytevectors) @@ -154,7 +157,7 @@ the 'SSL_CERT_FILE' and 'SSL_CERT_DIR' environment variables." ;; TODO: Both should be handled & exposed by the PROGRESS-BAR API instead. (define width (max (- (current-terminal-columns) - (string-length label) 7) + (terminal-string-width label) 7) 3)) (define grain @@ -428,6 +431,35 @@ could not be fetched from Software Heritage~%") (rename-file directory trashed) (delete-file-recursively trashed))) +(define (packs-in-git-repository directory) + "Return the number of pack files under DIRECTORY, a Git checkout." + (catch 'system-error + (lambda () + (let ((directory (opendir (in-vicinity directory ".git/objects/pack")))) + (let loop ((count 0)) + (match (readdir directory) + ((? eof-object?) + (closedir directory) + count) + (str + (loop (if (string-suffix? ".pack" str) + (+ 1 count) + count))))))) + (const 0))) + +(define (maybe-run-git-gc directory) + "Run 'git gc' in DIRECTORY if needed." + ;; XXX: As of libgit2 1.3.x (used by Guile-Git), there's no support for GC. + ;; Each time a checkout is pulled, a new pack is created, which eventually + ;; takes up a lot of space (lots of small, poorly-compressed packs). As a + ;; workaround, shell out to 'git gc' when the number of packs in a + ;; repository has become "too large", potentially wasting a lot of space. + ;; See <https://issues.guix.gnu.org/65720>. + (when (> (packs-in-git-repository directory) 25) + (info (G_ "compressing cached Git repository at '~a'...~%") + directory) + (invoke/quiet %git "-C" directory "gc"))) + (define* (update-cached-checkout url #:key (ref '()) @@ -515,6 +547,9 @@ it unchanged." seconds seconds nanoseconds nanoseconds)))) + ;; Run 'git gc' if needed. + (maybe-run-git-gc cache-directory) + ;; When CACHE-DIRECTORY is a sub-directory of the default cache ;; directory, remove expired checkouts that are next to it. (let ((parent (dirname cache-directory))) diff --git a/guix/grafts.scm b/guix/grafts.scm index 48f4c212f7..f4df513daf 100644 --- a/guix/grafts.scm +++ b/guix/grafts.scm @@ -22,7 +22,7 @@ #:use-module (guix records) #:use-module (guix combinators) #:use-module (guix derivations) - #:use-module ((guix utils) #:select (%current-system)) + #:use-module ((guix utils) #:select (%current-system target-hurd?)) #:use-module (guix sets) #:use-module (guix gexp) #:use-module (srfi srfi-1) @@ -98,7 +98,9 @@ OUTPUTS of DRV. This procedure performs \"shallow\" grafting in that GRAFTS are not recursively applied to dependencies of DRV." (define glibc-locales (module-ref (resolve-interface '(gnu packages commencement)) - 'glibc-utf8-locales-final)) + (if (target-hurd? system) + 'glibc-utf8-locales-final/hurd + 'glibc-utf8-locales-final))) (define mapping ;; List of store item pairs. diff --git a/guix/import/cabal.scm b/guix/import/cabal.scm index fe03c30254..d32c1c15fe 100644 --- a/guix/import/cabal.scm +++ b/guix/import/cabal.scm @@ -130,8 +130,17 @@ to the stack." (define (context-stack-clear!) ((context-stack) 'clear!)) -;; Indentation of the line being parsed. -(define current-indentation (make-parameter 0)) +;; Indentation of the line being parsed and that of the previous line. +(define current-indentation* (make-parameter 0)) + +(define previous-indentation (make-parameter 0)) + +(define* (current-indentation #:optional value) + (if value + (begin + (previous-indentation (current-indentation*)) + (current-indentation* value)) + (current-indentation*))) ;; Signal to reprocess the beginning of line, in case we need to close more ;; than one indentation level. @@ -196,27 +205,13 @@ to the stack." (exprs elif-else) : (append $1 (list ($2 '(())))) (elif-else) : (list ($1 '(())))) ;; LALR(1) parsers prefer to be left-recursive, which make if-statements slightly involved. - ;; XXX: This technically allows multiple else statements. - (elif-else (elif-else ELIF tests OCURLY exprs CCURLY) : (lambda (y) ($1 (list (append (list 'if $3 $5) y)))) - (elif-else ELIF tests open exprs close) : (lambda (y) ($1 (list (append (list 'if $3 $5) y)))) - (elif-else ELSE OCURLY exprs CCURLY) : (lambda (y) ($1 (list $4))) - ;; The 'open' token after 'tests' is shifted after an 'exprs' - ;; is found. This is because, instead of 'exprs' a 'OCURLY' - ;; token is a valid alternative. For this reason, 'open' - ;; pushes a <parse-context> with a line indentation equal to - ;; the indentation of 'exprs'. - ;; - ;; Differently from this, without the rule above this - ;; comment, when an 'ELSE' token is found, the 'open' token - ;; following the 'ELSE' would be shifted immediately, before - ;; the 'exprs' is found (because there are no other valid - ;; tokens). The 'open' would therefore create a - ;; <parse-context> with the indentation of 'ELSE' and not - ;; 'exprs', creating an inconsistency. We therefore allow - ;; mixed style conditionals. - (elif-else ELSE open exprs close) : (lambda (y) ($1 (list $4))) + (elif (elif ELIF tests OCURLY exprs CCURLY) : (lambda (y) ($1 (list (append (list 'if $3 $5) y)))) + (elif ELIF tests open exprs close) : (lambda (y) ($1 (list (append (list 'if $3 $5) y)))) ;; Terminating rule. (if-then) : (lambda (y) (append $1 y))) + (elif-else (elif ELSE OCURLY exprs CCURLY) : (lambda (y) ($1 (list $4))) + (elif ELSE open exprs close) : (lambda (y) ($1 (list $4))) + (elif) : $1) (if-then (IF tests OCURLY exprs CCURLY) : (list 'if $2 $4) (IF tests open exprs close) : (list 'if $2 $4)) (tests (TEST OPAREN ID CPAREN) : `(,$1 ,$3) @@ -237,7 +232,7 @@ to the stack." (OPAREN tests CPAREN) : $2) (open () : (context-stack-push! (make-parse-context (context layout) - (current-indentation)))) + (+ 1 (previous-indentation))))) (close (VCCURLY)))) (define (peek-next-line-indent port) @@ -655,7 +650,8 @@ If #f use the function 'port-filename' to obtain it." (let ((cabal-parser (make-cabal-parser))) (parameterize ((cabal-file-name (or file-name (port-filename port) "standard input")) - (current-indentation 0) + (current-indentation* 0) + (previous-indentation 0) (check-bol? #f) (context-stack (make-stack))) (cabal-parser (make-lexer port) (errorp))))) @@ -869,7 +865,16 @@ the ordering operation and the version." (((? string? name) values) (list name values)) ((("import" imports) rest ...) - (eval (append (append-map (cut assoc-ref common-stanzas <>) imports) + (eval (append (append-map + ;; The imports are (at least sometimes) a list with one string + ;; containing all the names separeted by commas. This splits + ;; those strings to a list of strings in the same format that is + ;; used in common-stanzas. + (cut assoc-ref common-stanzas <>) + (append-map (lambda (imports-string) + (map (compose string-downcase string-trim-both) + (string-split imports-string #\,))) + imports)) rest))) ((element rest ...) (cons (eval element) (eval rest))) diff --git a/guix/import/composer.scm b/guix/import/composer.scm new file mode 100644 index 0000000000..1ad608964b --- /dev/null +++ b/guix/import/composer.scm @@ -0,0 +1,268 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2019 Julien Lepiller <julien@lepiller.eu> +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. + +(define-module (guix import composer) + #:use-module (ice-9 match) + #:use-module (json) + #:use-module (guix hash) + #:use-module (guix base32) + #:use-module (guix build git) + #:use-module (guix build utils) + #:use-module (guix build-system) + #:use-module (guix build-system composer) + #:use-module (guix import json) + #:use-module (guix import utils) + #:use-module ((guix licenses) #:prefix license:) + #:use-module (guix memoization) + #:use-module (guix packages) + #:use-module (guix serialization) + #:use-module (guix upstream) + #:use-module (guix utils) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-11) + #:use-module (srfi srfi-26) + #:export (composer->guix-package + %composer-updater + composer-recursive-import + + %composer-base-url)) + +(define %composer-base-url + (make-parameter "https://repo.packagist.org")) + +(define (fix-version version) + "Return a fixed version from a version string. For instance, v10.1 -> 10.1" + (cond + ((string-prefix? "version" version) + (if (char-set-contains? char-set:digit (string-ref version 7)) + (substring version 7) + (substring version 8))) + ((string-prefix? "v" version) + (substring version 1)) + (else version))) + +(define (latest-version versions) + (fold (lambda (a b) (if (version>? (fix-version a) (fix-version b)) a b)) + (car versions) versions)) + +(define (json->require dict) + (if dict + (let loop ((result '()) (require dict)) + (match require + (() result) + ((((? (cut string-contains <> "/") name) . _) + require ...) + (loop (cons name result) require)) + ((_ require ...) (loop result require)) + (_ result))) + '())) + +(define-json-mapping <composer-source> make-composer-source composer-source? + json->composer-source + (type composer-source-type) + (url composer-source-url) + (reference composer-source-reference)) + +(define-json-mapping <composer-package> make-composer-package composer-package? + json->composer-package + (description composer-package-description) + (homepage composer-package-homepage) + (source composer-package-source "source" json->composer-source) + (name composer-package-name "name" php-package-name) + (version composer-package-version "version" fix-version) + (require composer-package-require "require" json->require) + (dev-require composer-package-dev-require "require-dev" json->require) + (license composer-package-license "license" + (lambda (vector) + (let ((l (map string->license (vector->list vector)))) + (if (eq? (length l) 1) + (car l) + `(list ,@l)))))) + +(define (valid-version? v) + (let ((d (string-downcase v))) + (and (not (string-contains d "dev")) + (not (string-contains d "beta")) + (not (string-contains d "rc"))))) + +(define* (composer-fetch name #:key (version #f)) + "Return a composer-package representation of the Composer metadata for the +package NAME with optional VERSION, or #f on failure." + (let* ((url (string-append (%composer-base-url) "/p/" name ".json")) + (packages (and=> (json-fetch url) + (lambda (pkg) + (let ((pkgs (assoc-ref pkg "packages"))) + (or (assoc-ref pkgs name) pkg)))))) + (if packages + (json->composer-package + (if version + (assoc-ref packages version) + (cdr + (reduce + (lambda (new cur-max) + (match new + (((? valid-version? version) . tail) + (if (version>? (fix-version version) + (fix-version (car cur-max))) + (cons* version tail) + cur-max)) + (_ cur-max))) + (cons* "0.0.0" #f) + packages)))) + #f))) + +(define (php-package-name name) + "Given the NAME of a package on Packagist, return a Guix-compliant name for +the package." + (let ((name (string-join (string-split name #\/) "-"))) + (if (string-prefix? "php-" name) + (snake-case name) + (string-append "php-" (snake-case name))))) + +(define (make-php-sexp composer-package) + "Return the `package' s-expression for a PHP package for the given +COMPOSER-PACKAGE." + (let* ((source (composer-package-source composer-package)) + (dependencies (map php-package-name + (composer-package-require composer-package))) + (dev-dependencies (map php-package-name + (composer-package-dev-require composer-package))) + (git? (equal? (composer-source-type source) "git"))) + ((if git? call-with-temporary-directory call-with-temporary-output-file) + (lambda* (temp #:optional port) + (and (if git? + (begin + (mkdir-p temp) + (git-fetch (composer-source-url source) + (composer-source-reference source) + temp)) + (url-fetch (composer-source-url source) temp)) + `(package + (name ,(composer-package-name composer-package)) + (version ,(composer-package-version composer-package)) + (source + (origin + ,@(if git? + `((method git-fetch) + (uri (git-reference + (url ,(if (string-suffix? + ".git" + (composer-source-url source)) + (string-drop-right + (composer-source-url source) + (string-length ".git")) + (composer-source-url source))) + (commit ,(composer-source-reference source)))) + (file-name (git-file-name name version)) + (sha256 + (base32 + ,(bytevector->nix-base32-string + (file-hash* temp))))) + `((method url-fetch) + (uri ,(composer-source-url source)) + (sha256 (base32 ,(guix-hash-url temp))))))) + (build-system composer-build-system) + ,@(if (null? dependencies) + '() + `((inputs + (list ,@(map string->symbol dependencies))))) + ,@(if (null? dev-dependencies) + '() + `((native-inputs + (list ,@(map string->symbol dev-dependencies))))) + (synopsis "") + (description ,(composer-package-description composer-package)) + (home-page ,(composer-package-homepage composer-package)) + (license ,(or (composer-package-license composer-package) + 'unknown-license!)))))))) + +(define composer->guix-package + (memoize + (lambda* (package-name #:key (version #f) #:allow-other-keys) + "Fetch the metadata for PACKAGE-NAME from packagist.org, and return the +`package' s-expression corresponding to that package and its list of +dependencies, or #f and the empty list on failure." + (let ((package (composer-fetch package-name #:version version))) + (if package + (let* ((dependencies-names (composer-package-require package)) + (dev-dependencies-names (composer-package-dev-require package))) + (values (make-php-sexp package) + (append dependencies-names dev-dependencies-names))) + (values #f '())))))) + +(define (guix-name->composer-name name) + "Given a guix package name, return the name of the package in Packagist." + (if (string-prefix? "php-" name) + (let ((components (string-split (substring name 4) #\-))) + (match components + ((namespace name ...) + (string-append namespace "/" (string-join name "-"))))) + name)) + +(define (guix-package->composer-name package) + "Given a Composer PACKAGE built from Packagist, return the name of the +package in Packagist." + (let ((upstream-name (assoc-ref + (package-properties package) + 'upstream-name)) + (name (package-name package))) + (if upstream-name + upstream-name + (guix-name->composer-name name)))) + +(define (string->license str) + "Convert the string STR into a license object." + (or (spdx-string->license str) + (match str + ("GNU LGPL" 'license:lgpl2.0) + ("GPL" 'license:gpl3) + ((or "BSD" "BSD License") 'license:bsd-3) + ((or "MIT" "MIT license" "Expat license") 'license:expat) + ("Public domain" 'license:public-domain) + ((or "Apache License, Version 2.0" "Apache 2.0") 'license:asl2.0) + (_ 'unknown-license!)))) + +(define (php-package? package) + "Return true if PACKAGE is a PHP package from Packagist." + (and + (eq? (package-build-system package) composer-build-system) + (string-prefix? "php-" (package-name package)))) + +(define (latest-release package) + "Return an <upstream-source> for the latest release of PACKAGE." + (let* ((php-name (guix-package->composer-name package)) + (package (composer-fetch php-name)) + (version (composer-package-version package)) + (url (composer-source-url (composer-package-source package)))) + (upstream-source + (package (package-name package)) + (version version) + (urls (list url))))) + +(define %composer-updater + (upstream-updater + (name 'composer) + (description "Updater for Composer packages") + (pred php-package?) + (import latest-release))) + +(define* (composer-recursive-import package-name #:optional version) + (recursive-import package-name + #:version version + #:repo->guix-package composer->guix-package + #:guix-name php-package-name)) diff --git a/guix/import/cran.scm b/guix/import/cran.scm index 59c65f9fa5..d7497e6fb9 100644 --- a/guix/import/cran.scm +++ b/guix/import/cran.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2015-2023 Ricardo Wurmus <rekado@elephly.net> +;;; Copyright © 2015-2024 Ricardo Wurmus <rekado@elephly.net> ;;; Copyright © 2015-2017, 2019-2021, 2023 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com> ;;; Copyright © 2020 Martin Becze <mjbecze@riseup.net> @@ -55,6 +55,10 @@ #:use-module (guix sets) #:export (%input-style + %bioconductor-version + download + fetch-description + cran->guix-package bioconductor->guix-package cran-recursive-import @@ -81,6 +85,21 @@ (define %input-style (make-parameter 'variable)) ; or 'specification +(define (format-inputs inputs) + "Generate a sorted list of package inputs from a list of upstream inputs." + (map (lambda (input) + (case (%input-style) + ((specification) + `(specification->package ,(upstream-input-name input))) + (else + ((compose string->symbol + upstream-input-downstream-name) + input)))) + (sort inputs + (lambda (a b) + (string-ci<? (upstream-input-name a) + (upstream-input-name b)))))) + (define (string->licenses license-string license-prefix) (let ((licenses (map string-trim-both @@ -173,17 +192,15 @@ package definition." (() '()) ((package-inputs ...) - `((,input-type (list ,@(map (compose string->symbol - upstream-input-downstream-name) - package-inputs))))))) + `((,input-type (list ,@(format-inputs package-inputs))))))) (define %cran-url "https://cran.r-project.org/web/packages/") (define %cran-canonical-url "https://cran.r-project.org/package=") (define %bioconductor-url "https://bioconductor.org/packages/") -;; The latest Bioconductor release is 3.17. Bioconductor packages should be +;; The latest Bioconductor release is 3.18. Bioconductor packages should be ;; updated together. -(define %bioconductor-version "3.17") +(define %bioconductor-version "3.18") (define* (bioconductor-packages-list-url #:optional type) (string-append "https://bioconductor.org/packages/" @@ -253,7 +270,7 @@ bioconductor package NAME, or #F if the package is unknown." ;; of the URLs is the /Archive CRAN URL. (any (cut download-to-store store <>) urls))))))))) -(define (fetch-description-from-tarball url) +(define* (fetch-description-from-tarball url #:key (download download)) "Fetch the tarball at URL, extra its 'DESCRIPTION' file, parse it, and return the resulting alist." (match (download url) @@ -271,7 +288,7 @@ return the resulting alist." (call-with-input-file (string-append dir "/DESCRIPTION") read-string))))))))) -(define* (fetch-description repository name #:optional version) +(define* (fetch-description repository name #:optional version replacement-download) "Return an alist of the contents of the DESCRIPTION file for the R package NAME at VERSION in the given REPOSITORY, or #f in case of failure. NAME is case-sensitive." @@ -293,7 +310,9 @@ from ~a: ~a (~a)~%") (string-append "mirror://cran/src/contrib/Archive/" name "/" name "_" version ".tar.gz")))) - (fetch-description-from-tarball urls)) + (fetch-description-from-tarball + urls #:download (or replacement-download + download))) (let* ((url (string-append %cran-url name "/DESCRIPTION")) (port (http-fetch url)) (result (description->alist (read-string port)))) @@ -310,7 +329,9 @@ from ~a: ~a (~a)~%") ;; TODO: Honor VERSION. (version (latest-bioconductor-package-version name type)) (url (car (bioconductor-uri name version type))) - (meta (fetch-description-from-tarball url))) + (meta (fetch-description-from-tarball + url #:download (or replacement-download + download)))) (if (boolean? type) meta (cons `(bioconductor-type . ,type) meta)))) @@ -383,7 +404,8 @@ empty list when the FIELD cannot be found." ;; The field for system dependencies is often abused to specify non-package ;; dependencies (such as c++11). This list is used to ignore them. (define invalid-packages - (list "c++" + (list "build-essential" + "c++" "c++11" "c++14" "c++17" @@ -392,7 +414,9 @@ empty list when the FIELD cannot be found." "gnu" "posix.1-2001" "linux" + "libR" "none" + "rtools" "unix" "windows" "xcode" @@ -410,6 +434,9 @@ empty list when the FIELD cannot be found." ("freetype2" "freetype") ("gettext" "gnu-gettext") ("gmake" "gnu-make") + ("h5py" "python-h5py") + ("hmmer3" "hmmer") + ("leidenalg" "python-leidenalg") ("libarchive-devel" "libarchive") ("libarchive_dev" "libarchive") ("libbz2" "bzip2") @@ -417,13 +444,27 @@ empty list when the FIELD cannot be found." ("libjpeg" "libjpeg-turbo") ("liblz4" "lz4") ("liblzma" "xz") + ("libssl-dev" "openssl") + ("libssl_dev" "openssl") ("libzstd" "zstd") ("libxml2-devel" "libxml2") + ("libxml2-dev" "libxml2") ("libz" "zlib") + ("libz-dev" "zlib") ("mariadb-devel" "mariadb") ("mysql56_dev" "mariadb") + ("nodejs" "node") + ("numpy" "python-numpy") + ("openssl-devel" "openssl") + ("openssl@1.1" "openssl-1.1") + ("packaging" "python-packaging") + ("pandas" "python-pandas") ("pandoc-citeproc" "pandoc") ("python3" "python-3") + ("pytorch" "python-pytorch") + ("scikit-learn" "python-scikit-learn") + ("scipy" "python-scipy") + ("sklearn" "python-scikit-learn") ("sqlite3" "sqlite") ("svn" "subversion") ("tcl/tk" "tcl") @@ -432,6 +473,7 @@ empty list when the FIELD cannot be found." ("x11" "libx11") ("xml2" "libxml2") ("zlib-devel" "zlib") + ("zlib1g-dev" "zlib") (_ sysname))) (define cran-guix-name (cut guix-name "r-" <>)) diff --git a/guix/import/crate.scm b/guix/import/crate.scm index 43823d006e..7a25b2243c 100644 --- a/guix/import/crate.scm +++ b/guix/import/crate.scm @@ -5,7 +5,8 @@ ;;; Copyright © 2021 Nicolas Goaziou <mail@nicolasgoaziou.fr> ;;; Copyright © 2022 Hartmut Goebel <h.goebel@crazy-compilers.com> ;;; Copyright © 2023 Simon Tournier <zimon.toutoune@gmail.com> -;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il> +;;; Copyright © 2023, 2024 Efraim Flashner <efraim@flashner.co.il> +;;; Copyright © 2023, 2024 David Elsing <david.elsing@posteo.net> ;;; ;;; This file is part of GNU Guix. ;;; @@ -25,12 +26,15 @@ (define-module (guix import crate) #:use-module (guix base32) #:use-module (guix build-system cargo) + #:use-module (guix diagnostics) #:use-module (gcrypt hash) #:use-module (guix http-client) + #:use-module (guix i18n) #:use-module (guix import json) #:use-module (guix import utils) #:use-module (guix memoization) #:use-module (guix packages) + #:use-module (guix read-print) #:use-module (guix upstream) #:use-module (guix utils) #:use-module (gnu packages) @@ -40,6 +44,7 @@ #:use-module (srfi srfi-1) #:use-module (srfi srfi-2) #:use-module (srfi srfi-26) + #:use-module (srfi srfi-69) #:use-module (srfi srfi-71) #:export (crate->guix-package guix-package->crate-name @@ -99,7 +104,7 @@ ;; Autoload Guile-Semver so we only have a soft dependency. (module-autoload! (current-module) - '(semver) '(string->semver semver->string semver<?)) + '(semver) '(string->semver semver->string semver<? semver=? semver>?)) (module-autoload! (current-module) '(semver ranges) '(string->semver-range semver-range-contains?)) @@ -164,16 +169,18 @@ record or #f if it was not found." (list-matches "^(0+\\.){,2}[0-9]+" version)))) (define* (make-crate-sexp #:key name version cargo-inputs cargo-development-inputs - home-page synopsis description license build?) + home-page synopsis description license build? yanked?) "Return the `package' s-expression for a rust package with the given NAME, VERSION, CARGO-INPUTS, CARGO-DEVELOPMENT-INPUTS, HOME-PAGE, SYNOPSIS, DESCRIPTION, and LICENSE." (define (format-inputs inputs) (map (match-lambda - ((name version) + ((name version yanked) (list (crate-name->package-name name) - (version->semver-prefix version)))) + (if yanked + (string-append version "-yanked") + (version->semver-prefix version))))) inputs)) (let* ((port (http-fetch (crate-uri name version))) @@ -183,6 +190,9 @@ and LICENSE." (pkg `(package (name ,guix-name) (version ,version) + ,@(if yanked? + `(,(comment "; This version was yanked!\n" #t)) + '()) (source (origin (method url-fetch) (uri (crate-uri ,name version)) @@ -190,6 +200,9 @@ and LICENSE." (sha256 (base32 ,(bytevector->nix-base32-string (port-sha256 port)))))) + ,@(if yanked? + `((properties '((crate-version-yanked? . #t)))) + '()) (build-system cargo-build-system) ,@(maybe-arguments (append (if build? '() @@ -206,7 +219,10 @@ and LICENSE." ((license) license) (_ `(list ,@license))))))) (close-port port) - (package->definition pkg (version->semver-prefix version)))) + (package->definition pkg + (if yanked? + (string-append version "-yanked") + (version->semver-prefix version))))) (define (string->license string) (filter-map (lambda (license) @@ -217,13 +233,47 @@ and LICENSE." 'unknown-license!))) (string-split string (string->char-set " /")))) -(define* (crate->guix-package crate-name #:key version include-dev-deps? - #:allow-other-keys) +(define (min-element l less) + "Returns the smallest element of l according to less or #f if l is empty." + + (let loop ((curr #f) + (remaining l)) + (if (null-list? remaining) + curr + (let ((next (car remaining)) + (remaining (cdr remaining))) + (if (and curr + (not (less next curr))) + (loop curr remaining) + (loop next remaining)))))) + +(define (max-crate-version-of-semver semver-range range) + "Returns a <crate-version> of the highest version within the semver range." + + (define (crate->semver crate) + (string->semver (crate-version-number crate))) + + (min-element + (filter (lambda (crate) + (semver-range-contains? semver-range (crate->semver crate))) + range) + (lambda args + (apply semver>? (map crate->semver args))))) + +(define (nonyanked-crate-versions crate) + "Returns a list of <crate-version>s which are not yanked by upstream." + (filter (lambda (entry) + (not (crate-version-yanked? entry))) + (crate-versions crate))) + +(define* (crate->guix-package + crate-name + #:key version include-dev-deps? allow-yanked? #:allow-other-keys) "Fetch the metadata for CRATE-NAME from crates.io, and return the `package' s-expression corresponding to that package, or #f on failure. When VERSION is specified, convert it into a semver range and attempt to fetch the latest version matching this semver range; otherwise fetch the latest -version of CRATE-NAME. If INCLUDE-DEV-DEPS is true then this will also +version of CRATE-NAME. If INCLUDE-DEV-DEPS is true then this will also look up the development dependencs for the given crate." (define (semver-range-contains-string? range version) @@ -242,63 +292,100 @@ look up the development dependencs for the given crate." (or version (crate-latest-version crate)))) - ;; find the highest existing package that fulfills the semver <range> + ;; Find the highest existing package that fulfills the semver <range>. + ;; Packages previously marked as yanked take lower priority. (define (find-package-version name range) (let* ((semver-range (string->semver-range range)) - (versions - (sort - (filter (lambda (version) - (semver-range-contains? semver-range version)) + (version + (min-element + (filter (match-lambda ((semver yanked) + (and + (or allow-yanked? (not yanked)) + (semver-range-contains? semver-range semver)))) (map (lambda (pkg) - (string->semver (package-version pkg))) + (let ((version (package-version pkg))) + (list + (string->semver version) + (assoc-ref (package-properties pkg) + 'crate-version-yanked?)))) (find-packages-by-name (crate-name->package-name name)))) - semver<?))) - (and (not (null-list? versions)) - (semver->string (last versions))))) - - ;; Find the highest version of a crate that fulfills the semver <range> - ;; and hasn't been yanked. + (match-lambda* (((semver1 yanked1) (semver2 yanked2)) + (or (and yanked1 (not yanked2)) + (and (eq? yanked1 yanked2) + (semver<? semver1 semver2)))))))) + (and (not (eq? #f version)) + (match-let (((semver yanked) version)) + (list (semver->string semver) yanked))))) + + ;; Find the highest version of a crate that fulfills the semver <range>. + ;; If no matching non-yanked version has been found and allow-yanked? is #t, + ;; also consider yanked packages. (define (find-crate-version crate range) - (let* ((semver-range (string->semver-range range)) - (versions - (sort - (filter (lambda (entry) - (and - (not (crate-version-yanked? (second entry))) - (semver-range-contains? semver-range (first entry)))) - (map (lambda (ver) - (list (string->semver (crate-version-number ver)) - ver)) - (crate-versions crate))) - (match-lambda* (((semver _) ...) - (apply semver<? semver)))))) - (and (not (null-list? versions)) - (second (last versions))))) - - (define (dependency-name+version dep) + (let ((semver-range (string->semver-range range)) + (versions (nonyanked-crate-versions crate))) + (or (and (not (null-list? versions)) + (max-crate-version-of-semver semver-range versions)) + (and allow-yanked? + (not (null-list? (crate-versions crate))) + (max-crate-version-of-semver semver-range + (crate-versions crate)))))) + + ;; If no non-yanked existing package version was found, check the upstream + ;; versions. If a non-yanked upsteam version exists, use it instead, + ;; otherwise use the existing package version, provided it exists. + (define (dependency-name+version+yanked dep) (let* ((name (crate-dependency-id dep)) - (req (crate-dependency-requirement dep)) - (existing-version (find-package-version name req))) - (if existing-version - (list name existing-version) + (req (crate-dependency-requirement dep)) + (existing-version (find-package-version name req))) + (if (and existing-version (not (second existing-version))) + (cons name existing-version) (let* ((crate (lookup-crate* name)) (ver (find-crate-version crate req))) - (list name - (crate-version-number ver)))))) + (if existing-version + (if (and ver (not (crate-version-yanked? ver))) + (if (semver=? (string->semver (first existing-version)) + (string->semver (crate-version-number ver))) + (begin + (warning (G_ "~A: version ~a is no longer yanked~%") + name (first existing-version)) + (cons name existing-version)) + (list name + (crate-version-number ver) + (crate-version-yanked? ver))) + (begin + (warning (G_ "~A: using existing version ~a, which was yanked~%") + name (first existing-version)) + (cons name existing-version))) + (begin + (unless ver + (leave (G_ "~A: no version found for requirement ~a~%") name req)) + (if (crate-version-yanked? ver) + (warning (G_ "~A: imported version ~a was yanked~%") + name (crate-version-number ver))) + (list name + (crate-version-number ver) + (crate-version-yanked? ver)))))))) (define version* (and crate - (find-crate-version crate version-number))) + (or (find-crate-version crate version-number) + (leave (G_ "~A: version ~a not found~%") crate-name version-number)))) ;; sort and map the dependencies to a list containing ;; pairs of (name version) (define (sort-map-dependencies deps) - (sort (map dependency-name+version + (sort (map dependency-name+version+yanked deps) - (match-lambda* (((name _) ...) + (match-lambda* (((name _ _) ...) (apply string-ci<? name))))) + (define (remove-yanked-info deps) + (map + (match-lambda ((name version yanked) + (list name version))) + deps)) + (if (and crate version*) (let* ((dependencies (crate-version-dependencies version*)) (dep-crates dev-dep-crates (partition normal-dependency? dependencies)) @@ -308,6 +395,7 @@ look up the development dependencs for the given crate." '()))) (values (make-crate-sexp #:build? include-dev-deps? + #:yanked? (crate-version-yanked? version*) #:name crate-name #:version (crate-version-number version*) #:cargo-inputs cargo-inputs @@ -324,19 +412,27 @@ look up the development dependencs for the given crate." #:description (crate-description crate) #:license (and=> (crate-version-license version*) string->license)) - (append cargo-inputs cargo-development-inputs))) + (append + (remove-yanked-info cargo-inputs) + (remove-yanked-info cargo-development-inputs)))) (values #f '()))) -(define* (crate-recursive-import crate-name #:key version) - (recursive-import crate-name - #:repo->guix-package (lambda* params - ;; download development dependencies only for the top level package - (let ((include-dev-deps? (equal? (car params) crate-name)) - (crate->guix-package* (memoize crate->guix-package))) - (apply crate->guix-package* - (append params `(#:include-dev-deps? ,include-dev-deps?))))) - #:version version - #:guix-name crate-name->package-name)) +(define* (crate-recursive-import + crate-name #:key version recursive-dev-dependencies? allow-yanked?) + (recursive-import + crate-name + #:repo->guix-package + (let ((crate->guix-package* (memoize crate->guix-package))) + (lambda* params + ;; download development dependencies only for the top level package + (let ((include-dev-deps? + (or (equal? (car params) crate-name) + recursive-dev-dependencies?))) + (apply crate->guix-package* + (append params `(#:include-dev-deps? ,include-dev-deps? + #:allow-yanked? ,allow-yanked?)))))) + #:version version + #:guix-name crate-name->package-name)) (define (guix-package->crate-name package) "Return the crate name of PACKAGE." @@ -352,6 +448,7 @@ look up the development dependencs for the given crate." (define (crate-name->package-name name) (guix-name "rust-" name)) + ;;; ;;; Updater @@ -365,12 +462,20 @@ look up the development dependencs for the given crate." include a VERSION string to fetch a specific version." (let* ((crate-name (guix-package->crate-name package)) (crate (lookup-crate crate-name)) - (version (or version (crate-latest-version crate))) - (url (crate-uri crate-name version))) - (upstream-source - (package (package-name package)) - (version version) - (urls (list url))))) + (version (or version + (let ((max-crate-version + (max-crate-version-of-semver + (string->semver-range + (string-append "^" (package-version package))) + (nonyanked-crate-versions crate)))) + (and=> max-crate-version + crate-version-number))))) + (if version + (upstream-source + (package (package-name package)) + (version version) + (urls (list (crate-uri crate-name version)))) + #f))) (define %crate-updater (upstream-updater diff --git a/guix/import/go.scm b/guix/import/go.scm index 0357e6a1eb..dd9298808d 100644 --- a/guix/import/go.scm +++ b/guix/import/go.scm @@ -7,6 +7,7 @@ ;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz> ;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev> ;;; Copyright © 2021 Simon Tournier <zimon.toutoune@gmail.com> +;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il> ;;; ;;; This file is part of GNU Guix. ;;; @@ -28,6 +29,7 @@ #:use-module (guix git) #:use-module (guix hash) #:use-module (guix i18n) + #:use-module ((guix utils) #:select (version>?)) #:use-module (guix diagnostics) #:use-module (guix import utils) #:use-module (guix import json) @@ -92,6 +94,11 @@ ;;; Code: +(define (go-package) + "Return the 'go' package. This is a lazy reference so that we don't +depend on (gnu packages golang)." + (module-ref (resolve-interface '(gnu packages golang)) 'go)) + (define http-fetch* ;; Like http-fetch, but memoized and returning the body as a string. (memoize (lambda args @@ -293,7 +300,10 @@ comment, or unknown) and is followed by the indicated data." ;; The following directives may all be used solo or in a block ;; RequireSpec = ModulePath Version newline . - (define-peg-pattern require all (and module-path version EOL)) + (define-peg-pattern require all + (and module-path version + ;; We don't want the transitive dependencies. + (not-followed-by (and (* WS) "//" (* WS) "indirect")) EOL)) (define-peg-pattern require-top body (and (ignore "require") (or (and block-start (* (or require block-line)) block-end) require))) @@ -310,7 +320,7 @@ comment, or unknown) and is followed by the indicated data." (define-peg-pattern with all (or (and module-path version) file-path)) (define-peg-pattern replace all (and original => with EOL)) (define-peg-pattern replace-top body - (and (ignore "replace") + (and (ignore "replace") (or (and block-start (* (or replace block-line)) block-end) replace))) ;; RetractSpec = ( Version | "[" Version "," Version "]" ) newline . @@ -374,6 +384,17 @@ DIRECTIVE." ;; Prevent inlining of this procedure, which is accessed by unit tests. (set! go.mod-requirements go.mod-requirements) +(define (go.mod-go-version go.mod) + "Return the minimum version of go required to specified by GO.MOD." + (let ((go-version (go.mod-directives go.mod 'go))) + (if (null? go-version) + ;; If the go directive is missing, go 1.16 is assumed. + '(version "1.16") + (flatten go-version)))) + +;; Prevent inlining of this procedure, which is accessed by unit tests. +(set! go.mod-go-version go.mod-go-version) + (define-record-type <vcs> (%make-vcs url-prefix root-regex type) vcs? @@ -606,6 +627,7 @@ When VERSION is unspecified, the latest version available is used." available-versions module-path)) (content (fetch-go.mod goproxy module-path version*)) + (min-go-version (second (go.mod-go-version (parse-go.mod content)))) (dependencies+versions (go.mod-requirements (parse-go.mod content))) (dependencies (if pin-versions? dependencies+versions @@ -630,10 +652,13 @@ When VERSION is unspecified, the latest version available is used." ,(vcs->origin vcs-type vcs-repo-url version*)) (build-system go-build-system) (arguments - '(#:import-path ,module-path - ,@(if (string=? module-path-sans-suffix root-module-path) - '() - `(#:unpack-path ,root-module-path)))) + (list ,@(if (version>? min-go-version (package-version (go-package))) + `(#:go ,(string->number min-go-version)) + '()) + #:import-path ,module-path + ,@(if (string=? module-path-sans-suffix root-module-path) + '() + `(#:unpack-path ,root-module-path)))) ,@(maybe-propagated-inputs (map (match-lambda ((name version) diff --git a/guix/import/hackage.scm b/guix/import/hackage.scm index 9333bedbbd..bbaee73a06 100644 --- a/guix/import/hackage.scm +++ b/guix/import/hackage.scm @@ -335,7 +335,7 @@ the hash of the Cabal file." (synopsis ,(cabal-package-synopsis cabal)) (description ,(beautify-description (cabal-package-description cabal))) (license ,(string->license (cabal-package-license cabal)))) - inputs))) + (map upstream-input-name inputs)))) (define* (hackage->guix-package package-name #:key (include-test-dependencies? #t) diff --git a/guix/import/stackage.scm b/guix/import/stackage.scm index 00814c7d46..f801835b33 100644 --- a/guix/import/stackage.scm +++ b/guix/import/stackage.scm @@ -92,7 +92,7 @@ "Return the version of the package with upstream NAME included in PACKAGES." (let ((pkg (find (lambda (pkg) (string=? (stackage-package-name pkg) name)) packages))) - (stackage-package-version pkg))) + (and=> pkg stackage-package-version))) ;;; diff --git a/guix/inferior.scm b/guix/inferior.scm index fca6fb4b22..190ba01b3c 100644 --- a/guix/inferior.scm +++ b/guix/inferior.scm @@ -872,14 +872,17 @@ prefix, resolve it; and if 'commit' is unset, fetch CHANNEL's branch tip." (authenticate? #t) (cache-directory (%inferior-cache-directory)) (ttl (* 3600 24 30)) - validate-channels) + (reference-channels '()) + (validate-channels (const #t))) "Return a directory containing a guix filetree defined by CHANNELS, a list of channels. The directory is a subdirectory of CACHE-DIRECTORY, where entries can be reclaimed after TTL seconds. This procedure opens a new connection to the build daemon. AUTHENTICATE? determines whether CHANNELS are authenticated. -VALIDATE-CHANNELS, if specified, must be a one argument procedure accepting a -list of channels that can be used to validate the channels; it should raise an -exception in case of problems." + +VALIDATE-CHANNELS must be a four-argument procedure used to validate channel +instances against REFERENCE-CHANNELS; it is passed as #:validate-pull to +'latest-channel-instances' and should raise an exception in case a target +channel commit is deemed \"invalid\"." (define commits ;; Since computing the instances of CHANNELS is I/O-intensive, use a ;; cheaper way to get the commit list of CHANNELS. This limits overhead @@ -927,30 +930,31 @@ exception in case of problems." (if (file-exists? cached) cached - (begin - (when (procedure? validate-channels) - (validate-channels channels)) - (run-with-store store - (mlet* %store-monad ((instances - -> (latest-channel-instances store channels - #:authenticate? - authenticate?)) - (profile - (channel-instances->derivation instances))) - (mbegin %store-monad - ;; It's up to the caller to install a build handler to report - ;; what's going to be built. - (built-derivations (list profile)) - - ;; Cache if and only if AUTHENTICATE? is true. - (if authenticate? - (mbegin %store-monad - (symlink* (derivation->output-path profile) cached) - (add-indirect-root* cached) - (return cached)) - (mbegin %store-monad - (add-temp-root* (derivation->output-path profile)) - (return (derivation->output-path profile)))))))))) + (run-with-store store + (mlet* %store-monad ((instances + -> (latest-channel-instances store channels + #:authenticate? + authenticate? + #:current-channels + reference-channels + #:validate-pull + validate-channels)) + (profile + (channel-instances->derivation instances))) + (mbegin %store-monad + ;; It's up to the caller to install a build handler to report + ;; what's going to be built. + (built-derivations (list profile)) + + ;; Cache if and only if AUTHENTICATE? is true. + (if authenticate? + (mbegin %store-monad + (symlink* (derivation->output-path profile) cached) + (add-indirect-root* cached) + (return cached)) + (mbegin %store-monad + (add-temp-root* (derivation->output-path profile)) + (return (derivation->output-path profile))))))))) (define* (inferior-for-channels channels #:key diff --git a/guix/least-authority.scm b/guix/least-authority.scm index bfd7275e7c..3465fe9a48 100644 --- a/guix/least-authority.scm +++ b/guix/least-authority.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2022 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2022-2023 Ludovic Courtès <ludo@gnu.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -41,6 +41,8 @@ (define* (least-authority-wrapper program #:key (name "pola-wrapper") + (user #f) + (group #f) (guest-uid 1000) (guest-gid 1000) (mappings '()) @@ -55,7 +57,11 @@ symbols; it runs with GUEST-UID and GUEST-GID. MAPPINGS is a list of <file-system-mapping> records indicating directories mirrored inside the execution environment of PROGRAM. DIRECTORY is the working directory of the wrapped process. Each environment listed in PRESERVED-ENVIRONMENT-VARIABLES -is preserved; other environment variables are erased." +is preserved; other environment variables are erased. + +When USER and GROUP are set and NAMESPACES does not include 'user, change UIDs +and GIDs to these prior to executing PROGRAM. This usually requires that the +resulting wrapper be executed as root so it can call setgid(2) and setuid(2)." (define code (with-imported-modules (source-module-closure '((gnu system file-systems) @@ -113,6 +119,10 @@ is preserved; other environment variables are erased." #$program signal) (exit (+ 128 signal)))))) + (define namespaces '#$namespaces) + (define host-group '#$group) + (define host-user '#$user) + ;; Note: 'call-with-container' creates a sub-process that this one ;; waits for. This might seem suboptimal but unshare(2) isn't ;; really applicable: the process would still run in the same PID @@ -123,6 +133,17 @@ is preserved; other environment variables are erased." (lambda () (chdir #$directory) (environ variables) + + (unless (memq 'user namespaces) + ;; This process lives in its parent user namespace, + ;; presumably as root; now is the time to setgid/setuid if + ;; asked for it (the 'clone' call would fail with EPERM if we + ;; changed UIDs/GIDs beforehand). + (when host-group + (setgid (group:gid (getgr host-group)))) + (when host-user + (setuid (passwd:uid (getpw host-user))))) + (apply execl #$program #$program (cdr (command-line)))) ;; Don't assume PROGRAM can behave as an init process. diff --git a/guix/lint.scm b/guix/lint.scm index 7ccf52dec1..861e352b93 100644 --- a/guix/lint.scm +++ b/guix/lint.scm @@ -1857,7 +1857,8 @@ them for PACKAGE." (call-with-input-file file (lambda (port) - (let loop ((line-number 1) + (go-to-location port starting-line 0) + (let loop ((line-number starting-line) (last-line #f) (warnings '())) (let ((line (read-line port))) diff --git a/guix/monad-repl.scm b/guix/monad-repl.scm index 8a6053edd5..d6b39112b7 100644 --- a/guix/monad-repl.scm +++ b/guix/monad-repl.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2014, 2015, 2016, 2022 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2014-2016, 2022-2023 Ludovic Courtès <ludo@gnu.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -21,13 +21,15 @@ #:use-module (guix monads) #:use-module (guix utils) #:use-module (guix packages) + #:autoload (guix build-system) (bag) #:use-module (guix status) - #:autoload (guix gexp) (lower-object) + #:autoload (guix gexp) (gexp gexp? lower-gexp lowered-gexp-sexp lower-object) #:use-module ((guix derivations) #:select (derivation? derivation->output-paths built-derivations)) + #:autoload (guix read-print) (pretty-print-with-comments) #:use-module (ice-9 match) - #:use-module (ice-9 pretty-print) + #:autoload (ice-9 pretty-print) (pretty-print) #:use-module (system repl repl) #:use-module (system repl common) #:use-module (system repl command) @@ -138,4 +140,68 @@ Enter a REPL for values in the store monad." (repl-option-set! new 'interp #t) (run-repl new)))) -;;; monad-repl.scm ends here + +;;; +;;; Viewing package arguments. +;;; + +(define (keyword-argument-value args keyword default) + "Return the value associated with KEYWORD in ARGS, a keyword/value sequence, +or DEFAULT if KEYWORD is missing from ARGS." + (let loop ((args args)) + (match args + (() + default) + ((kw value rest ...) + (if (eq? kw keyword) + value + (loop rest)))))) + +(define (package-argument-command repl form keyword default) + "Implement a command that display KEYWORD, a keyword such as #:phases, in +the arguments of the package FORM evaluates to. Return DEFAULT is KEYWORD is +missing from those arguments." + (match (repl-eval repl form) + ((? package? package) + (let* ((bag* (bag + (inherit (package->bag package)) + (build (lambda* (name inputs #:rest args) + (with-monad %store-monad + (return (keyword-argument-value args keyword + default)))))))) + (define phases + (parameterize ((%graft? #f)) + (with-store store + (set-build-options store + #:print-build-trace #t + #:print-extended-build-trace? #t + #:multiplexed-build-output? #t) + (run-with-store store + (mlet %store-monad ((exp (bag->derivation bag*))) + (if (gexp? exp) + (mlet %store-monad ((gexp (lower-gexp exp))) + (return (lowered-gexp-sexp gexp))) + (return exp))))))) + + (run-hook before-print-hook phases) + (let ((column (port-column (current-output-port)))) + (pretty-print-with-comments (current-output-port) phases + #:indent column) + (newline (current-output-port))))) + (_ + (format #t ";; ERROR: This command only accepts package records.~%")))) + +(define-meta-command ((phases guix) repl (form)) + "phases +Return the build phases of the package defined by FORM." + (package-argument-command repl form #:phases #~%standard-phases)) + +(define-meta-command ((configure-flags guix) repl (form)) + "configure-flags +Return the configure flags of the package defined by FORM." + (package-argument-command repl form #:configure-flags #~'())) + +(define-meta-command ((make-flags guix) repl (form)) + "make-flags +Return the make flags of the package defined by FORM." + (package-argument-command repl form #:make-flags #~'())) diff --git a/guix/packages.scm b/guix/packages.scm index e2e82692ad..930b1a3b0e 100644 --- a/guix/packages.scm +++ b/guix/packages.scm @@ -849,14 +849,15 @@ identifiers. The result is inferred from the file names of patches." '())))) (append-map patch-vulnerabilities patches))) -(define (%standard-patch-inputs) +(define (%standard-patch-inputs system) (let* ((canonical (module-ref (resolve-interface '(gnu packages base)) 'canonical-package)) (ref (lambda (module var) ;; Make sure 'canonical-package' is not influenced by ;; '%current-target-system' since we're going to use the ;; native package anyway. - (parameterize ((%current-target-system #f)) + (parameterize ((%current-target-system #f) + (%current-system system)) (canonical (module-ref (resolve-interface module) var)))))) `(("tar" ,(ref '(gnu packages base) 'tar)) @@ -866,7 +867,12 @@ identifiers. The result is inferred from the file names of patches." ("lzip" ,(ref '(gnu packages compression) 'lzip)) ("unzip" ,(ref '(gnu packages compression) 'unzip)) ("patch" ,(ref '(gnu packages base) 'patch)) - ("locales" ,(ref '(gnu packages base) 'glibc-utf8-locales))))) + ("locales" + ,(parameterize ((%current-target-system #f) + (%current-system system)) + (canonical + ((module-ref (resolve-interface '(gnu packages base)) + 'libc-utf8-locales-for-target)))))))) (define (default-guile) "Return the default Guile package used to run the build code of @@ -909,7 +915,7 @@ specifies modules in scope when evaluating SNIPPET." (define lookup-input ;; The default value of the 'patch-inputs' field, and thus INPUTS is #f, ;; so deal with that. - (let ((inputs (or inputs (%standard-patch-inputs)))) + (let ((inputs (or inputs (%standard-patch-inputs system)))) (lambda (name) (match (assoc-ref inputs name) ((package) package) diff --git a/guix/platform.scm b/guix/platform.scm index 55917ca308..994563ab26 100644 --- a/guix/platform.scm +++ b/guix/platform.scm @@ -29,6 +29,7 @@ platform-target platform-system platform-linux-architecture + platform-rust-target platform-glibc-dynamic-linker &platform-not-found-error @@ -74,6 +75,8 @@ (system platform-system) (linux-architecture platform-linux-architecture (default #false)) + (rust-target platform-rust-target + (default #false)) (glibc-dynamic-linker platform-glibc-dynamic-linker)) diff --git a/guix/platforms/arm.scm b/guix/platforms/arm.scm index 32c0fbc032..b0c76efc73 100644 --- a/guix/platforms/arm.scm +++ b/guix/platforms/arm.scm @@ -27,6 +27,7 @@ (target "arm-linux-gnueabihf") (system "armhf-linux") (linux-architecture "arm") + (rust-target "armv7-unknown-linux-gnueabihf") (glibc-dynamic-linker "/lib/ld-linux-armhf.so.3"))) (define aarch64-linux @@ -34,4 +35,5 @@ (target "aarch64-linux-gnu") (system "aarch64-linux") (linux-architecture "arm64") + (rust-target "aarch64-unknown-linux-gnu") (glibc-dynamic-linker "/lib/ld-linux-aarch64.so.1"))) diff --git a/guix/platforms/avr.scm b/guix/platforms/avr.scm new file mode 100644 index 0000000000..ba178db6ea --- /dev/null +++ b/guix/platforms/avr.scm @@ -0,0 +1,28 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2023 Foundation Devices, Inc. <hello@foundationdevices.com> +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. + +(define-module (guix platforms avr) + #:use-module (guix platform) + #:use-module (guix records) + #:export (avr)) + +(define avr + (platform + (target "avr") + (system #f) + (glibc-dynamic-linker #f))) diff --git a/guix/platforms/mips.scm b/guix/platforms/mips.scm index e6fa9eb292..17b6958f48 100644 --- a/guix/platforms/mips.scm +++ b/guix/platforms/mips.scm @@ -26,4 +26,5 @@ (target "mips64el-linux-gnu") (system "mips64el-linux") (linux-architecture "mips") + (rust-target "mips64el-unknown-linux-gnuabi64") (glibc-dynamic-linker "/lib/ld.so.1"))) diff --git a/guix/platforms/powerpc.scm b/guix/platforms/powerpc.scm index 1c7141ab42..c55301768d 100644 --- a/guix/platforms/powerpc.scm +++ b/guix/platforms/powerpc.scm @@ -28,6 +28,7 @@ (target "powerpc-linux-gnu") (system "powerpc-linux") (linux-architecture "powerpc") + (rust-target "powerpc-unknown-linux-gnu") (glibc-dynamic-linker "/lib/ld.so.1"))) (define powerpc64-linux @@ -35,6 +36,7 @@ (target "powerpc64-linux-gnu") (system #f) ;not supported (linux-architecture "powerpc") + (rust-target "powerpc64-unknown-linux-gnu") (glibc-dynamic-linker "/lib/ld64.so.1"))) (define powerpc64le-linux @@ -42,4 +44,5 @@ (target "powerpc64le-linux-gnu") (system "powerpc64le-linux") (linux-architecture "powerpc") + (rust-target "powerpc64le-unknown-linux-gnu") (glibc-dynamic-linker "/lib/ld64.so.2"))) diff --git a/guix/platforms/riscv.scm b/guix/platforms/riscv.scm index c716c12c12..1b34e82b36 100644 --- a/guix/platforms/riscv.scm +++ b/guix/platforms/riscv.scm @@ -26,4 +26,5 @@ (target "riscv64-linux-gnu") (system "riscv64-linux") (linux-architecture "riscv") + (rust-target "riscv64gc-unknown-linux-gnu") (glibc-dynamic-linker "/lib/ld-linux-riscv64-lp64d.so.1"))) diff --git a/guix/platforms/x86.scm b/guix/platforms/x86.scm index 6f547dd770..0c8fc7296c 100644 --- a/guix/platforms/x86.scm +++ b/guix/platforms/x86.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2022 Mathieu Othacehe <othacehe@gnu.org> +;;; Copyright © 2023, 2024 Efraim Flashner <efraim@flashner.co.il> ;;; ;;; This file is part of GNU Guix. ;;; @@ -21,6 +22,7 @@ #:use-module (guix records) #:export (i686-linux x86_64-linux + x86_64-linux-x32 i686-mingw x86_64-mingw i586-gnu)) @@ -30,6 +32,7 @@ (target "i686-linux-gnu") (system "i686-linux") (linux-architecture "i386") + (rust-target "i686-unknown-linux-gnu") (glibc-dynamic-linker "/lib/ld-linux.so.2"))) (define x86_64-linux @@ -37,22 +40,34 @@ (target "x86_64-linux-gnu") (system "x86_64-linux") (linux-architecture "x86_64") + (rust-target "x86_64-unknown-linux-gnu") (glibc-dynamic-linker "/lib/ld-linux-x86-64.so.2"))) +(define x86_64-linux-x32 + (platform + (target "x86_64-linux-gnux32") + (system #f) + (linux-architecture "x86_64") + (rust-target "x86_64-unknown-linux-gnux32") + (glibc-dynamic-linker "/lib/ld-linux-x32.so.2"))) + (define i686-mingw (platform (target "i686-w64-mingw32") (system #f) + (rust-target "i686-pc-windows-gnu") (glibc-dynamic-linker #f))) (define x86_64-mingw (platform (target "x86_64-w64-mingw32") (system #f) + (rust-target "x86_64-pc-windows-gnu") (glibc-dynamic-linker #f))) (define i586-gnu (platform (target "i586-pc-gnu") (system "i586-gnu") + (rust-target "i686-unknown-hurd-gnu") (glibc-dynamic-linker "/lib/ld.so.1"))) diff --git a/guix/profiles.scm b/guix/profiles.scm index 5d2fb8dc64..ce2f8337bf 100644 --- a/guix/profiles.scm +++ b/guix/profiles.scm @@ -1000,8 +1000,9 @@ MANIFEST." (module-ref (resolve-interface '(gnu packages texinfo)) 'texinfo)) (define gzip ;lazy reference (module-ref (resolve-interface '(gnu packages compression)) 'gzip)) - (define glibc-utf8-locales ;lazy reference - (module-ref (resolve-interface '(gnu packages base)) 'glibc-utf8-locales)) + (define libc-utf8-locales-for-target ;lazy reference + (module-ref (resolve-interface '(gnu packages base)) + 'libc-utf8-locales-for-target)) (define build (with-imported-modules '((guix build utils)) @@ -1043,7 +1044,8 @@ MANIFEST." (setenv "PATH" (string-append #+gzip "/bin")) ;for info.gz files (setenv "GUIX_LOCPATH" - #+(file-append glibc-utf8-locales "/lib/locale")) + #+(file-append (libc-utf8-locales-for-target system) + "/lib/locale")) (mkdir-p (string-append #$output "/share/info")) (exit (every install-info @@ -1124,8 +1126,9 @@ MANIFEST. Single-file bundles are required by programs such as Git and Lynx." ;; See <http://lists.gnu.org/archive/html/guix-devel/2015-02/msg00429.html> ;; for a discussion. - (define glibc-utf8-locales ;lazy reference - (module-ref (resolve-interface '(gnu packages base)) 'glibc-utf8-locales)) + (define libc-utf8-locales-for-target ;lazy reference + (module-ref (resolve-interface '(gnu packages base)) + 'libc-utf8-locales-for-target)) (define build (with-imported-modules '((guix build utils)) @@ -1159,9 +1162,11 @@ MANIFEST. Single-file bundles are required by programs such as Git and Lynx." ;; Some file names in the NSS certificates are UTF-8 encoded so ;; install a UTF-8 locale. (setenv "LOCPATH" - (string-append #+glibc-utf8-locales "/lib/locale/" + (string-append #+(libc-utf8-locales-for-target system) + "/lib/locale/" #+(version-major+minor - (package-version glibc-utf8-locales)))) + (package-version + (libc-utf8-locales-for-target system))))) (setlocale LC_ALL "en_US.utf8") (match (append-map ca-files '#$(manifest-inputs manifest)) @@ -1999,19 +2004,21 @@ are cross-built for TARGET." (and (derivation? drv) (gexp-input drv))) extras)) - (define glibc-utf8-locales ;lazy reference + (define libc-utf8-locales-for-target ;lazy reference (module-ref (resolve-interface '(gnu packages base)) - 'glibc-utf8-locales)) + 'libc-utf8-locales-for-target)) (define set-utf8-locale ;; Some file names (e.g., in 'nss-certs') are UTF-8 encoded so ;; install a UTF-8 locale. - #~(begin - (setenv "LOCPATH" - #$(file-append glibc-utf8-locales "/lib/locale/" - (version-major+minor - (package-version glibc-utf8-locales)))) - (setlocale LC_ALL "en_US.utf8"))) + (let ((locales (libc-utf8-locales-for-target + (or system (%current-system))))) + #~(begin + (setenv "LOCPATH" + #$(file-append locales "/lib/locale/" + (version-major+minor + (package-version locales)))) + (setlocale LC_ALL "en_US.utf8")))) (define builder (with-imported-modules '((guix build profiles) diff --git a/guix/progress.scm b/guix/progress.scm index 33cf6f4a1a..e1b35094e1 100644 --- a/guix/progress.scm +++ b/guix/progress.scm @@ -21,6 +21,7 @@ (define-module (guix progress) #:use-module (guix records) + #:autoload (guix build syscalls) (terminal-string-width) #:use-module (srfi srfi-19) #:use-module (rnrs io ports) #:use-module (rnrs bytevectors) @@ -307,7 +308,7 @@ tasks is performed. Write PREFIX at the beginning of the line." (if (string-null? prefix) (display (progress-bar ratio (current-terminal-columns)) port) (let ((width (- (current-terminal-columns) - (string-length prefix) 3))) + (terminal-string-width prefix) 3))) (display prefix port) (display " " port) (display (progress-bar ratio width) port))) diff --git a/guix/read-print.scm b/guix/read-print.scm index 7faad82c94..6421b79737 100644 --- a/guix/read-print.scm +++ b/guix/read-print.scm @@ -46,6 +46,7 @@ page-break page-break? + <comment> comment comment? comment->string @@ -330,6 +331,7 @@ expressions and blanks that were read." ('add-after '(((modify-phases) . 3))) ('add-before '(((modify-phases) . 3))) ('replace '(((modify-phases) . 2))) ;different from 'modify-inputs' + ('parameterize 2) ('substitute* 2) ('substitute-keyword-arguments 2) ('call-with-input-file 2) diff --git a/guix/scripts/challenge.scm b/guix/scripts/challenge.scm index 01e2f9a2b2..d38171b868 100644 --- a/guix/scripts/challenge.scm +++ b/guix/scripts/challenge.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2015-2017, 2019-2022 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2015-2017, 2019-2023 Ludovic Courtès <ludo@gnu.org> ;;; ;;; This file is part of GNU Guix. ;;; @@ -504,7 +504,6 @@ Challenge the substitutes for PACKAGE... provided by one or more servers.\n")) (define %default-options `((system . ,(%current-system)) - (substitute-urls . ,%default-substitute-urls) (difference-report . ,report-differing-files))) @@ -539,7 +538,13 @@ Challenge the substitutes for PACKAGE... provided by one or more servers.\n")) (G_ "no arguments specified, nothing to do~%")) (exit 0)) (x - files)))) + files))) + (urls (or urls + (substitute-urls store) + (begin + (warning (G_ "could not determine current \ +substitute URLs; using defaults~%")) + %default-substitute-urls)))) (set-build-options store #:use-substitutes? #f) diff --git a/guix/scripts/download.scm b/guix/scripts/download.scm index 0441d3fead..19052d5652 100644 --- a/guix/scripts/download.scm +++ b/guix/scripts/download.scm @@ -55,7 +55,7 @@ file)) (define (ensure-valid-store-file-name name) - "Replace any character not allowed in a stror name by an underscore." + "Replace any character not allowed in a store name by an underscore." (define valid ;; according to nix/libstore/store-api.cc diff --git a/guix/scripts/edit.scm b/guix/scripts/edit.scm index ff2d529bcf..b7b4cd2514 100644 --- a/guix/scripts/edit.scm +++ b/guix/scripts/edit.scm @@ -64,7 +64,11 @@ Start $VISUAL or $EDITOR to edit the definitions of PACKAGE...\n")) (define (search-path* path file) "Like 'search-path' but exit if FILE is not found." - (let ((absolute-file-name (search-path path file))) + (let ((absolute-file-name (or (search-path path file) + ;; It could be that FILE is a relative name + ;; i.e., not relative to an element of PATH. + (and (file-exists? file) + file)))) (unless absolute-file-name ;; Shouldn't happen unless somebody fiddled with the 'location' field. (leave (G_ "file '~a' not found in search path ~s~%") diff --git a/guix/scripts/environment.scm b/guix/scripts/environment.scm index 6ae3b11e39..1d7a6e198d 100644 --- a/guix/scripts/environment.scm +++ b/guix/scripts/environment.scm @@ -311,6 +311,9 @@ use '--preserve' instead~%")) (define (options/resolve-packages store opts) "Return OPTS with package specification strings replaced by manifest entries for the corresponding packages." + (define system + (assoc-ref opts 'system)) + (define (manifest-entry=? e1 e2) (and (eq? (manifest-entry-item e1) (manifest-entry-item e2)) (string=? (manifest-entry-output e1) @@ -327,11 +330,11 @@ for the corresponding packages." ((? package? package) (if (eq? mode 'ad-hoc-package) (list (package->manifest-entry* package)) - (manifest-entries (package->development-manifest package)))) + (manifest-entries (package->development-manifest package system)))) (((? package? package) (? string? output)) (if (eq? mode 'ad-hoc-package) (list (package->manifest-entry* package output)) - (manifest-entries (package->development-manifest package)))) + (manifest-entries (package->development-manifest package system)))) ((lst ...) (append-map (cut packages->outputs <> mode) lst)))) @@ -345,7 +348,8 @@ for the corresponding packages." (('package 'package (? string? spec)) (manifest-entries (package->development-manifest - (transform (specification->package+output spec))))) + (transform (specification->package+output spec)) + system))) (('expression mode str) ;; Add all the outputs of the package STR evaluates to. (packages->outputs (read/eval str) mode)) diff --git a/guix/scripts/import.scm b/guix/scripts/import.scm index 1e8ffd25ec..d2a1cee56e 100644 --- a/guix/scripts/import.scm +++ b/guix/scripts/import.scm @@ -47,7 +47,7 @@ (define importers '("gnu" "pypi" "cpan" "hackage" "stackage" "egg" "elpa" "gem" "go" "cran" "crate" "texlive" "json" "opam" - "minetest" "elm" "hexpm")) + "minetest" "elm" "hexpm" "composer")) (define (resolve-importer name) (let ((module (resolve-interface diff --git a/guix/scripts/import/composer.scm b/guix/scripts/import/composer.scm new file mode 100644 index 0000000000..412bae6318 --- /dev/null +++ b/guix/scripts/import/composer.scm @@ -0,0 +1,107 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2015 David Thompson <davet@gnu.org> +;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com> +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. + +(define-module (guix scripts import composer) + #:use-module (guix ui) + #:use-module (guix utils) + #:use-module (guix scripts) + #:use-module (guix import composer) + #:use-module (guix scripts import) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-11) + #:use-module (srfi srfi-37) + #:use-module (srfi srfi-41) + #:use-module (ice-9 match) + #:use-module (ice-9 format) + #:export (guix-import-composer)) + + +;;; +;;; Command-line options. +;;; + +(define %default-options + '()) + +(define (show-help) + (display (G_ "Usage: guix import composer PACKAGE-NAME +Import and convert the Composer package for PACKAGE-NAME.\n")) + (display (G_ " + -h, --help display this help and exit")) + (display (G_ " + -V, --version display version information and exit")) + (display (G_ " + -r, --recursive generate package expressions for all Composer packages\ + that are not yet in Guix")) + (newline) + (show-bug-report-information)) + +(define %options + ;; Specification of the command-line options. + (cons* (option '(#\h "help") #f #f + (lambda args + (show-help) + (exit 0))) + (option '(#\V "version") #f #f + (lambda args + (show-version-and-exit "guix import composer"))) + (option '(#\r "recursive") #f #f + (lambda (opt name arg result) + (alist-cons 'recursive #t result))) + %standard-import-options)) + + +;;; +;;; Entry point. +;;; + +(define (guix-import-composer . args) + (define (parse-options) + ;; Return the alist of option values. + (args-fold* args %options + (lambda (opt name arg result) + (leave (G_ "~A: unrecognized option~%") name)) + (lambda (arg result) + (alist-cons 'argument arg result)) + %default-options)) + + (let* ((opts (parse-options)) + (args (filter-map (match-lambda + (('argument . value) + value) + (_ #f)) + (reverse opts)))) + (match args + ((package-name) + (if (assoc-ref opts 'recursive) + (map (match-lambda + ((and ('package ('name name) . rest) pkg) + `(define-public ,(string->symbol name) + ,pkg)) + (_ #f)) + (composer-recursive-import package-name)) + (let ((sexp (composer->guix-package package-name))) + (unless sexp + (leave (G_ "failed to download meta-data for package '~a'~%") + package-name)) + sexp))) + (() + (leave (G_ "too few arguments~%"))) + ((many ...) + (leave (G_ "too many arguments~%")))))) diff --git a/guix/scripts/import/crate.scm b/guix/scripts/import/crate.scm index 038faa87db..082a973aee 100644 --- a/guix/scripts/import/crate.scm +++ b/guix/scripts/import/crate.scm @@ -5,6 +5,7 @@ ;;; Copyright © 2019, 2020 Martin Becze <mjbecze@riseup.net> ;;; Copyright © 2021 Sarah Morgensen <iskarian@mgsn.dev> ;;; Copyright © 2023 Simon Tournier <zimon.toutoune@gmail.com> +;;; Copyright © 2023 David Elsing <david.elsing@posteo.net> ;;; ;;; This file is part of GNU Guix. ;;; @@ -47,6 +48,13 @@ Import and convert the crates.io package for PACKAGE-NAME.\n")) (display (G_ " -r, --recursive import packages recursively")) + (display (G_ " + --recursive-dev-dependencies + include dev-dependencies recursively")) + (display (G_ " + --allow-yanked + allow importing yanked crates if no alternative + satisfying the version requirement exists")) (newline) (display (G_ " -h, --help display this help and exit")) @@ -67,6 +75,12 @@ Import and convert the crates.io package for PACKAGE-NAME.\n")) (option '(#\r "recursive") #f #f (lambda (opt name arg result) (alist-cons 'recursive #t result))) + (option '("recursive-dev-dependencies") #f #f + (lambda (opt name arg result) + (alist-cons 'recursive-dev-dependencies #t result))) + (option '("allow-yanked") #f #f + (lambda (opt name arg result) + (alist-cons 'allow-yanked #t result))) %standard-import-options)) @@ -92,8 +106,14 @@ Import and convert the crates.io package for PACKAGE-NAME.\n")) (package-name->name+version spec)) (match (if (assoc-ref opts 'recursive) - (crate-recursive-import name #:version version) - (crate->guix-package name #:version version #:include-dev-deps? #t)) + (crate-recursive-import + name #:version version + #:recursive-dev-dependencies? + (assoc-ref opts 'recursive-dev-dependencies) + #:allow-yanked? (assoc-ref opts 'allow-yanked)) + (crate->guix-package + name #:version version #:include-dev-deps? #t + #:allow-yanked? (assoc-ref opts 'allow-yanked))) ((or #f '()) (leave (G_ "failed to download meta-data for package '~a'~%") (if version diff --git a/guix/scripts/locate.scm b/guix/scripts/locate.scm index ae64f46896..963ff2bf57 100644 --- a/guix/scripts/locate.scm +++ b/guix/scripts/locate.scm @@ -114,14 +114,24 @@ alter table Packages add column output text; "))) +;; XXX: missing in guile-sqlite3@0.1.3 +(define SQLITE_BUSY 5) + (define (call-with-database file proc) - (let ((db (sqlite-open file))) - (dynamic-wind - (lambda () #t) - (lambda () - (ensure-latest-database-schema db) - (proc db)) - (lambda () (sqlite-close db))))) + (catch 'sqlite-error + (lambda () + (let ((db (sqlite-open file))) + (dynamic-wind + (lambda () #t) + (lambda () + (ensure-latest-database-schema db) + (proc db)) + (lambda () (sqlite-close db))))) + (lambda (key who code errmsg) + (if (= code SQLITE_BUSY) + (leave (G_ "~a: database is locked by another process~%") + file) + (throw key who code errmsg))))) (define (ensure-latest-database-schema db) "Ensure DB follows the latest known version of the schema." @@ -657,7 +667,7 @@ Locate FILE and return the list of packages that contain it.\n")) files))) (() (if (null? files) - (unless update? + (unless (or update? (assoc-ref opts 'clear?)) (leave (G_ "no files to search for~%"))) (leave (N_ "file~{ '~a'~} not found in database '~a'~%" "files~{ '~a'~} not found in database '~a'~%" diff --git a/guix/scripts/pack.scm b/guix/scripts/pack.scm index bdbea49910..3e45c34895 100644 --- a/guix/scripts/pack.scm +++ b/guix/scripts/pack.scm @@ -8,6 +8,8 @@ ;;; Copyright © 2020, 2021, 2022, 2023 Maxim Cournoyer <maxim.cournoyer@gmail.com> ;;; Copyright © 2020 Eric Bavier <bavier@posteo.net> ;;; Copyright © 2022 Alex Griffin <a@ajgrf.com> +;;; Copyright © 2023 Graham James Addis <graham@addis.org.uk> +;;; Copyright © 2023 Oleg Pykhalov <go.wigust@gmail.com> ;;; ;;; This file is part of GNU Guix. ;;; @@ -47,6 +49,7 @@ #:use-module (guix scripts build) #:use-module (guix transformations) #:use-module ((guix self) #:select (make-config.scm)) + #:use-module ((guix docker) #:select (%docker-image-max-layers)) #:use-module (gnu compression) #:use-module (gnu packages) #:use-module (gnu packages bootstrap) @@ -137,7 +140,8 @@ dependencies are registered." ;; Make sure non-ASCII file names are properly handled. (setenv "GUIX_LOCPATH" - #+(file-append glibc-utf8-locales "/lib/locale")) + #+(file-append (libc-utf8-locales-for-target (%current-system)) + "/lib/locale")) (setlocale LC_ALL "en_US.utf8") (sql-schema #$schema) @@ -201,6 +205,16 @@ target the profile's @file{bin/env} file: (leave (G_ "~a: invalid symlink specification~%") arg)))) +(define (entry-point-argument-spec-option-parser opt name arg result) + "A SRFI-37 option parser for the --entry-point-argument option. The spec +takes multiple occurrences. The entries are used in the exec form for the +docker entry-point. The values are used as parameters in conjunction with the +--entry-point option which is used as the first value in the exec form." + (let ((entry-point-argument (assoc-ref result 'entry-point-argument))) + (alist-cons 'entry-point-argument + (append entry-point-argument (list arg)) + (alist-delete 'entry-point-argument result eq?)))) + (define (set-utf8-locale profile) "Configure the environment to use the \"en_US.utf8\" locale provided by the GLIBC-UT8-LOCALES package." @@ -209,7 +223,10 @@ GLIBC-UT8-LOCALES package." (profile-locales? profile)) #~(begin (setenv "GUIX_LOCPATH" - #+(file-append glibc-utf8-locales "/lib/locale")) + #+(file-append (let-system (system target) + (libc-utf8-locales-for-target + (or target system))) + "/lib/locale")) (setlocale LC_ALL "en_US.utf8")) #~(setenv "GUIX_LOCPATH" "unset for tests"))) @@ -502,12 +519,15 @@ added to the pack." localstatedir? (symlinks '()) (archiver tar) - (extra-options '())) - "Return a derivation to construct a Docker image of PROFILE. The -image is a tarball conforming to the Docker Image Specification, compressed -with COMPRESSOR. It can be passed to 'docker load'. If TARGET is true, it -must a be a GNU triplet and it is used to derive the architecture metadata in -the image. EXTRA-OPTIONS may contain the IMAGE-TAG keyword argument." + (extra-options '()) + max-layers) + "Return a derivation to construct a Docker image of PROFILE. The image is a +tarball conforming to the Docker Image Specification, compressed with +COMPRESSOR. It can be passed to 'docker load'. If TARGET is true, it must a +be a GNU triplet and it is used to derive the architecture metadata in the +image. EXTRA-OPTIONS may contain the IMAGE-TAG keyword argument. If +MAX-LAYERS is not false, the image will be splitted in up to MAX-LAYERS +layers." (define database (and localstatedir? (file-append (store-database (list profile)) @@ -558,10 +578,28 @@ the image. EXTRA-OPTIONS may contain the IMAGE-TAG keyword argument." `((directory "/tmp" ,(getuid) ,(getgid) #o1777) ,@(append-map symlink->directives '#$symlinks))) - (setenv "PATH" #+(file-append archiver "/bin")) + (define (form-entry-point prefix entry-point entry-point-argument) + ;; Construct entry-point parameter for build-docker-image. The + ;; first entry is constructed by prefixing the entry-point with + ;; the supplied index, subsequent entries are taken from the + ;; --entry-point-argument options. + (and=> entry-point + (lambda (entry-point) + (cons* (string-append prefix "/" entry-point) + entry-point-argument)))) + + (setenv "PATH" + (string-join `(#+(file-append archiver "/bin") + #+@(if max-layers + (list (file-append gzip "/bin")) + '())) + ":")) (let-keywords '#$extra-options #f - ((image-tag #f)) + ((image-tag #f) + (entry-point-argument '()) + (max-layers #f)) + (build-docker-image #$output (map store-info-item (call-with-input-file "profile" @@ -574,16 +612,16 @@ the image. EXTRA-OPTIONS may contain the IMAGE-TAG keyword argument." #:database #+database #:system (or #$target %host-type) #:environment environment - #:entry-point - #$(and entry-point - #~(list - (string-append #$profile "/" - #$entry-point))) + #:entry-point (form-entry-point + #$profile + #$entry-point + entry-point-argument) #:extra-files directives #:compressor #+(compressor-command compressor) #:creation-time - (make-time time-utc 0 1))))))) + (make-time time-utc 0 1) + #:max-layers max-layers)))))) (gexp->derivation (string-append name ".tar" (compressor-extension compressor)) @@ -1260,6 +1298,8 @@ last resort for relocation." (debug . 0) (verbosity . 1) (symlinks . ()) + (entry-point-argument . ()) + (max-layers . ,%docker-image-max-layers) (compressor . ,(first %compressors)))) (define %formats @@ -1295,7 +1335,13 @@ last resort for relocation." rest)))) (define %docker-format-options - (list (required-option 'image-tag))) + (list (required-option 'image-tag) + (option '(#\A "entry-point-argument") #t #f + entry-point-argument-spec-option-parser) + (option '("max-layers") #t #f + (lambda (opt name arg result) + (alist-cons 'max-layers (string->number* arg) + result))))) (define (show-docker-format-options) (display (G_ " @@ -1304,7 +1350,15 @@ last resort for relocation." (define (show-docker-format-options/detailed) (display (G_ " --image-tag=NAME - Use the given NAME for the Docker image repository")) + Use the given NAME for the Docker image repository + + -A, --entry-point-argument=COMMAND/PARAMETER + Value(s) to use for the Docker ENTRYPOINT arguments. + Multiple instances are accepted. This is only valid + in conjunction with the --entry-point option + + --max-layers=N + Number of image layers")) (newline) (exit 0)) @@ -1615,7 +1669,11 @@ Create a bundle of PACKAGE.\n")) (extra-options (match pack-format ('docker (list #:image-tag - (assoc-ref opts 'image-tag))) + (assoc-ref opts 'image-tag) + #:entry-point-argument + (assoc-ref opts 'entry-point-argument) + #:max-layers + (assoc-ref opts 'max-layers))) ('deb (list #:control-file (process-file-arg opts 'control-file) diff --git a/guix/scripts/shell.scm b/guix/scripts/shell.scm index 10ea110fee..0584a7e018 100644 --- a/guix/scripts/shell.scm +++ b/guix/scripts/shell.scm @@ -399,9 +399,16 @@ return #f and #f." ((('nesting? . #t) . rest) (loop rest system file (append specs '("nested guix")))) ((('load . ('package candidate)) . rest) + ;; This is 'guix shell -D -f guix.scm'. (if (and (not file) (null? specs)) (loop rest system candidate specs) (values #f #f))) + ((('load . ('ad-hoc-package candidate)) . rest) + ;; When running 'guix shell -f guix.scm', one typically expects + ;; 'guix.scm' to be evaluated every time because it may contain + ;; references like (local-file "." #:recursive? #t). Thus, disable + ;; caching. + (values #f #f)) ((('manifest . candidate) . rest) (if (and (not file) (null? specs)) (loop rest system candidate specs) diff --git a/guix/scripts/size.scm b/guix/scripts/size.scm index d26ed98388..8a8676a16f 100644 --- a/guix/scripts/size.scm +++ b/guix/scripts/size.scm @@ -317,7 +317,8 @@ Report the size of the PACKAGE or STORE-ITEM, with its dependencies.\n")) ;; Turn off grafts because (1) substitute servers do not serve grafted ;; packages, and (2) they do not make any difference on the ;; resulting size. - (parameterize ((%graft? #f)) + (parameterize ((%graft? #f) + (%current-system system)) (with-store store (set-build-options store #:use-substitutes? #t diff --git a/guix/scripts/style.scm b/guix/scripts/style.scm index 145cd09881..211980dc1c 100644 --- a/guix/scripts/style.scm +++ b/guix/scripts/style.scm @@ -625,6 +625,8 @@ Update package definitions to the latest style.\n")) opts))) (unless (eq? format-package-definition style) (warning (G_ "'--styling' option has no effect in whole-file mode~%"))) + (when (null? files) + (warning (G_ "no files specified, nothing to do~%"))) (for-each format-whole-file files)) (let ((packages (filter-map (match-lambda (('argument . spec) diff --git a/guix/scripts/substitute.scm b/guix/scripts/substitute.scm index 126f0f9c69..37cd08e289 100755 --- a/guix/scripts/substitute.scm +++ b/guix/scripts/substitute.scm @@ -635,8 +635,9 @@ way to download the nar." (let loop ((cache-urls cache-urls)) (match cache-urls (() - (leave (G_ "failed to find alternative substitute for '~a'~%") - (narinfo-path narinfo))) + (report-error (G_ "failed to find alternative substitute for '~a'~%") + (narinfo-path narinfo)) + (display "not-found\n" port)) ((cache-url rest ...) (match (lookup-narinfos cache-url (list (narinfo-path narinfo)) diff --git a/guix/scripts/system.scm b/guix/scripts/system.scm index f85b663d64..bf3d2f9044 100644 --- a/guix/scripts/system.scm +++ b/guix/scripts/system.scm @@ -58,6 +58,7 @@ #:use-module (guix scripts system reconfigure) #:use-module (guix build utils) #:use-module (guix progress) + #:use-module ((guix docker) #:select (%docker-image-max-layers)) #:use-module (gnu build image) #:use-module (gnu build install) #:autoload (gnu build file-systems) @@ -1053,6 +1054,8 @@ Some ACTIONS support additional ARGS.\n")) (newline) (show-native-build-options-help) (newline) + (show-docker-format-options) + (newline) (display (G_ " -h, --help display this help and exit")) (display (G_ " @@ -1060,12 +1063,21 @@ Some ACTIONS support additional ARGS.\n")) (newline) (show-bug-report-information)) +(define %docker-format-options + (list (option '("max-layers") #t #f + (lambda (opt name arg result) + (alist-cons 'max-layers (string->number* arg) + result))))) + (define %options ;; Specifications of the command-line options. (cons* (option '(#\h "help") #f #f (lambda args (leave-on-EPIPE (show-help)) (exit 0))) + (option '("help-docker-format") #f #f + (lambda args + (show-docker-format-options/detailed))) (option '(#\V "version") #f #f (lambda args (show-version-and-exit "guix system"))) @@ -1154,7 +1166,8 @@ Some ACTIONS support additional ARGS.\n")) (alist-cons 'list-installed (or arg "") result))) (append %standard-build-options %standard-cross-build-options - %standard-native-build-options))) + %standard-native-build-options + %docker-format-options))) (define %default-options ;; Alist of default option values. @@ -1175,7 +1188,8 @@ Some ACTIONS support additional ARGS.\n")) (label . #f) (volatile-image-root? . #f) (volatile-vm-root? . #t) - (graph-backend . "graphviz"))) + (graph-backend . "graphviz") + (max-layers . ,%docker-image-max-layers))) (define (verbosity-level opts) "Return the verbosity level based on OPTS, the alist of parsed options." @@ -1183,6 +1197,17 @@ Some ACTIONS support additional ARGS.\n")) (if (eq? (assoc-ref opts 'action) 'build) 3 1))) +(define (show-docker-format-options) + (display (G_ " + --help-docker-format list options specific to the docker image type."))) + +(define (show-docker-format-options/detailed) + (display (G_ " + --max-layers=N + Number of image layers")) + (newline) + (exit 0)) + ;;; ;;; Entry point. @@ -1245,6 +1270,7 @@ resulting from command-line parsing." ((docker-image) docker-image-type) (else image-type))) (image-size (assoc-ref opts 'image-size)) + (image-max-layers (assoc-ref opts 'max-layers)) (volatile? (assoc-ref opts 'volatile-image-root?)) (shared-network? @@ -1258,6 +1284,7 @@ resulting from command-line parsing." (image-with-label base-image label) base-image)) (size image-size) + (max-layers image-max-layers) (volatile-root? volatile?) (shared-network? shared-network?)))) (os (or (image-operating-system image) diff --git a/guix/scripts/time-machine.scm b/guix/scripts/time-machine.scm index f31fae7435..2c30fe7cfd 100644 --- a/guix/scripts/time-machine.scm +++ b/guix/scripts/time-machine.scm @@ -46,12 +46,6 @@ #:use-module (srfi srfi-71) #:export (guix-time-machine)) -;;; The required inferiors mechanism relied on by 'guix time-machine' was -;;; firmed up in v1.0.0; it is the oldest, safest commit that can be travelled -;;; to. -(define %oldest-possible-commit - "6298c3ffd9654d3231a6f25390b056483e8f407c") ;v1.0.0 - ;;; ;;; Command-line options. @@ -146,6 +140,31 @@ Execute COMMAND ARGS... in an older version of Guix.\n")) ;;; +;;; Avoiding traveling too far back. +;;; + +;;; The required inferiors mechanism relied on by 'guix time-machine' was +;;; firmed up in v1.0.0; it is the oldest, safest commit that can be travelled +;;; to. +(define %oldest-possible-commit + "6298c3ffd9654d3231a6f25390b056483e8f407c") ;v1.0.0 + +(define %reference-channels + (list (channel (inherit %default-guix-channel) + (commit %oldest-possible-commit)))) + +(define (validate-guix-channel channel start commit relation) + "Raise an error if CHANNEL is the 'guix' channel and the RELATION of COMMIT +to %OLDEST-POSSIBLE-COMMIT is not that of an ancestor." + (unless (or (not (guix-channel? channel)) + (memq relation '(ancestor self))) + (raise (formatted-message + (G_ "cannot travel past commit `~a' from May 1st, 2019") + (string-take %oldest-possible-commit 12))))) + + + +;;; ;;; Entry point. ;;; @@ -160,44 +179,22 @@ Execute COMMAND ARGS... in an older version of Guix.\n")) (ref (assoc-ref opts 'ref)) (substitutes? (assoc-ref opts 'substitutes?)) (authenticate? (assoc-ref opts 'authenticate-channels?))) - - (define (validate-guix-channel channels) - "Finds the Guix channel among CHANNELS, and validates that REF as -captured from the closure, a git reference specification such as a commit hash -or tag associated to the channel, is valid and new enough to satisfy the 'guix -time-machine' requirements. If the captured REF variable is #f, the reference -validate is the one of the Guix channel found in CHANNELS. A -`formatted-message' condition is raised otherwise." - (let* ((guix-channel (find guix-channel? channels)) - (guix-channel-commit (channel-commit guix-channel)) - (guix-channel-branch (channel-branch guix-channel)) - (guix-channel-ref (if guix-channel-commit - `(tag-or-commit . ,guix-channel-commit) - `(branch . ,guix-channel-branch))) - (reference (or ref guix-channel-ref)) - (checkout commit relation (update-cached-checkout - (channel-url guix-channel) - #:ref reference - #:starting-commit - %oldest-possible-commit))) - (unless (memq relation '(ancestor self)) - (raise (formatted-message - (G_ "cannot travel past commit `~a' from May 1st, 2019") - (string-take %oldest-possible-commit 12)))))) - - (when command-line - (let* ((directory - (with-store store - (with-status-verbosity (assoc-ref opts 'verbosity) - (with-build-handler (build-notifier #:use-substitutes? - substitutes? - #:verbosity - (assoc-ref opts 'verbosity) - #:dry-run? #f) - (set-build-options-from-command-line store opts) - (cached-channel-instance store channels - #:authenticate? authenticate? - #:validate-channels - validate-guix-channel))))) - (executable (string-append directory "/bin/guix"))) - (apply execl (cons* executable executable command-line)))))))) + (if command-line + (let* ((directory + (with-store store + (with-status-verbosity (assoc-ref opts 'verbosity) + (with-build-handler (build-notifier #:use-substitutes? + substitutes? + #:verbosity + (assoc-ref opts 'verbosity) + #:dry-run? #f) + (set-build-options-from-command-line store opts) + (cached-channel-instance store channels + #:authenticate? authenticate? + #:reference-channels + %reference-channels + #:validate-channels + validate-guix-channel))))) + (executable (string-append directory "/bin/guix"))) + (apply execl (cons* executable executable command-line))) + (warning (G_ "no command specified; nothing to do~%"))))))) diff --git a/guix/scripts/weather.scm b/guix/scripts/weather.scm index 140df3435f..2f8985593d 100644 --- a/guix/scripts/weather.scm +++ b/guix/scripts/weather.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2017-2022 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2017-2023 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2017 Ricardo Wurmus <rekado@elephly.net> ;;; Copyright © 2018 Kyle Meyer <kyle@kyleam.com> ;;; Copyright © 2020 Simon Tournier <zimon.toutoune@gmail.com> @@ -35,6 +35,8 @@ #:use-module ((guix build utils) #:select (every*)) #:use-module (guix substitutes) #:use-module (guix narinfo) + #:use-module (guix pki) + #:autoload (gcrypt pk-crypto) (canonical-sexp->string) #:use-module (guix http-client) #:use-module (guix ci) #:use-module (guix sets) @@ -185,6 +187,44 @@ or #f if it could not be determined." (() #f))) +(define (check-narinfo-authorization narinfo) + "Print a warning when NARINFO is not signed by an authorized key." + (define acl + (catch 'system-error + (lambda () + (current-acl)) + (lambda args + (warning (G_ "could not read '~a': ~a~%") + %acl-file (strerror (system-error-errno args))) + (warning (G_ "'~a' is unreadable, cannot determine whether \ +substitutes are authorized~%") + %acl-file) + #f))) + + (unless (or (not acl) (valid-narinfo? narinfo acl)) + (warning (G_ "substitutes from '~a' are unauthorized~%") + (narinfo-uri-base narinfo)) + ;; The "all substitutes" below reflects the fact that, in reality, it *is* + ;; possible to download "unauthorized" substitutes, as long as they match + ;; authorized substitutes. + (display-hint (G_ "To authorize all substitutes from @uref{~a} to be +downloaded, the following command needs to be run as root: + +@example +guix archive --authorize <<EOF +~a +EOF +@end example + +Alternatively, on Guix System, you can add the signing key above to the +@code{authorized-keys} field of @code{guix-configuration}. + +See \"Getting Substitutes from Other Servers\" in the manual for more +information.") + (narinfo-uri-base narinfo) + (canonical-sexp->string + (signature-subject (narinfo-signature narinfo)))))) + (define* (report-server-coverage server items #:key display-missing?) "Report the subset of ITEMS available as substitutes on SERVER. @@ -204,6 +244,12 @@ In case ITEMS is an empty list, return 1 instead." #:make-progress-reporter (lambda* (total #:key url #:allow-other-keys) (progress-reporter/bar total))))) + (match narinfos + (() #f) + ((narinfo . _) + ;; Help diagnose missing substitute authorizations. + (check-narinfo-authorization narinfo))) + (let ((obtained (length narinfos)) (requested (length items)) (missing (lset-difference string=? @@ -391,7 +437,7 @@ Report the availability of substitutes.\n")) %standard-native-build-options)) (define %default-options - `((substitute-urls . ,%default-substitute-urls))) + '()) (define (load-manifest file) "Load the manifest from FILE and return the list of packages it refers to." @@ -582,7 +628,16 @@ SERVER. Display information for packages with at least THRESHOLD dependents." (let* ((opts (parse-command-line args %options (list %default-options) #:build-options? #f)) - (urls (assoc-ref opts 'substitute-urls)) + (urls (or (assoc-ref opts 'substitute-urls) + (with-store store + (substitute-urls store)) + (begin + ;; Could not determine the daemon's current + ;; substitute URLs, presumably because it's too + ;; old. + (warning (G_ "using default \ +substitute URLs~%")) + %default-substitute-urls))) (systems (match (filter-map (match-lambda (('system . system) system) (_ #f)) diff --git a/guix/self.scm b/guix/self.scm index a1f235659d..f378548959 100644 --- a/guix/self.scm +++ b/guix/self.scm @@ -73,7 +73,10 @@ ("po4a" . ,(ref 'gettext 'po4a)) ("gettext-minimal" . ,(ref 'gettext 'gettext-minimal)) ("gcc-toolchain" . ,(ref 'commencement 'gcc-toolchain)) - ("glibc-utf8-locales" . ,(ref 'base 'glibc-utf8-locales)) + ("glibc-utf8-locales" . ,(delay + ((module-ref (resolve-interface + '(gnu packages base)) + 'libc-utf8-locales-for-target)))) ("graphviz" . ,(ref 'graphviz 'graphviz-minimal)) ("font-ghostscript" . ,(ref 'ghostscript 'font-ghostscript)) ("texinfo" . ,(ref 'texinfo 'texinfo))))) diff --git a/guix/store.scm b/guix/store.scm index f8e77b2cd9..97c4f32a5b 100644 --- a/guix/store.scm +++ b/guix/store.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2012-2022 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2012-2023 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2018 Jan Nieuwenhuizen <janneke@gnu.org> ;;; Copyright © 2019, 2020 Mathieu Othacehe <m.othacehe@gmail.com> ;;; Copyright © 2020 Florian Pelz <pelzflorian@pelzflorian.de> @@ -145,6 +145,7 @@ path-info-nar-size built-in-builders + substitute-urls references references/cached references* @@ -199,7 +200,7 @@ derivation-log-file log-file)) -(define %protocol-version #x163) +(define %protocol-version #x164) (define %worker-magic-1 #x6e697863) ; "nixc" (define %worker-magic-2 #x6478696f) ; "dxio" @@ -253,7 +254,8 @@ (query-valid-derivers 33) (optimize-store 34) (verify-store 35) - (built-in-builders 80)) + (built-in-builders 80) + (substitute-urls 81)) (define-enumerate-type hash-algo ;; hash.hh @@ -1780,6 +1782,16 @@ The result is always the empty list unless the daemon was started with This makes sense only when the daemon was started with '--cache-failures'." boolean) +(define substitute-urls + (let ((urls (operation (substitute-urls) + #f + string-list))) + (lambda (store) + "Return the list of currently configured substitutes URLs for STORE, or +#f if the daemon is too old and does not implement this RPC." + (and (>= (store-connection-version store) #x164) + (urls store))))) + ;;; ;;; Per-connection caches. diff --git a/guix/transformations.scm b/guix/transformations.scm index 9cba6bedab..132ccd957a 100644 --- a/guix/transformations.scm +++ b/guix/transformations.scm @@ -3,6 +3,7 @@ ;;; Copyright © 2021 Marius Bakke <marius@gnu.org> ;;; Copyright © 2023 Sarthak Shah <shahsarthakw@gmail.com> ;;; Copyright © 2023 Efraim Flashner <efraim@flashner.co.il> +;;; Copyright © 2023 Ekaitz Zarraga <ekaitz@elenq.tech> ;;; ;;; This file is part of GNU Guix. ;;; @@ -439,7 +440,8 @@ the equal sign." actual compiler." (define wrapper #~(begin - (use-modules (ice-9 match)) + (use-modules (ice-9 match) + (ice-9 string-fun)) (define psabi #$(gcc-architecture->micro-architecture-level micro-architecture)) @@ -486,11 +488,20 @@ actual compiler." (apply execl next (append (cons next arguments) - (if (and (search-next "go") - (string=? next (search-next "go"))) - '() - (list (string-append "-march=" - #$micro-architecture))))))))))) + (cond + ((and (search-next "go") + (string=? next (search-next "go"))) + '()) + ((and (search-next "zig") + (string=? next (search-next "zig"))) + `(,(string-append + ;; https://issues.guix.gnu.org/67075#3 + "-Dcpu=" + (string-replace-substring + #$micro-architecture "-" "_")))) + (else + (list (string-append "-march=" + #$micro-architecture)))))))))))) (define program (program-file (string-append "tuning-compiler-wrapper-" micro-architecture) @@ -508,7 +519,7 @@ actual compiler." (symlink #$program (string-append bin "/" program))) '("cc" "gcc" "clang" "g++" "c++" "clang++" - "go"))))))) + "go" "zig"))))))) (define (build-system-with-tuning-compiler bs micro-architecture) "Return a variant of BS, a build system, that ensures that the compiler that diff --git a/guix/ui.scm b/guix/ui.scm index e3bf07212f..962d291d2e 100644 --- a/guix/ui.scm +++ b/guix/ui.scm @@ -1,5 +1,5 @@ ;;; GNU Guix --- Functional package management for GNU -;;; Copyright © 2012-2023 Ludovic Courtès <ludo@gnu.org> +;;; Copyright © 2012-2024 Ludovic Courtès <ludo@gnu.org> ;;; Copyright © 2013, 2018 Mark H Weaver <mhw@netris.org> ;;; Copyright © 2013 Nikita Karetnikov <nikita@karetnikov.org> ;;; Copyright © 2014 Cyril Roelandt <tipecaml@gmail.com> @@ -555,7 +555,7 @@ See the \"Application Setup\" section in the manual, for more info.\n")) (leave-on-EPIPE (simple-format #t "~a (~a) ~a~%" command %guix-package-name %guix-version) - (format #t "Copyright ~a 2023 ~a" + (format #t "Copyright ~a 2024 ~a" ;; TRANSLATORS: Translate "(C)" to the copyright symbol ;; (C-in-a-circle), if this symbol is available in the user's ;; locale. Otherwise, do not translate "(C)"; leave it as-is. */ diff --git a/guix/utils.scm b/guix/utils.scm index 7a42b49df2..e4e9d922e7 100644 --- a/guix/utils.scm +++ b/guix/utils.scm @@ -7,7 +7,7 @@ ;;; Copyright © 2015 David Thompson <davet@gnu.org> ;;; Copyright © 2017 Mathieu Othacehe <m.othacehe@gmail.com> ;;; Copyright © 2018, 2020 Marius Bakke <marius@gnu.org> -;;; Copyright © 2020, 2021 Efraim Flashner <efraim@flashner.co.il> +;;; Copyright © 2020, 2021, 2024 Efraim Flashner <efraim@flashner.co.il> ;;; Copyright © 2020, 2021, 2022 Maxim Cournoyer <maxim.cournoyer@gmail.com> ;;; Copyright © 2021 Simon Tournier <zimon.toutoune@gmail.com> ;;; Copyright © 2021 Chris Marusich <cmmarusich@gmail.com> @@ -19,6 +19,7 @@ ;;; Copyright © 2023 Philip McGrath <philip@philipmcgrath.com> ;;; Copyright © 2023 Janneke Nieuwenhuizen <janneke@gnu.org> ;;; Copyright © 2023 Zheng Junjie <873216071@qq.com> +;;; Copyright © 2023 Foundation Devices, Inc. <hello@foundationdevices.com> ;;; ;;; This file is part of GNU Guix. ;;; @@ -96,9 +97,11 @@ target-x86-32? target-x86-64? target-x86? + target-x32? target-arm32? target-aarch64? target-arm? + target-avr? target-ppc32? target-ppc64le? target-powerpc? @@ -632,6 +635,8 @@ returned by `config.guess'." (else triplet)))) (cond ((string-match "^arm[^-]*-([^-]+-)?linux-gnueabihf" triplet) "armhf-linux") + ;; Otherwise it will show up as x86_64-linux... which isn't wrong. + ((string-match "x86_64-linux-gnux32" triplet) "x86_64-linux-gnux32") ((string-match "^([^-]+)-([^-]+-)?linux-gnu.*" triplet) => (lambda (m) @@ -708,6 +713,13 @@ a character other than '@'." architecture (x86_64)?" (string-prefix? "x86_64-" target)) +(define* (target-x32? #:optional (target (or (%current-target-system) + (%current-system)))) + "Is the architecture of TARGET a variant of Intel/AMD's 64-bit +architecture (x86_64) using 32-bit data types?" + (and (target-x86-64? target) + (string-suffix? "gnux32" target))) + (define* (target-x86? #:optional (target (or (%current-target-system) (%current-system)))) (or (target-x86-32? target) (target-x86-64? target))) @@ -724,6 +736,10 @@ architecture (x86_64)?" (%current-system)))) (or (target-arm32? target) (target-aarch64? target))) +(define* (target-avr? #:optional (target (%current-target-system))) + "Is the architecture of TARGET a variant of Microchip's AVR architecture?" + (or (string=? target "avr") (string-prefix? "avr-" target))) + (define* (target-ppc32? #:optional (target (or (%current-target-system) (%current-system)))) (string-prefix? "powerpc-" target)) |