diff options
Diffstat (limited to 'guix/build')
-rw-r--r-- | guix/build/go-build-system.scm | 38 | ||||
-rw-r--r-- | guix/build/guile-build-system.scm | 153 | ||||
-rw-r--r-- | guix/build/haskell-build-system.scm | 5 | ||||
-rw-r--r-- | guix/build/profiles.scm | 2 | ||||
-rw-r--r-- | guix/build/ruby-build-system.scm | 111 |
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"))) |