diff options
author | Liliana Marie Prikler <liliana.prikler@gmail.com> | 2023-12-20 00:05:21 +0100 |
---|---|---|
committer | Liliana Marie Prikler <liliana.prikler@gmail.com> | 2023-12-20 00:05:21 +0100 |
commit | 24d4d6fdd67561e0de4b1cea6380e43e63d69646 (patch) | |
tree | 9c3f946b6e7c3d67af44cdcd9710ad8320e90080 /guix | |
parent | 92982ecca4efe857666d8b94ad95d2cc7d2ab54b (diff) | |
parent | a512bbd23a2e129cf3d8e71255d504ce8bac77d3 (diff) | |
download | guix-patches-24d4d6fdd67561e0de4b1cea6380e43e63d69646.tar guix-patches-24d4d6fdd67561e0de4b1cea6380e43e63d69646.tar.gz |
Merge branch 'master' into gnome-team
Diffstat (limited to 'guix')
35 files changed, 1689 insertions, 100 deletions
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/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/meson.scm b/guix/build-system/meson.scm index 2d14016b94..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. 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/zig.scm b/guix/build-system/zig.scm index 16b8a712cc..215178ceb4 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 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/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 4afe6d2f87..b2871c3c10 100644 --- a/guix/build/syscalls.scm +++ b/guix/build/syscalls.scm @@ -1098,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. 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 ca984cb49c..723a770e41 100644 --- a/guix/import/cran.scm +++ b/guix/import/cran.scm @@ -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 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/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 b768dddb5f..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)) @@ -867,7 +868,8 @@ identifiers. The result is inferred from the file names of patches." ("unzip" ,(ref '(gnu packages compression) 'unzip)) ("patch" ,(ref '(gnu packages base) 'patch)) ("locales" - ,(parameterize ((%current-target-system #f)) + ,(parameterize ((%current-target-system #f) + (%current-system system)) (canonical ((module-ref (resolve-interface '(gnu packages base)) 'libc-utf8-locales-for-target)))))))) @@ -913,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..4ed5638c14 100644 --- a/guix/platforms/x86.scm +++ b/guix/platforms/x86.scm @@ -30,6 +30,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 +38,26 @@ (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 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/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/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/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/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/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/utils.scm b/guix/utils.scm index 7a42b49df2..8e71f97e1c 100644 --- a/guix/utils.scm +++ b/guix/utils.scm @@ -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. ;;; @@ -99,6 +100,7 @@ target-arm32? target-aarch64? target-arm? + target-avr? target-ppc32? target-ppc64le? target-powerpc? @@ -724,6 +726,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)) |