search-paths.scm 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2013, 2014, 2015, 2017, 2018 Ludovic Courtès <ludo@gnu.org>
  3. ;;; Copyright © 2022 Maxime Devos <maximedevos@telenet.be>
  4. ;;;
  5. ;;; This file is part of GNU Guix.
  6. ;;;
  7. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  8. ;;; under the terms of the GNU General Public License as published by
  9. ;;; the Free Software Foundation; either version 3 of the License, or (at
  10. ;;; your option) any later version.
  11. ;;;
  12. ;;; GNU Guix is distributed in the hope that it will be useful, but
  13. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;;; GNU General Public License for more details.
  16. ;;;
  17. ;;; You should have received a copy of the GNU General Public License
  18. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  19. (define-module (guix search-paths)
  20. #:use-module (guix records)
  21. #:use-module (guix build utils)
  22. #:use-module (srfi srfi-1)
  23. #:use-module (srfi srfi-26)
  24. #:use-module (ice-9 match)
  25. #:export (<search-path-specification>
  26. search-path-specification
  27. search-path-specification?
  28. search-path-specification-variable
  29. search-path-specification-files
  30. search-path-specification-separator
  31. search-path-specification-file-type
  32. search-path-specification-file-pattern
  33. $PATH
  34. $GUIX_EXTENSIONS_PATH
  35. $PKG_CONFIG_PATH
  36. $SSL_CERT_DIR
  37. $SSL_CERT_FILE
  38. search-path-specification->sexp
  39. sexp->search-path-specification
  40. string-tokenize*
  41. evaluate-search-paths
  42. environment-variable-definition
  43. search-path-definition
  44. set-search-paths))
  45. ;;; Commentary:
  46. ;;;
  47. ;;; This module defines "search path specifications", which allow packages to
  48. ;;; declare environment variables that they use to define search paths. For
  49. ;;; instance, GCC has the 'CPATH' variable, Guile has the 'GUILE_LOAD_PATH'
  50. ;;; variable, etc.
  51. ;;;
  52. ;;; Code:
  53. ;; The specification of a search path.
  54. (define-record-type* <search-path-specification>
  55. search-path-specification make-search-path-specification
  56. search-path-specification?
  57. (variable search-path-specification-variable) ;string
  58. (files search-path-specification-files) ;list of strings
  59. (separator search-path-specification-separator ;string | #f
  60. (default ":"))
  61. (file-type search-path-specification-file-type ;symbol
  62. (default 'directory))
  63. (file-pattern search-path-specification-file-pattern ;#f | string
  64. (default #f)))
  65. (define $PATH
  66. ;; The 'PATH' variable. This variable is a bit special: it is not attached
  67. ;; to any package in particular.
  68. (search-path-specification
  69. (variable "PATH")
  70. (files '("bin" "sbin"))))
  71. (define $GUIX_EXTENSIONS_PATH
  72. ;; 'GUIX_EXTENSIONS_PATH' is used by Guix to locate extension commands.
  73. ;; Unlike 'PATH', it is attached to a package, Guix; however, it is
  74. ;; convenient to define it by default because the 'guix' package is not
  75. ;; supposed to be installed in a profile.
  76. (search-path-specification
  77. (variable "GUIX_EXTENSIONS_PATH")
  78. (files '("share/guix/extensions"))))
  79. (define $PKG_CONFIG_PATH
  80. ;; 'PKG_CONFIG_PATH' is used by pkg-config to locate available header files
  81. ;; and libraries, via their .pc files.
  82. (search-path-specification
  83. (variable "PKG_CONFIG_PATH")
  84. (files '("lib/pkgconfig" "lib64/pkgconfig" "share/pkgconfig"))))
  85. ;; Two variables for certificates (info "(guix)X.509 Certificates"),
  86. ;; respected by OpenSSL and possibly GnuTLS in the future
  87. ;; (https://gitlab.com/gnutls/gnutls/-/merge_requests/1541)
  88. ;; and many of their dependents -- even some GnuTLS dependents
  89. ;; like Guile. As they are not tied to a single package, define
  90. ;; them here to avoid duplication.
  91. ;;
  92. ;; Additionally, the 'native-search-paths' field is not thunked,
  93. ;; so doing (package-native-search-paths openssl)
  94. ;; could cause import cycle issues.
  95. (define $SSL_CERT_DIR
  96. (search-path-specification
  97. (variable "SSL_CERT_DIR")
  98. (separator #f) ;single entry
  99. (files '("etc/ssl/certs"))))
  100. (define $SSL_CERT_FILE
  101. (search-path-specification
  102. (variable "SSL_CERT_FILE")
  103. (file-type 'regular)
  104. (separator #f) ;single entry
  105. (files '("etc/ssl/certs/ca-certificates.crt"))))
  106. (define (search-path-specification->sexp spec)
  107. "Return an sexp representing SPEC, a <search-path-specification>. The sexp
  108. corresponds to the arguments expected by `set-path-environment-variable'."
  109. ;; Note that this sexp format is used both by build systems and in
  110. ;; (guix profiles), so think twice before you change it.
  111. (match spec
  112. (($ <search-path-specification> variable files separator type pattern)
  113. `(,variable ,files ,separator ,type ,pattern))))
  114. (define (sexp->search-path-specification sexp)
  115. "Convert SEXP, which is as returned by 'search-path-specification->sexp', to
  116. a <search-path-specification> object."
  117. (match sexp
  118. ((variable files separator type pattern)
  119. (search-path-specification
  120. (variable variable)
  121. (files files)
  122. (separator separator)
  123. (file-type type)
  124. (file-pattern pattern)))))
  125. (define-syntax-rule (with-null-error-port exp)
  126. "Evaluate EXP with the error port pointing to the bit bucket."
  127. (with-error-to-port (%make-void-port "w")
  128. (lambda () exp)))
  129. ;; XXX: This procedure used to be in (guix utils) but since we want to be able
  130. ;; to use (guix search-paths) on the build side, we want to avoid the
  131. ;; dependency on (guix utils), and so this procedure is back here for now.
  132. (define (string-tokenize* string separator)
  133. "Return the list of substrings of STRING separated by SEPARATOR. This is
  134. like `string-tokenize', but SEPARATOR is a string."
  135. (define (index string what)
  136. (let loop ((string string)
  137. (offset 0))
  138. (cond ((string-null? string)
  139. #f)
  140. ((string-prefix? what string)
  141. offset)
  142. (else
  143. (loop (string-drop string 1) (+ 1 offset))))))
  144. (define len
  145. (string-length separator))
  146. (let loop ((string string)
  147. (result '()))
  148. (cond ((index string separator)
  149. =>
  150. (lambda (offset)
  151. (loop (string-drop string (+ offset len))
  152. (cons (substring string 0 offset)
  153. result))))
  154. (else
  155. (reverse (cons string result))))))
  156. (define* (evaluate-search-paths search-paths directories
  157. #:optional (getenv (const #f)))
  158. "Evaluate SEARCH-PATHS, a list of search-path specifications, for
  159. DIRECTORIES, a list of directory names, and return a list of
  160. specification/value pairs. Use GETENV to determine the current settings and
  161. report only settings not already effective."
  162. (define (search-path-definition spec)
  163. (match spec
  164. (($ <search-path-specification> variable files #f type pattern)
  165. ;; Separator is #f so return the first match.
  166. (match (with-null-error-port
  167. (search-path-as-list files directories
  168. #:type type
  169. #:pattern pattern))
  170. (()
  171. #f)
  172. ((head . _)
  173. (let ((value (getenv variable)))
  174. (if (and value (string=? value head))
  175. #f ;VARIABLE already set appropriately
  176. (cons spec head))))))
  177. (($ <search-path-specification> variable files separator
  178. type pattern)
  179. (let* ((values (or (and=> (getenv variable)
  180. (cut string-tokenize* <> separator))
  181. '()))
  182. ;; XXX: Silence 'find-files' when it stumbles upon non-existent
  183. ;; directories (see
  184. ;; <http://lists.gnu.org/archive/html/guix-devel/2015-01/msg00269.html>.)
  185. (path (with-null-error-port
  186. (search-path-as-list files directories
  187. #:type type
  188. #:pattern pattern))))
  189. (if (every (cut member <> values) path)
  190. #f ;VARIABLE is already set appropriately
  191. (cons spec (string-join path separator)))))))
  192. (filter-map search-path-definition search-paths))
  193. (define* (environment-variable-definition variable value
  194. #:key
  195. (kind 'exact)
  196. (separator ":"))
  197. "Return a the definition of VARIABLE to VALUE in Bash syntax.
  198. KIND can be either 'exact (return the definition of VARIABLE=VALUE),
  199. 'prefix (return the definition where VALUE is added as a prefix to VARIABLE's
  200. current value), or 'suffix (return the definition where VALUE is added as a
  201. suffix to VARIABLE's current value.) In the case of 'prefix and 'suffix,
  202. SEPARATOR is used as the separator between VARIABLE's current value and its
  203. prefix/suffix."
  204. (match (if (not separator) 'exact kind)
  205. ('exact
  206. (format #f "export ~a=\"~a\"" variable value))
  207. ('prefix
  208. (format #f "export ~a=\"~a${~a:+~a}$~a\""
  209. variable value variable separator variable))
  210. ('suffix
  211. (format #f "export ~a=\"$~a${~a:+~a}~a\""
  212. variable variable variable separator value))))
  213. (define* (search-path-definition search-path value
  214. #:key (kind 'exact))
  215. "Similar to 'environment-variable-definition', but applied to a
  216. <search-path-specification>."
  217. (match search-path
  218. (($ <search-path-specification> variable _ separator)
  219. (environment-variable-definition variable value
  220. #:kind kind
  221. #:separator separator))))
  222. (define* (set-search-paths search-paths directories
  223. #:key (setenv setenv))
  224. "Set the search path environment variables specified by SEARCH-PATHS for the
  225. given directories."
  226. (for-each (match-lambda
  227. ((spec . value)
  228. (setenv (search-path-specification-variable spec)
  229. value)))
  230. (evaluate-search-paths search-paths directories)))
  231. ;;; search-paths.scm ends here