From 64f032d73f83727c0d06a1ea6531c226593ee976 Mon Sep 17 00:00:00 2001 From: raingloom Date: Tue, 13 Oct 2020 09:26:52 +0200 Subject: [PATCH] build-system: Add chicken-build-system. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * guix/build-system/chicken.scm: New file. * guix/build/chicken-build-system.scm: New file. * Makefile.am: Add them. * doc/guix.texi: Document it. Signed-off-by: Ludovic Courtès --- Makefile.am | 2 + doc/guix.texi | 22 +++++ guix/build-system/chicken.scm | 132 +++++++++++++++++++++++++++ guix/build/chicken-build-system.scm | 133 ++++++++++++++++++++++++++++ 4 files changed, 289 insertions(+) create mode 100644 guix/build-system/chicken.scm create mode 100644 guix/build/chicken-build-system.scm diff --git a/Makefile.am b/Makefile.am index fc60d15561..1a3ca227a4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -126,6 +126,7 @@ MODULES = \ guix/build-system/android-ndk.scm \ guix/build-system/ant.scm \ guix/build-system/cargo.scm \ + guix/build-system/chicken.scm \ guix/build-system/clojure.scm \ guix/build-system/cmake.scm \ guix/build-system/dub.scm \ @@ -175,6 +176,7 @@ MODULES = \ guix/build/download-nar.scm \ guix/build/cargo-build-system.scm \ guix/build/cargo-utils.scm \ + guix/build/chicken-build-system.scm \ guix/build/cmake-build-system.scm \ guix/build/dub-build-system.scm \ guix/build/dune-build-system.scm \ diff --git a/doc/guix.texi b/doc/guix.texi index 889f380108..9835d19d2b 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -7335,6 +7335,28 @@ parameters available to cargo. It will also remove an included defined by the crate. @end defvr +@defvr {Scheme Variable} chicken-build-system +This variable is exported by @code{(guix build-system chicken)}. +It builds Chicken Scheme modules (also called ``eggs'' or ``extensions''). +Chicken generates C source code, which then gets compiled by a C compiler, +in this case GCC. + +It adds @code{chicken} to the package inputs, as well as the packages of +@code{gnu-build-system}. + +The build system can't (yet) deduce the egg's name automatically, so just like +with @code{go-build-system} and its @code{#:import-path}, you should define +@code{#:egg-name} in the package's @code{arguments} field. + +For example, if you are packaging the srfi-1 egg: +@lisp +(arguments '(#:egg-name "srfi-1")) +@end lisp + +Egg dependencies must be defined in @code{propagated-inputs}, not @code{inputs} +because Chicken doesn't embed absolute references in compiled eggs. +Test dependecies should go to @code{native-inputs}, as usual. +@end defvr @defvr {Scheme Variable} copy-build-system This variable is exported by @code{(guix build-system copy)}. It diff --git a/guix/build-system/chicken.scm b/guix/build-system/chicken.scm new file mode 100644 index 0000000000..9abae0431a --- /dev/null +++ b/guix/build-system/chicken.scm @@ -0,0 +1,132 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2020 raingloom +;;; +;;; 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 . + +(define-module (guix build-system chicken) + #: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 packages) + #:use-module (ice-9 match) + #:export (%chicken-build-system-modules + chicken-build + chicken-build-system)) + +(define %chicken-build-system-modules + ;; Build-side modules imported and used by default. + `((guix build chicken-build-system) + (guix build union) + ,@%gnu-build-system-modules)) + +(define (default-chicken) + ;; Lazily resolve the binding to avoid a circular dependency. + ;; TODO is this actually needed in every build system? + (let ((chicken (resolve-interface '(gnu packages chicken)))) + (module-ref chicken 'chicken))) + +(define* (lower name + #:key source inputs native-inputs outputs system target + (chicken (default-chicken)) + #:allow-other-keys + #:rest arguments) + "Return a bag for NAME." + (define private-keywords + '(#:source #:target #:chicken #:inputs #:native-inputs)) + + ;; TODO: cross-compilation support + (and (not target) + (bag + (name name) + (system system) + (host-inputs `(,@(if source + `(("source" ,source)) + '()) + ,@inputs + + ;; Keep the standard inputs of 'gnu-build-system', since + ;; Chicken compiles Scheme by using C as an intermediate + ;; language. + ,@(standard-packages))) + (build-inputs `(("chicken" ,chicken) + ,@native-inputs)) + (outputs outputs) + (build chicken-build) + (arguments (strip-keyword-arguments private-keywords arguments))))) + +(define* (chicken-build store name inputs + #:key + (phases '(@ (guix build chicken-build-system) + %standard-phases)) + (outputs '("out")) + (search-paths '()) + (egg-name "") + (unpack-path "") + (build-flags ''()) + (tests? #t) + (system (%current-system)) + (guile #f) + (imported-modules %chicken-build-system-modules) + (modules '((guix build chicken-build-system) + (guix build union) + (guix build utils)))) + (define builder + `(begin + (use-modules ,@modules) + (chicken-build #:name ,name + #:source ,(match (assoc-ref inputs "source") + (((? derivation? source)) + (derivation->output-path source)) + ((source) + source) + (source + source)) + #:system ,system + #:phases ,phases + #:outputs %outputs + #:search-paths ',(map search-path-specification->sexp + search-paths) + #:egg-name ,egg-name + #:unpack-path ,unpack-path + #:build-flags ,build-flags + #:tests? ,tests? + #:inputs %build-inputs))) + + (define guile-for-build + (match guile + ((? package?) + (package-derivation store guile system #:graft? #f)) + (#f ; the default + (let* ((distro (resolve-interface '(gnu packages commencement))) + (guile (module-ref distro 'guile-final))) + (package-derivation store guile system + #:graft? #f))))) + + (build-expression->derivation store name builder + #:inputs inputs + #:system system + #:modules imported-modules + #:outputs outputs + #:guile-for-build guile-for-build)) + +(define chicken-build-system + (build-system + (name 'chicken) + (description + "Build system for Chicken Scheme programs") + (lower lower))) diff --git a/guix/build/chicken-build-system.scm b/guix/build/chicken-build-system.scm new file mode 100644 index 0000000000..5db9906acf --- /dev/null +++ b/guix/build/chicken-build-system.scm @@ -0,0 +1,133 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2020 raingloom +;;; +;;; 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 . + +(define-module (guix build chicken-build-system) + #:use-module ((guix build gnu-build-system) #:prefix gnu:) + #:use-module (guix build union) + #:use-module (guix build utils) + #:use-module (ice-9 match) + #:use-module (ice-9 ftw) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) + #:use-module (rnrs io ports) + #:use-module (rnrs bytevectors) + #:export (%standard-phases + chicken-build)) + +;; CHICKEN_EGG_CACHE is where sources are fetched and binaries are built +;; CHICKEN_INSTALL_REPOSITORY is where dependencies are looked up +;; its first component is also where new eggs are installed. + +;; TODO: deduplicate with go-build-system.scm ? +;; TODO: the binary version should be defined in one of the relevant modules +;; instead of being hardcoded everywhere. Tried to do that but got undefined +;; variable errors. + +(define (chicken-package? name) + (string-prefix? "chicken-" name)) + +(define* (setup-chicken-environment #:key inputs outputs #:allow-other-keys) + (setenv "CHICKEN_INSTALL_REPOSITORY" + (string-concatenate + ;; see TODO item about binary version above + (append (list (assoc-ref outputs "out") "/var/lib/chicken/11/") + (let ((oldenv (getenv "CHICKEN_INSTALL_REPOSITORY"))) + (if oldenv + (list ":" oldenv) + '()))))) + (setenv "CHICKEN_EGG_CACHE" (getcwd)) + #t) + +;; This is copied from go-build-system.scm so it could probably be simplified. +;; I used it because the source of the egg needs to be unpacked into a directory +;; that is named after the egg and I knew that the go build system does that. +(define* (unpack #:key source egg-name unpack-path #:allow-other-keys) + "Relative to $CHICKEN_EGG_CACHE, unpack SOURCE in UNPACK-PATH, or EGG-NAME +when UNPACK-PATH is unset. If the SOURCE archive has a single top level +directory, it is stripped so that the sources appear directly under UNPACK-PATH. +When SOURCE is a directory, copy its content into UNPACK-PATH instead of +unpacking." + (define (unpack-maybe-strip source dest) + (let* ((scratch-dir (string-append (or (getenv "TMPDIR") "/tmp") + "/scratch-dir")) + (out (mkdir-p scratch-dir))) + (with-directory-excursion scratch-dir + (if (string-suffix? ".zip" source) + (invoke "unzip" source) + (invoke "tar" "-xvf" source)) + (let ((top-level-files (remove (lambda (x) + (member x '("." ".."))) + (scandir ".")))) + (match top-level-files + ((top-level-file) + (when (file-is-directory? top-level-file) + (copy-recursively top-level-file dest #:keep-mtime? #t))) + (_ + (copy-recursively "." dest #:keep-mtime? #t))))) + (delete-file-recursively scratch-dir))) + + (when (string-null? egg-name) + (display "WARNING: The egg name is unset.\n")) + (when (string-null? unpack-path) + (set! unpack-path egg-name)) + (let ((dest (string-append (getenv "CHICKEN_EGG_CACHE") "/" unpack-path))) + (mkdir-p dest) + (if (file-is-directory? source) + (copy-recursively source dest #:keep-mtime? #t) + (unpack-maybe-strip source dest))) + #t) + +(define* (build #:key egg-name #:allow-other-keys) + "Build the Chicken egg named by EGG-NAME" + (invoke "chicken-install" "-cached" "-no-install" egg-name)) + +(define* (install #:key egg-name #:allow-other-keys) + "Install the already built egg named by EGG-NAME" + (invoke "chicken-install" "-cached" egg-name)) + +(define* (check #:key egg-name tests? #:allow-other-keys) + "Build and run tests for the Chicken egg EGG-NAME" + ;; there is no "-test-only" option, but we've already run install + ;; so this just runs tests. + ;; i think it's a fair assumption that phases won't be reordered. + (setenv "CHICKEN_REPOSITORY_PATH" + (string-append (getenv "CHICKEN_INSTALL_REPOSITORY") + ":" + (getenv "CHICKEN_REPOSITORY_PATH"))) + (when tests? + (invoke "chicken-install" "-cached" "-test" "-no-install" egg-name))) + +;; It doesn't look like Chicken generates any unnecessary references. +;; So we don't have to remove them either. Nice. + +(define %standard-phases + (modify-phases gnu:%standard-phases + (replace 'unpack unpack) + (delete 'bootstrap) + (delete 'configure) + (delete 'patch-generated-file-shebangs) + (add-before 'unpack 'setup-chicken-environment setup-chicken-environment) + (replace 'build build) + (delete 'check) + (replace 'install install) + (add-after 'install 'check check))) + +(define* (chicken-build #:key inputs (phases %standard-phases) + #:allow-other-keys #:rest args) + "Build the given Chicken package, applying all of PHASES in order." + (apply gnu:gnu-build #:inputs inputs #:phases phases args))