all messages for Guix-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* [PATCH] build-system: Add haskell-build-system.
@ 2015-03-27  8:59 Federico Beffa
  2015-03-29 13:44 ` Ludovic Courtès
  0 siblings, 1 reply; 7+ messages in thread
From: Federico Beffa @ 2015-03-27  8:59 UTC (permalink / raw)
  To: Guix-devel

[-- Attachment #1: Type: text/plain, Size: 951 bytes --]

Please find attached a build-system for Haskell. Currently focusing on
GHC, but trying to be flexible for addition of support for other
compilers.

Please note that installed libraries need to be registered in a
compiler specific database. The database consists of a directory with
a configuration file for each library and *a single binary cache*
file. To avoid clashes in profiles, the build system does not create
the cache.

To overcome clash problems: at build time the build system creates a
temporary library database to make GHC find input libraries. However,
when a user installs a library in his profile we need to create a
database cache.

I would like to propose to use the same mechanism as used for the
"dir" file of texinfo.
WDYT?

Binary files seems to include absolute path to libraries and do not
require any special handling. This impression comes from inspecting
haddock's derivation created with this build system.

Regards,
Fede

[-- Attachment #2: 0001-build-system-Add-haskell-build-system.patch --]
[-- Type: text/x-diff, Size: 13698 bytes --]

From b8c6b21e01c6eb7d9c5c7e9ec28a4ac7d12b0628 Mon Sep 17 00:00:00 2001
From: Federico Beffa <beffa@fbengineering.ch>
Date: Fri, 27 Mar 2015 09:36:56 +0100
Subject: [PATCH] build-system: Add haskell-build-system.

* guix/build-system/haskell.scm: New file.
* guix/build/haskell-build-system.scm: New file.
---
 guix/build-system/haskell.scm       | 131 +++++++++++++++++++++++++
 guix/build/haskell-build-system.scm | 190 ++++++++++++++++++++++++++++++++++++
 2 files changed, 321 insertions(+)
 create mode 100644 guix/build-system/haskell.scm
 create mode 100644 guix/build/haskell-build-system.scm

diff --git a/guix/build-system/haskell.scm b/guix/build-system/haskell.scm
new file mode 100644
index 0000000..4c419f1
--- /dev/null
+++ b/guix/build-system/haskell.scm
@@ -0,0 +1,131 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2015 Federico Beffa <beffa@fbengineering.ch>
+;;;
+;;; 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 haskell)
+  #:use-module (guix store)
+  #:use-module (guix utils)
+  #:use-module (guix packages)
+  #:use-module (guix derivations)
+  #:use-module (guix build-system)
+  #:use-module (guix build-system gnu)
+  #:use-module (ice-9 match)
+  #:use-module (srfi srfi-26)
+  #:export (haskell-build
+            haskell-build-system))
+
+;; Commentary:
+;;
+;; Standard build procedure for Haskell packages using 'Setup.hs'.  This is
+;; implemented as an extension of 'gnu-build-system'.
+;;
+;; Code:
+
+(define (default-haskell)
+  "Return the default Haskell package."
+  ;; Lazily resolve the binding to avoid a circular dependency.
+  (let ((haskell (resolve-interface '(gnu packages haskell))))
+    (module-ref haskell 'ghc)))
+
+(define* (lower name
+                #:key source inputs native-inputs outputs system target
+                (haskell (default-haskell))
+                #:allow-other-keys
+                #:rest arguments)
+  "Return a bag for NAME."
+  (define private-keywords
+    '(#:source #:target #:python #: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 `(("haskell" ,haskell)
+                         ,@native-inputs))
+         (outputs outputs)
+         (build haskell-build)
+         (arguments (strip-keyword-arguments private-keywords arguments)))))
+
+(define* (haskell-build store name inputs
+                        #:key
+                        (tests? #t)
+                        (test-target "test")
+                        (configure-flags ''())
+                        (phases '(@ (guix build haskell-build-system)
+                                    %standard-phases))
+                        (outputs '("out"))
+                        (search-paths '())
+                        (system (%current-system))
+                        (guile #f)
+                        (imported-modules '((guix build haskell-build-system)
+                                            (guix build gnu-build-system)
+                                            (guix build utils)))
+                        (modules '((guix build haskell-build-system)
+                                   (guix build utils))))
+  "Build SOURCE using HASKELL, and with INPUTS.  This assumes that SOURCE
+provides a 'Setup.hs' file as its build system."
+  (define builder
+    `(begin
+       (use-modules ,@modules)
+       (haskell-build #:name ,name
+                      #:source ,(match (assoc-ref inputs "source")
+                                  (((? derivation? source))
+                                   (derivation->output-path source))
+                                  ((source)
+                                   source)
+                                  (source
+                                   source))
+                      #:configure-flags ,configure-flags
+                      #:system ,system
+                      #:test-target ,test-target
+                      #:tests? ,tests?
+                      #:phases ,phases
+                      #:outputs %outputs
+                      #:search-paths ',(map search-path-specification->sexp
+                                            search-paths)
+                      #: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 haskell-build-system
+  (build-system
+    (name 'haskell)
+    (description "The standard Haskell build system")
+    (lower lower)))
+
+;;; haskell.scm ends here
diff --git a/guix/build/haskell-build-system.scm b/guix/build/haskell-build-system.scm
new file mode 100644
index 0000000..c8195ee
--- /dev/null
+++ b/guix/build/haskell-build-system.scm
@@ -0,0 +1,190 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2015 Federico Beffa <beffa@fbengineering.ch>
+;;;
+;;; 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 haskell-build-system)
+  #:use-module ((guix build gnu-build-system) #:prefix gnu:)
+  #:use-module (guix build utils)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-26)
+  #:use-module (ice-9 rdelim)
+  #:use-module (ice-9 regex)
+  #:use-module (ice-9 match)
+  #:export (%standard-phases
+            haskell-build))
+
+;; Commentary:
+;;
+;; Builder-side code of the standard Haskell package build procedure.
+;;
+;; Code:
+
+;; Directory where we create the temporary libraries database with its cache
+;; as required by the compiler.
+(define %tmp-db-dir
+  (string-append (or (getenv "TMP") "/tmp")
+                 "/package.conf.d"))
+
+(define (call-setuphs command params)
+  (let ((setup-file (cond
+                     ((file-exists? "Setup.hs")
+                      "Setup.hs")
+                     ((file-exists? "Setup.lhs")
+                      "Setup.lhs")
+                     (else
+                      #f))))
+    (if setup-file
+        (begin
+          (format
+           #t
+           "running \"runhaskell Setup.hs\" with command ~s and parameters ~s~%"
+           command params)
+          (zero? (apply system* "runhaskell" setup-file command params)))
+        (error "no Setup.hs nor Setup.lhs found"))))
+
+(define* (configure #:key outputs inputs tests? (configure-flags '())
+                    #:allow-other-keys)
+  "Install a given Haskell package."
+  (let* ((out (assoc-ref outputs "out"))
+         (input-dirs (match inputs
+                       (((_ . dir) ...)
+                        dir)
+                       (_ '())))
+         (params (append `(,(string-append "--prefix=" out))
+                         `(,(string-append "--package-db=" %tmp-db-dir))
+                         '("--global")
+                         `(,(string-append
+                             "--extra-include-dirs="
+                             (list->search-path-as-string
+                              (search-path-as-list '("include") input-dirs)
+                              ":")))
+                         `(,(string-append
+                             "--extra-lib-dirs="
+                             (list->search-path-as-string
+                              (search-path-as-list '("lib") input-dirs)
+                              ":")))
+                         (if tests?
+                             '("--enable-tests")
+                             '())
+                         configure-flags)))
+    (call-setuphs "configure" params)))
+
+(define* (build #:rest empty)
+  "Build a given Haskell package."
+  (call-setuphs "build" '()))
+
+(define* (install #:rest empty)
+  "Install a given Haskell package."
+  (call-setuphs "copy" '()))
+
+(define (compiler-name-version haskell-input)
+  (let* ((base (basename haskell-input)))
+    (string-drop base
+                 (+ 1 (string-index base #\-)))))
+
+(define (grep rx port)
+  (let ((line (read-line port)))
+    (if (eof-object? line)
+        #f
+        (let ((rx-result (regexp-exec rx line)))
+          (if rx-result
+              (match:substring rx-result 1)
+              (grep rx port))))))
+
+(define* (setup-compiler #:key system inputs outputs #:allow-other-keys)
+  (let* ((haskell (assoc-ref inputs "haskell"))
+         (name-version (compiler-name-version haskell)))
+    (cond
+     ((string-match "ghc" name-version)
+      (setup-ghc system inputs outputs))
+     (else
+      (format #t
+              "Compiler ~a not supported~%" name-version)))))
+
+(define (setup-ghc system inputs outputs)
+  (let* ((haskell  (assoc-ref inputs "haskell"))
+         (input-dirs (match inputs
+                       (((_ . dir) ...)
+                        dir)
+                       (_ '())))
+         (conf-dirs (search-path-as-list
+                     `(,(string-append "lib/" system "-"
+                                       (compiler-name-version haskell)
+                                       "/package.conf.d"))
+                     input-dirs)))
+    (mkdir-p %tmp-db-dir)
+    (for-each
+     (lambda (dir)
+       (let ((conf-files
+              (find-files dir ".*\\.conf")))
+         (unless (null? conf-files)
+           (for-each
+            (lambda (file)
+              (copy-file file (string-append %tmp-db-dir "/" (basename file))))
+            conf-files))))
+     conf-dirs)
+    (zero? (system* "ghc-pkg"
+                    (string-append "--package-db=" %tmp-db-dir)
+                    "recache"))))
+
+(define* (register #:key name system inputs outputs #:allow-other-keys)
+  "Generate the compiler registration file for a given Haskell package.  Don't
+generate the cache as it would clash in user profiles."
+  (let* ((out (assoc-ref outputs "out"))
+         (haskell  (assoc-ref inputs "haskell"))
+         (lib (string-append out "/lib"))
+         (config-dir (string-append lib "/" system
+                                    "-" (compiler-name-version haskell)
+                                    "/package.conf.d"))
+         (id-rx (make-regexp "^id: *(.*)$"))
+         (lib-rx (make-regexp "lib.*\\.(a|so)"))
+         (config-file (string-append config-dir "/" name ".conf"))
+         (params
+          (list (string-append "--gen-pkg-config=" config-file))))
+    (unless (null? (find-files lib lib-rx))
+      (mkdir-p config-dir)
+      (call-setuphs "register" params)
+      (let ((config-file-name+id
+             (call-with-ascii-input-file config-file (cut grep id-rx <>))))
+        (rename-file config-file
+                     (string-append config-dir "/" config-file-name+id
+                                    ".conf"))))
+    #t))
+
+(define* (check #:key tests? test-target #:allow-other-keys)
+  "Run the test suite of a given Haskell package."
+  (if tests?
+      (call-setuphs test-target '())
+      #t))
+
+(define %standard-phases
+  (modify-phases gnu:%standard-phases
+    (add-before configure setup-compiler setup-compiler)
+    (add-after install register register)
+    (replace install install)
+    (replace check check)
+    (replace build build)
+    (replace configure configure)))
+
+(define* (haskell-build #:key inputs (phases %standard-phases)
+                        #:allow-other-keys #:rest args)
+  "Build the given Haskell package, applying all of PHASES in order."
+  (apply gnu:gnu-build
+         #:inputs inputs #:phases phases
+         args))
+
+;;; haskell-build-system.scm ends here
-- 
2.2.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2015-04-02 21:31 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-03-27  8:59 [PATCH] build-system: Add haskell-build-system Federico Beffa
2015-03-29 13:44 ` Ludovic Courtès
2015-03-29 14:00   ` Ricardo Wurmus
2015-03-29 14:45     ` Federico Beffa
2015-03-30  8:16       ` Ludovic Courtès
2015-03-30 16:48         ` Federico Beffa
2015-04-02 21:31           ` Ludovic Courtès

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/guix.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.