summaryrefslogtreecommitdiff
path: root/guix/build
diff options
context:
space:
mode:
Diffstat (limited to 'guix/build')
-rw-r--r--guix/build/go-build-system.scm38
-rw-r--r--guix/build/guile-build-system.scm153
-rw-r--r--guix/build/haskell-build-system.scm5
-rw-r--r--guix/build/profiles.scm2
-rw-r--r--guix/build/ruby-build-system.scm111
5 files changed, 234 insertions, 75 deletions
diff --git a/guix/build/go-build-system.scm b/guix/build/go-build-system.scm
index 7c833a616f..6be0167063 100644
--- a/guix/build/go-build-system.scm
+++ b/guix/build/go-build-system.scm
@@ -125,17 +125,17 @@ unset. When SOURCE is a directory, copy it instead of unpacking."
(copy-recursively source dest #:keep-mtime? #t)
#t)
(if (string-suffix? ".zip" source)
- (zero? (system* "unzip" "-d" dest source))
- (zero? (system* "tar" "-C" dest "-xvf" source))))))
+ (invoke "unzip" "-d" dest source)
+ (invoke "tar" "-C" dest "-xvf" source)))))
(define* (install-source #:key install-source? outputs #:allow-other-keys)
"Install the source code to the output directory."
(let* ((out (assoc-ref outputs "out"))
(source "src")
(dest (string-append out "/" source)))
- (if install-source?
- (copy-recursively source dest #:keep-mtime? #t)
- #t)))
+ (when install-source?
+ (copy-recursively source dest #:keep-mtime? #t))
+ #t))
(define (go-package? name)
(string-prefix? "go-" name))
@@ -178,24 +178,26 @@ respectively."
(define* (build #:key import-path #:allow-other-keys)
"Build the package named by IMPORT-PATH."
- (or
- (zero? (system* "go" "install"
- "-v" ; print the name of packages as they are compiled
- "-x" ; print each command as it is invoked
- ;; Respectively, strip the symbol table and debug
- ;; information, and the DWARF symbol table.
- "-ldflags=-s -w"
- import-path))
- (begin
+ (with-throw-handler
+ #t
+ (lambda _
+ (invoke "go" "install"
+ "-v" ; print the name of packages as they are compiled
+ "-x" ; print each command as it is invoked
+ ;; Respectively, strip the symbol table and debug
+ ;; information, and the DWARF symbol table.
+ "-ldflags=-s -w"
+ import-path))
+ (lambda (key . args)
(display (string-append "Building '" import-path "' failed.\n"
"Here are the results of `go env`:\n"))
- (system* "go" "env")
- #f)))
+ (invoke "go" "env"))))
(define* (check #:key tests? import-path #:allow-other-keys)
"Run the tests for the package named by IMPORT-PATH."
- (if tests?
- (zero? (system* "go" "test" import-path))))
+ (when tests?
+ (invoke "go" "test" import-path))
+ #t)
(define* (install #:key outputs #:allow-other-keys)
"Install the compiled libraries. `go install` installs these files to
diff --git a/guix/build/guile-build-system.scm b/guix/build/guile-build-system.scm
new file mode 100644
index 0000000000..0bed049436
--- /dev/null
+++ b/guix/build/guile-build-system.scm
@@ -0,0 +1,153 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2018 Ludovic Courtès <ludo@gnu.org>
+;;;
+;;; 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 guile-build-system)
+ #:use-module ((guix build gnu-build-system) #:prefix gnu:)
+ #:use-module (guix build utils)
+ #:use-module (srfi srfi-26)
+ #:use-module (ice-9 match)
+ #:use-module (ice-9 popen)
+ #:use-module (ice-9 rdelim)
+ #:use-module (guix build utils)
+ #:export (target-guile-effective-version
+ %standard-phases
+ guile-build))
+
+(define* (target-guile-effective-version #:optional guile)
+ "Return the effective version of GUILE or whichever 'guile' is in $PATH.
+Return #false if it cannot be determined."
+ (let* ((pipe (open-pipe* OPEN_READ
+ (if guile
+ (string-append guile "/bin/guile")
+ "guile")
+ "-c" "(display (effective-version))"))
+ (line (read-line pipe)))
+ (and (zero? (close-pipe pipe))
+ (string? line)
+ line)))
+
+(define (file-sans-extension file) ;TODO: factorize
+ "Return the substring of FILE without its extension, if any."
+ (let ((dot (string-rindex file #\.)))
+ (if dot
+ (substring file 0 dot)
+ file)))
+
+(define %scheme-file-regexp
+ ;; Regexp to match Scheme files.
+ "\\.(scm|sls)$")
+
+(define %documentation-file-regexp
+ ;; Regexp to match README files and the likes.
+ "^(README.*|.*\\.html|.*\\.org|.*\\.md)$")
+
+(define* (set-locale-path #:key inputs native-inputs
+ #:allow-other-keys)
+ "Set 'GUIX_LOCPATH'."
+ (match (assoc-ref (or native-inputs inputs) "locales")
+ (#f #t)
+ (locales
+ (setenv "GUIX_LOCPATH" (string-append locales "/lib/locale"))
+ #t)))
+
+(define* (build #:key outputs inputs native-inputs
+ (source-directory ".")
+ (compile-flags '())
+ (scheme-file-regexp %scheme-file-regexp)
+ target
+ #:allow-other-keys)
+ "Build files in SOURCE-DIRECTORY that match SCHEME-FILE-REGEXP."
+ (let* ((out (assoc-ref outputs "out"))
+ (guile (assoc-ref (or native-inputs inputs) "guile"))
+ (effective (target-guile-effective-version guile))
+ (module-dir (string-append out "/share/guile/site/"
+ effective))
+ (go-dir (string-append out "/lib/guile/"
+ effective "/site-ccache/"))
+ (guild (string-append guile "/bin/guild"))
+ (flags (if target
+ (cons (string-append "--target=" target)
+ compile-flags)
+ compile-flags)))
+ (if target
+ (format #t "Cross-compiling for '~a' with Guile ~a...~%"
+ target effective)
+ (format #t "Compiling with Guile ~a...~%" effective))
+ (format #t "compile flags: ~s~%" flags)
+
+ ;; Make installation directories.
+ (mkdir-p module-dir)
+ (mkdir-p go-dir)
+
+ ;; Compile .scm files and install.
+ (setenv "GUILE_AUTO_COMPILE" "0")
+ (setenv "GUILE_LOAD_COMPILED_PATH"
+ (string-append go-dir
+ (match (getenv "GUILE_LOAD_COMPILED_PATH")
+ (#f "")
+ (path (string-append ":" path)))))
+ (for-each (lambda (file)
+ (let* ((go (string-append go-dir
+ (file-sans-extension file)
+ ".go")))
+ ;; Install source module.
+ (install-file (string-append source-directory "/" file)
+ (string-append module-dir
+ "/" (dirname file)))
+
+ ;; Install and compile module.
+ (apply invoke guild "compile" "-L" source-directory
+ "-o" go
+ (string-append source-directory "/" file)
+ flags)))
+
+ ;; Arrange to strip SOURCE-DIRECTORY from file names.
+ (with-directory-excursion source-directory
+ (find-files "." scheme-file-regexp)))
+ #t))
+
+(define* (install-documentation #:key outputs
+ (documentation-file-regexp
+ %documentation-file-regexp)
+ #:allow-other-keys)
+ "Install files that mactch DOCUMENTATION-FILE-REGEXP."
+ (let* ((out (assoc-ref outputs "out"))
+ (doc (string-append out "/share/doc/"
+ (strip-store-file-name out))))
+ (for-each (cut install-file <> doc)
+ (find-files "." documentation-file-regexp))
+ #t))
+
+(define %standard-phases
+ (modify-phases gnu:%standard-phases
+ (delete 'bootstrap)
+ (delete 'configure)
+ (add-before 'install-locale 'set-locale-path
+ set-locale-path)
+ (replace 'build build)
+ (add-after 'build 'install-documentation
+ install-documentation)
+ (delete 'check)
+ (delete 'strip)
+ (delete 'validate-runpath)
+ (delete 'install)))
+
+(define* (guile-build #:key (phases %standard-phases)
+ #:allow-other-keys #:rest args)
+ "Build the given Guile package, applying all of PHASES in order."
+ (apply gnu:gnu-build #:phases phases args))
diff --git a/guix/build/haskell-build-system.scm b/guix/build/haskell-build-system.scm
index 268d59c1be..26519ce5a6 100644
--- a/guix/build/haskell-build-system.scm
+++ b/guix/build/haskell-build-system.scm
@@ -66,7 +66,7 @@
(format #t "running \"runhaskell Setup.hs\" with command ~s \
and parameters ~s~%"
command params)
- (zero? (apply system* "runhaskell" setup-file command params)))
+ (apply invoke "runhaskell" setup-file command params))
(error "no Setup.hs nor Setup.lhs found"))))
(define* (configure #:key outputs inputs tests? (configure-flags '())
@@ -114,7 +114,8 @@ and parameters ~s~%"
(setenv "CONFIG_SHELL" "sh"))
(run-setuphs "configure" params)
- (setenv "GHC_PACKAGE_PATH" ghc-path)))
+ (setenv "GHC_PACKAGE_PATH" ghc-path)
+ #t))
(define* (build #:rest empty)
"Build a given Haskell package."
diff --git a/guix/build/profiles.scm b/guix/build/profiles.scm
index 819688a913..df785c85a7 100644
--- a/guix/build/profiles.scm
+++ b/guix/build/profiles.scm
@@ -89,7 +89,7 @@ definitions for all the SEARCH-PATHS."
# When GUIX_PROFILE is undefined, the various environment variables refer
# to this specific profile generation.
\n" port)
- (let ((variables (evaluate-search-paths (cons $PATH search-paths)
+ (let ((variables (evaluate-search-paths search-paths
(list output))))
(for-each (write-environment-variable-definition port)
(map (abstract-profile output) variables))))))
diff --git a/guix/build/ruby-build-system.scm b/guix/build/ruby-build-system.scm
index abef6937bc..3a658e2557 100644
--- a/guix/build/ruby-build-system.scm
+++ b/guix/build/ruby-build-system.scm
@@ -52,18 +52,19 @@ directory."
(define* (unpack #:key source #:allow-other-keys)
"Unpack the gem SOURCE and enter the resulting directory."
(if (gem-archive? source)
- (and (zero? (system* "gem" "unpack" source))
- ;; The unpacked gem directory is named the same as the archive,
- ;; sans the ".gem" extension. It is renamed to simply "gem" in an
- ;; effort to keep file names shorter to avoid UNIX-domain socket
- ;; file names and shebangs that exceed the system's fixed maximum
- ;; length when running test suites.
- (let ((dir (match:substring (string-match "^(.*)\\.gem$"
- (basename source))
- 1)))
- (rename-file dir "gem")
- (chdir "gem")
- #t))
+ (begin
+ (invoke "gem" "unpack" source)
+ ;; The unpacked gem directory is named the same as the archive,
+ ;; sans the ".gem" extension. It is renamed to simply "gem" in an
+ ;; effort to keep file names shorter to avoid UNIX-domain socket
+ ;; file names and shebangs that exceed the system's fixed maximum
+ ;; length when running test suites.
+ (let ((dir (match:substring (string-match "^(.*)\\.gem$"
+ (basename source))
+ 1)))
+ (rename-file dir "gem")
+ (chdir "gem"))
+ #t)
;; Use GNU unpack strategy for things that aren't gem archives.
(gnu:unpack #:source source)))
@@ -77,7 +78,8 @@ operation is not deterministic, we replace it with `find`."
(when (not (gem-archive? source))
(let ((gemspec (first-gemspec)))
(substitute* gemspec
- (("`git ls-files`") "`find . -type f |sort`"))))
+ (("`git ls-files`") "`find . -type f |sort`")
+ (("`git ls-files -z`") "`find . -type f -print0 |sort -z`"))))
#t)
(define* (extract-gemspec #:key source #:allow-other-keys)
@@ -104,7 +106,8 @@ generate the files list."
(write-char (read-char pipe) out))))
#t)
(lambda ()
- (close-pipe pipe)))))))
+ (close-pipe pipe)))))
+ #t))
(define* (build #:key source #:allow-other-keys)
"Build a new gem using the gemspec from the SOURCE gem."
@@ -112,13 +115,13 @@ generate the files list."
;; Build a new gem from the current working directory. This also allows any
;; dynamic patching done in previous phases to be present in the installed
;; gem.
- (zero? (system* "gem" "build" (first-gemspec))))
+ (invoke "gem" "build" (first-gemspec)))
(define* (check #:key tests? test-target #:allow-other-keys)
"Run the gem's test suite rake task TEST-TARGET. Skip the tests if TESTS?
is #f."
(if tests?
- (zero? (system* "rake" test-target))
+ (invoke "rake" test-target)
#t))
(define* (install #:key inputs outputs (gem-flags '())
@@ -137,43 +140,42 @@ GEM-FLAGS are passed to the 'gem' invokation, if present."
0
(- (string-length gem-file-basename) 4))))
(setenv "GEM_VENDOR" vendor-dir)
- (and (let ((install-succeeded?
- (zero?
- (apply system* "gem" "install" gem-file
- "--local" "--ignore-dependencies" "--vendor"
- ;; Executables should go into /bin, not
- ;; /lib/ruby/gems.
- "--bindir" (string-append out "/bin")
- gem-flags))))
- (or install-succeeded?
- (begin
- (simple-format #t "installation failed\n")
- (let ((failed-output-dir (string-append (getcwd) "/out")))
- (mkdir failed-output-dir)
- (copy-recursively out failed-output-dir))
- #f)))
- (begin
- ;; Remove the cached gem file as this is unnecessary and contains
- ;; timestamped files rendering builds not reproducible.
- (let ((cached-gem (string-append vendor-dir "/cache/" gem-file)))
- (log-file-deletion cached-gem)
- (delete-file cached-gem))
- ;; For gems with native extensions, several Makefile-related files
- ;; are created that contain timestamps or other elements making
- ;; them not reproducible. They are unnecessary so we remove them.
- (if (file-exists? (string-append vendor-dir "/ext"))
- (begin
- (for-each (lambda (file)
- (log-file-deletion file)
- (delete-file file))
- (append
- (find-files (string-append vendor-dir "/doc")
- "page-Makefile.ri")
- (find-files (string-append vendor-dir "/extensions")
- "gem_make.out")
- (find-files (string-append vendor-dir "/ext")
- "Makefile")))))
- #t))))
+
+ (or (zero?
+ (apply system* "gem" "install" gem-file
+ "--local" "--ignore-dependencies" "--vendor"
+ ;; Executables should go into /bin, not
+ ;; /lib/ruby/gems.
+ "--bindir" (string-append out "/bin")
+ gem-flags))
+ (begin
+ (let ((failed-output-dir (string-append (getcwd) "/out")))
+ (mkdir failed-output-dir)
+ (copy-recursively out failed-output-dir))
+ (error "installation failed")))
+
+ ;; Remove the cached gem file as this is unnecessary and contains
+ ;; timestamped files rendering builds not reproducible.
+ (let ((cached-gem (string-append vendor-dir "/cache/" gem-file)))
+ (log-file-deletion cached-gem)
+ (delete-file cached-gem))
+
+ ;; For gems with native extensions, several Makefile-related files
+ ;; are created that contain timestamps or other elements making
+ ;; them not reproducible. They are unnecessary so we remove them.
+ (when (file-exists? (string-append vendor-dir "/ext"))
+ (for-each (lambda (file)
+ (log-file-deletion file)
+ (delete-file file))
+ (append
+ (find-files (string-append vendor-dir "/doc")
+ "page-Makefile.ri")
+ (find-files (string-append vendor-dir "/extensions")
+ "gem_make.out")
+ (find-files (string-append vendor-dir "/ext")
+ "Makefile"))))
+
+ #t))
(define* (wrap-ruby-program prog #:key (gem-clear-paths #t) #:rest vars)
"Make a wrapper for PROG. VARS should look like this:
@@ -301,7 +303,8 @@ extended with definitions for VARS."
(let ((files (list-of-files dir)))
(for-each (cut wrap-ruby-program <> var)
files)))
- bindirs)))
+ bindirs))
+ #t)
(define (log-file-deletion file)
(display (string-append "deleting '" file "' for reproducibility\n")))