;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2013, 2014, 2015, 2016, 2017 Ludovic Courtès ;;; Copyright © 2013 Andreas Enge ;;; Copyright © 2013 Nikita Karetnikov ;;; Copyright © 2017 Federico Beffa ;;; ;;; 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 utils) #:use-module (guix build-system) #:use-module (guix memoization) #:use-module (guix packages) #:use-module (guix ui) #:use-module (guix utils) #:use-module (ice-9 match) #:export (package-with-explicit-compiler)) ;; Note: delay call to 'compiler' until after the 'arguments' field of ;; packages is accessed to avoid a circular dependency when evaluating the ;; top-level of (gnu packages python). For a similar reason we pass the name ;; of the build-system and not the build-system itself. (define* (package-with-explicit-compiler compiler bs-name old-prefix new-prefix #:key variant-property) "Return a procedure of one argument, P. The procedure creates a package with the same fields as P, which is assumed a build-system named BS-NAME, such that it is compiled with COMPILER instead. The inputs are changed recursively accordingly. If the name of P starts with OLD-PREFIX, this is replaced by NEW-PREFIX; otherwise, NEW-PREFIX is prepended to the name. When VARIANT-PROPERTY is present, it is used as a key to search for pre-defined variants of this transformation recorded in the 'properties' field of packages. The property value must be the promise of a package. This is a convenient way for package writers to force the transformation to use pre-defined variants." (define (maybe-force maybe-promise) (if (promise? maybe-promise) (force maybe-promise) maybe-promise)) (define compiler-keyword (case bs-name ((haskell python emacs perl r ruby) (symbol->keyword bs-name)) (else (leave (_ "Operation not supported by the build system: ~A~%") bs-name)))) (define transform ;; Memoize the transformations. Failing to do that, we would build a huge ;; object graph with lots of duplicates, which in turns prevents us from ;; benefiting from memoization in 'package-derivation'. (mlambdaq (p) (let* ((rewrite-if-package (lambda (content) ;; CONTENT may be a file name, in which case it is returned, ;; or a package, which is rewritten with the new COMPILER and ;; NEW-PREFIX. (if (package? content) (transform content) content))) (rewrite (match-lambda ((name content . rest) (append (list name (rewrite-if-package content)) rest))))) (cond ;; If VARIANT-PROPERTY is present, use that. ((and variant-property (assoc-ref (package-properties p) variant-property)) => force) ;; Otherwise build the new package object graph. ((eq? (build-system-name (package-build-system p)) bs-name) (package (inherit p) (location (package-location p)) (name (let ((name (package-name p))) (string-append new-prefix (if (string-prefix? old-prefix name) (substring name (string-length old-prefix)) name)))) (arguments (let ((compiler (maybe-force compiler))) (ensure-keyword-arguments (package-arguments p) `(,compiler-keyword ,compiler)))) (inputs (map rewrite (package-inputs p))) (propagated-inputs (map rewrite (package-propagated-inputs p))) (native-inputs (map rewrite (package-native-inputs p))))) (else p))))) transform)