guix-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[bug#66801] [PATCH] build-system: Add mix-build-system.


From: Liliana Marie Prikler
Subject: [bug#66801] [PATCH] build-system: Add mix-build-system.
Date: Fri, 08 Dec 2023 08:25:10 +0100
User-agent: Evolution 3.46.4

Am Donnerstag, dem 07.12.2023 um 23:34 +0100 schrieb Pierre-Henry
Fröhring:
> * guix/build-system/mix.scm: New file.
> * guix/build/mix-build-system.scm: New file.
> 
> Change-Id: I8066d00f7ada4a384621bf541e679bc512e93435
> ---
Pretty sure you forgot the reroll-count in the header.  Please don't :)

>  guix/build-system/mix.scm       | 186
> ++++++++++++++++++++++++++++++++
>  guix/build/mix-build-system.scm | 161 +++++++++++++++++++++++++++
>  2 files changed, 347 insertions(+)
>  create mode 100644 guix/build-system/mix.scm
>  create mode 100644 guix/build/mix-build-system.scm
> 
> diff --git a/guix/build-system/mix.scm b/guix/build-system/mix.scm
> new file mode 100644
> index 000000000..1b04053d7
> --- /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 A
> nd
> +  ;; "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/mix-build-system.scm b/guix/build/mix-build-
> system.scm
> new file mode 100644
> index 000000000..fe2e36d18
> --- /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")))
Note that when cross-compiling, elixir would likely be a native-input
rather than an input.  Neither this procedure nor its callers appear to
be aware of that.

You can keep the compose intact if you do
  (and=> (assoc-ref inputs "elixir")
         (compose ...))
Then you can call it as 
  (or (elixir-version native-inputs) (elixir-version inputs))


> +(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
> 
> base-commit: 06f25a9a85be1bbe7a709e58ce41c1a834e5f1ae
Would you be so nice as to send a complete series as a revision?  We
have focused quite a lot on the intricacies of rebar-build-system and
mix-build-system in the past review, but for testing purposes, it would
be nice to have some (minimal set of) packages that we can build with
those improvements.

Cheers

reply via email to

[Prev in Thread] Current Thread [Next in Thread]