build: Honor make's '-j' flag.
[jackhill/guix/guix.git] / guix / modules.scm
CommitLineData
7ca87354 1;;; GNU Guix --- Functional package management for GNU
f9704f17 2;;; Copyright © 2016, 2017 Ludovic Courtès <ludo@gnu.org>
7ca87354
LC
3;;;
4;;; This file is part of GNU Guix.
5;;;
6;;; GNU Guix is free software; you can redistribute it and/or modify it
7;;; under the terms of the GNU General Public License as published by
8;;; the Free Software Foundation; either version 3 of the License, or (at
9;;; your option) any later version.
10;;;
11;;; GNU Guix is distributed in the hope that it will be useful, but
12;;; WITHOUT ANY WARRANTY; without even the implied warranty of
13;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;;; GNU General Public License for more details.
15;;;
16;;; You should have received a copy of the GNU General Public License
17;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
18
19(define-module (guix modules)
f9704f17 20 #:use-module (guix memoization)
7ca87354
LC
21 #:use-module (guix sets)
22 #:use-module (srfi srfi-26)
bfe5264a
LC
23 #:use-module (srfi srfi-34)
24 #:use-module (srfi srfi-35)
7ca87354 25 #:use-module (ice-9 match)
bfe5264a
LC
26 #:export (missing-dependency-error?
27 missing-dependency-module
28
29 source-module-closure
7ca87354
LC
30 live-module-closure
31 guix-module-name?))
32
33;;; Commentary:
34;;;
35;;; This module provides introspection tools for Guile modules at the source
36;;; level. Namely, it allows you to determine the closure of a module; it
37;;; does so just by reading the 'define-module' clause of the module and its
38;;; dependencies. This is primarily useful as an argument to
39;;; 'with-imported-modules'.
40;;;
41;;; Code:
42
bfe5264a
LC
43;; The error corresponding to a missing module.
44(define-condition-type &missing-dependency-error &error
45 missing-dependency-error?
46 (module missing-dependency-module))
47
7ca87354
LC
48(define (colon-symbol? obj)
49 "Return true if OBJ is a symbol that starts with a colon."
50 (and (symbol? obj)
51 (string-prefix? ":" (symbol->string obj))))
52
53(define (colon-symbol->keyword symbol)
54 "Convert SYMBOL to a keyword after stripping its initial ':'."
55 (symbol->keyword
56 (string->symbol (string-drop (symbol->string symbol) 1))))
57
58(define (extract-dependencies clauses)
59 "Return the list of modules imported according to the given 'define-module'
60CLAUSES."
61 (let loop ((clauses clauses)
62 (result '()))
63 (match clauses
64 (()
65 (reverse result))
66 ((#:use-module (module (or #:select #:hide #:prefix #:renamer) _)
67 rest ...)
68 (loop rest (cons module result)))
69 ((#:use-module module rest ...)
70 (loop rest (cons module result)))
71 ((#:autoload module _ rest ...)
72 (loop rest (cons module result)))
73 (((or #:export #:re-export #:export-syntax #:re-export-syntax
74 #:replace #:version)
75 _ rest ...)
76 (loop rest result))
77 (((or #:pure #:no-backtrace) rest ...)
78 (loop rest result))
79 (((? colon-symbol? symbol) rest ...)
80 (loop (cons (colon-symbol->keyword symbol) rest)
81 result)))))
82
83(define module-file-dependencies
55b2d921
LC
84 (mlambda (file)
85 "Return the list of the names of modules that the Guile module in FILE
7ca87354 86depends on."
55b2d921
LC
87 (call-with-input-file file
88 (lambda (port)
89 (match (read port)
90 (('define-module name clauses ...)
91 (extract-dependencies clauses))
92 ;; XXX: R6RS 'library' form is ignored.
93 (_
94 '()))))))
7ca87354
LC
95
96(define (module-name->file-name module)
97 "Return the file name for MODULE."
98 (string-append (string-join (map symbol->string module) "/")
99 ".scm"))
100
101(define (guix-module-name? name)
102 "Return true if NAME (a list of symbols) denotes a Guix or GuixSD module."
103 (match name
104 (('guix _ ...) #t)
105 (('gnu _ ...) #t)
106 (_ #f)))
107
7afc2aab
LC
108(define %source-less-modules
109 ;; These are modules that have no corresponding source files or a source
110 ;; file different from what you'd expect.
111 '((system syntax) ;2.0, defined in boot-9
112 (ice-9 ports internal) ;2.2, defined in (ice-9 ports)
113 (system syntax internal))) ;2.2, defined in boot-9
114
7ca87354
LC
115(define* (source-module-dependencies module #:optional (load-path %load-path))
116 "Return the modules used by MODULE by looking at its source code."
7afc2aab 117 (if (member module %source-less-modules)
7ca87354 118 '()
bfe5264a
LC
119 (match (search-path load-path (module-name->file-name module))
120 ((? string? file)
121 (module-file-dependencies file))
122 (#f
123 (raise (condition (&missing-dependency-error
124 (module module))))))))
7ca87354
LC
125
126(define* (module-closure modules
127 #:key
128 (select? guix-module-name?)
129 (dependencies source-module-dependencies))
130 "Return the closure of MODULES, calling DEPENDENCIES to determine the list
131of modules used by a given module. MODULES and the result are a list of Guile
132module names. Only modules that match SELECT? are considered."
133 (let loop ((modules modules)
134 (result '())
135 (visited (set)))
136 (match modules
137 (()
138 (reverse result))
139 ((module rest ...)
140 (cond ((set-contains? visited module)
141 (loop rest result visited))
142 ((select? module)
143 (loop (append (dependencies module) rest)
144 (cons module result)
145 (set-insert module visited)))
146 (else
147 (loop rest result visited)))))))
148
149(define* (source-module-closure modules
150 #:optional (load-path %load-path)
151 #:key (select? guix-module-name?))
152 "Return the closure of MODULES by reading 'define-module' forms in their
153source code. MODULES and the result are a list of Guile module names. Only
154modules that match SELECT? are considered."
155 (module-closure modules
156 #:dependencies (cut source-module-dependencies <> load-path)
157 #:select? select?))
158
159(define* (live-module-closure modules
160 #:key (select? guix-module-name?))
161 "Return the closure of MODULES, determined by looking at live (loaded)
162module information. MODULES and the result are a list of Guile module names.
163Only modules that match SELECT? are considered."
164 (define (dependencies module)
165 (map module-name
166 (delq the-scm-module (module-uses (resolve-module module)))))
167
168 (module-closure modules
169 #:dependencies dependencies
170 #:select? select?))
171
172;;; modules.scm ends here