glib-or-gtk-build-system.scm 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2014 Federico Beffa <beffa@fbengineering.ch>
  3. ;;; Copyright © 2014, 2015 Ludovic Courtès <ludo@gnu.org>
  4. ;;; Copyright © 2018 Mark H Weaver <mhw@netris.org>
  5. ;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
  6. ;;;
  7. ;;; This file is part of GNU Guix.
  8. ;;;
  9. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  10. ;;; under the terms of the GNU General Public License as published by
  11. ;;; the Free Software Foundation; either version 3 of the License, or (at
  12. ;;; your option) any later version.
  13. ;;;
  14. ;;; GNU Guix is distributed in the hope that it will be useful, but
  15. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ;;; GNU General Public License for more details.
  18. ;;;
  19. ;;; You should have received a copy of the GNU General Public License
  20. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  21. (define-module (guix build glib-or-gtk-build-system)
  22. #:use-module ((guix build gnu-build-system) #:prefix gnu:)
  23. #:use-module (guix build utils)
  24. #:use-module (ice-9 match)
  25. #:use-module (ice-9 regex)
  26. #:use-module (ice-9 ftw)
  27. #:use-module (srfi srfi-1)
  28. #:use-module (srfi srfi-26)
  29. #:export (%standard-phases
  30. glib-or-gtk-build))
  31. ;; Commentary:
  32. ;;
  33. ;; Builder-side code of the standard glib-or-gtk build procedure.
  34. ;;
  35. ;; Code:
  36. (define (subdirectory-exists? parent sub-directory)
  37. (directory-exists? (string-append parent sub-directory)))
  38. (define (directory-included? directory directories-list)
  39. "Is DIRECTORY included in DIRECTORIES-LIST?"
  40. (fold (lambda (s p) (or (string-ci=? s directory) p))
  41. #f directories-list))
  42. ;; We do not include $HOME/.guix-profile/gtk-v.0 (v=2 or 3) because we do not
  43. ;; want to mix gtk+-2 and gtk+-3 modules. See
  44. ;; https://developer.gnome.org/gtk3/stable/gtk-running.html
  45. (define (gtk-module-directories inputs)
  46. "Check for the existence of \"libdir/gtk-v.0\" in INPUTS. Return a list
  47. with all found directories."
  48. (let* ((version
  49. (if (string-match "gtk\\+-3"
  50. (or (assoc-ref inputs "gtk+")
  51. (assoc-ref inputs "source")
  52. "gtk+-3")) ; we default to version 3
  53. "3.0"
  54. "2.0"))
  55. (gtk-module
  56. (lambda (input prev)
  57. (let* ((in (match input
  58. ((_ . dir) dir)
  59. (_ "")))
  60. (libdir
  61. (string-append in "/lib/gtk-" version)))
  62. (if (and (directory-exists? libdir)
  63. (not (directory-included? libdir prev)))
  64. (cons libdir prev)
  65. prev)))))
  66. (fold gtk-module '() inputs)))
  67. ;; See
  68. ;; http://www.freedesktop.org/wiki/DesktopThemeSpec
  69. ;; http://freedesktop.org/wiki/Specifications/sound-theme-spec
  70. ;; http://freedesktop.org/wiki/Specifications/icon-theme-spec
  71. ;;
  72. ;; Currently desktop themes are not well supported and do not honor
  73. ;; XDG_DATA_DIRS. One example is evince which only looks for desktop themes
  74. ;; in $HOME/.themes (for backward compatibility) and in XDG_DATA_HOME (which
  75. ;; defaults to $HOME/.local/share). One way to handle these applications
  76. ;; appears to be by making $HOME/.themes a symlink to
  77. ;; $HOME/.guix-profile/share/themes.
  78. (define (data-directories inputs)
  79. "Check for the existence of \"$datadir/glib-2.0/schemas\" or XDG themes data
  80. in INPUTS. Return a list with all found directories."
  81. (define (data-directory input previous)
  82. (let* ((in (match input
  83. ((_ . dir) dir)
  84. (_ "")))
  85. (datadir (string-append in "/share")))
  86. (if (and (or (subdirectory-exists? datadir "/glib-2.0/schemas")
  87. (subdirectory-exists? datadir "/sounds")
  88. (subdirectory-exists? datadir "/themes")
  89. (subdirectory-exists? datadir "/cursors")
  90. (subdirectory-exists? datadir "/wallpapers")
  91. (subdirectory-exists? datadir "/icons")
  92. (subdirectory-exists? datadir "/mime")) ;shared-mime-info
  93. (not (directory-included? datadir previous)))
  94. (cons datadir previous)
  95. previous)))
  96. (fold data-directory '() inputs))
  97. ;; All GIO modules are expected to be installed in GLib's $libdir/gio/modules
  98. ;; directory. That directory has to include a file called giomodule.cache
  99. ;; listing all available modules. GIO can be made aware of modules in other
  100. ;; directories with the help of the environment variable GIO_EXTRA_MODULES.
  101. ;; The official GIO documentation states that this environment variable should
  102. ;; only be used for testing and not in a production environment. However, it
  103. ;; appears that there is no other way of specifying multiple modules
  104. ;; directories (NIXOS also does use this variable). See
  105. ;; https://developer.gnome.org/gio/stable/running-gio-apps.html
  106. (define (gio-module-directories inputs)
  107. "Check for the existence of \"$libdir/gio/modules\" in the INPUTS and
  108. returns a list with all found directories."
  109. (define (gio-module-directory input previous)
  110. (let* ((in (match input
  111. ((_ . dir) dir)
  112. (_ "")))
  113. (gio-mod-dir (string-append in "/lib/gio/modules")))
  114. (if (and (directory-exists? gio-mod-dir)
  115. (not (directory-included? gio-mod-dir previous)))
  116. (cons gio-mod-dir previous)
  117. previous)))
  118. (fold gio-module-directory '() inputs))
  119. (define* (wrap-all-programs #:key inputs outputs
  120. (glib-or-gtk-wrap-excluded-outputs '())
  121. #:allow-other-keys)
  122. "Implement phase \"glib-or-gtk-wrap\": look for GSettings schemas and
  123. gtk+-v.0 libraries and create wrappers with suitably set environment variables
  124. if found.
  125. Wrapping is not applied to outputs whose name is listed in
  126. GLIB-OR-GTK-WRAP-EXCLUDED-OUTPUTS. This is useful when an output is known not
  127. to contain any GLib or GTK+ binaries, and where wrapping would gratuitously
  128. add a dependency of that output on GLib and GTK+."
  129. ;; Do not require bash to be present in the package inputs
  130. ;; even when there is nothing to wrap.
  131. ;; Also, calculate (sh) only once to prevent some I/O.
  132. (define %sh (delay (search-input-file inputs "bin/bash")))
  133. (define (sh) (force %sh))
  134. (define handle-output
  135. (match-lambda
  136. ((output . directory)
  137. (unless (member output glib-or-gtk-wrap-excluded-outputs)
  138. (let* ((bindir (string-append directory "/bin"))
  139. (libexecdir (string-append directory "/libexec"))
  140. (bin-list (filter (negate wrapped-program?)
  141. (append (find-files bindir ".*")
  142. (find-files libexecdir ".*"))))
  143. (datadirs (data-directories
  144. (alist-cons output directory inputs)))
  145. (gtk-mod-dirs (gtk-module-directories
  146. (alist-cons output directory inputs)))
  147. (gio-mod-dirs (gio-module-directories
  148. (alist-cons output directory inputs)))
  149. (data-env-var
  150. (if (not (null? datadirs))
  151. `("XDG_DATA_DIRS" ":" prefix ,datadirs)
  152. #f))
  153. (gtk-mod-env-var
  154. (if (not (null? gtk-mod-dirs))
  155. `("GTK_PATH" ":" prefix ,gtk-mod-dirs)
  156. #f))
  157. (gio-mod-env-var
  158. (if (not (null? gio-mod-dirs))
  159. `("GIO_EXTRA_MODULES" ":" prefix ,gio-mod-dirs)
  160. #f)))
  161. (cond
  162. ((and data-env-var gtk-mod-env-var gio-mod-env-var)
  163. (for-each (cut wrap-program <> #:sh (sh)
  164. data-env-var
  165. gtk-mod-env-var
  166. gio-mod-env-var)
  167. bin-list))
  168. ((and data-env-var gtk-mod-env-var (not gio-mod-env-var))
  169. (for-each (cut wrap-program <> #:sh (sh)
  170. data-env-var
  171. gtk-mod-env-var)
  172. bin-list))
  173. ((and data-env-var (not gtk-mod-env-var) gio-mod-env-var)
  174. (for-each (cut wrap-program <> #:sh (sh)
  175. data-env-var
  176. gio-mod-env-var)
  177. bin-list))
  178. ((and (not data-env-var) gtk-mod-env-var gio-mod-env-var)
  179. (for-each (cut wrap-program <> #:sh (sh)
  180. gio-mod-env-var
  181. gtk-mod-env-var)
  182. bin-list))
  183. ((and data-env-var (not gtk-mod-env-var) (not gio-mod-env-var))
  184. (for-each (cut wrap-program <> #:sh (sh)
  185. data-env-var)
  186. bin-list))
  187. ((and (not data-env-var) gtk-mod-env-var (not gio-mod-env-var))
  188. (for-each (cut wrap-program <> #:sh (sh)
  189. gtk-mod-env-var)
  190. bin-list))
  191. ((and (not data-env-var) (not gtk-mod-env-var) gio-mod-env-var)
  192. (for-each (cut wrap-program <> #:sh (sh)
  193. gio-mod-env-var)
  194. bin-list))))))))
  195. (for-each handle-output outputs)
  196. #t)
  197. (define* (compile-glib-schemas #:key outputs #:allow-other-keys)
  198. "Implement phase \"glib-or-gtk-compile-schemas\": compile \"glib\" schemas
  199. if needed."
  200. (for-each (match-lambda
  201. ((output . directory)
  202. (let ((schemasdir (string-append directory
  203. "/share/glib-2.0/schemas")))
  204. (when (and (directory-exists? schemasdir)
  205. (not (file-exists?
  206. (string-append schemasdir "/gschemas.compiled"))))
  207. (invoke "glib-compile-schemas" schemasdir)))))
  208. outputs)
  209. #t)
  210. (define %standard-phases
  211. (modify-phases gnu:%standard-phases
  212. (add-after 'install 'glib-or-gtk-compile-schemas compile-glib-schemas)
  213. (add-after 'install 'glib-or-gtk-wrap wrap-all-programs)))
  214. (define* (glib-or-gtk-build #:key inputs (phases %standard-phases)
  215. #:allow-other-keys #:rest args)
  216. "Build the given package, applying all of PHASES in order."
  217. (apply gnu:gnu-build #:inputs inputs #:phases phases args))
  218. ;;; glib-or-gtk-build-system.scm ends here