gnu-build-system.scm 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Ludovic Courtès <ludo@gnu.org>
  3. ;;; Copyright © 2018 Mark H Weaver <mhw@netris.org>
  4. ;;; Copyright © 2020 Brendan Tildesley <mail@brendan.scot>
  5. ;;;
  6. ;;; This file is part of GNU Guix.
  7. ;;;
  8. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  9. ;;; under the terms of the GNU General Public License as published by
  10. ;;; the Free Software Foundation; either version 3 of the License, or (at
  11. ;;; your option) any later version.
  12. ;;;
  13. ;;; GNU Guix is distributed in the hope that it will be useful, but
  14. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  15. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. ;;; GNU General Public License for more details.
  17. ;;;
  18. ;;; You should have received a copy of the GNU General Public License
  19. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  20. (define-module (guix build gnu-build-system)
  21. #:use-module (guix build utils)
  22. #:use-module (guix build gremlin)
  23. #:use-module (guix elf)
  24. #:use-module (ice-9 ftw)
  25. #:use-module (ice-9 match)
  26. #:use-module (ice-9 regex)
  27. #:use-module (ice-9 format)
  28. #:use-module (ice-9 ftw)
  29. #:use-module (srfi srfi-1)
  30. #:use-module (srfi srfi-19)
  31. #:use-module (srfi srfi-34)
  32. #:use-module (srfi srfi-35)
  33. #:use-module (srfi srfi-26)
  34. #:use-module (rnrs io ports)
  35. #:export (%standard-phases
  36. %license-file-regexp
  37. dump-file-contents
  38. gnu-build))
  39. ;; Commentary:
  40. ;;
  41. ;; Standard build procedure for packages using the GNU Build System or
  42. ;; something compatible ("./configure && make && make install"). This is the
  43. ;; builder-side code.
  44. ;;
  45. ;; Code:
  46. (cond-expand
  47. (guile-2.2
  48. ;; Guile 2.2.2 has a bug whereby 'time-monotonic' objects have seconds and
  49. ;; nanoseconds swapped (fixed in Guile commit 886ac3e). Work around it.
  50. (define time-monotonic time-tai))
  51. (else #t))
  52. (define* (set-SOURCE-DATE-EPOCH #:rest _)
  53. "Set the 'SOURCE_DATE_EPOCH' environment variable. This is used by tools
  54. that incorporate timestamps as a way to tell them to use a fixed timestamp.
  55. See https://reproducible-builds.org/specs/source-date-epoch/."
  56. (setenv "SOURCE_DATE_EPOCH" "1")
  57. #t)
  58. (define (first-subdirectory directory)
  59. "Return the file name of the first sub-directory of DIRECTORY."
  60. (match (scandir directory
  61. (lambda (file)
  62. (and (not (member file '("." "..")))
  63. (file-is-directory? (string-append directory "/"
  64. file)))))
  65. ((first . _) first)))
  66. (define* (set-paths #:key target inputs native-inputs
  67. (search-paths '()) (native-search-paths '())
  68. #:allow-other-keys)
  69. (define input-directories
  70. (match inputs
  71. (((_ . dir) ...)
  72. dir)))
  73. (define native-input-directories
  74. (match native-inputs
  75. (((_ . dir) ...)
  76. dir)
  77. (#f ; not cross compiling
  78. '())))
  79. ;; Tell 'ld-wrapper' to disallow non-store libraries.
  80. (setenv "GUIX_LD_WRAPPER_ALLOW_IMPURITIES" "no")
  81. ;; When cross building, $PATH must refer only to native (host) inputs since
  82. ;; target inputs are not executable.
  83. (set-path-environment-variable "PATH" '("bin" "sbin")
  84. (append native-input-directories
  85. (if target
  86. '()
  87. input-directories)))
  88. (for-each (match-lambda
  89. ((env-var (files ...) separator type pattern)
  90. (set-path-environment-variable env-var files
  91. input-directories
  92. #:separator separator
  93. #:type type
  94. #:pattern pattern)))
  95. search-paths)
  96. (when native-search-paths
  97. ;; Search paths for native inputs, when cross building.
  98. (for-each (match-lambda
  99. ((env-var (files ...) separator type pattern)
  100. (set-path-environment-variable env-var files
  101. native-input-directories
  102. #:separator separator
  103. #:type type
  104. #:pattern pattern)))
  105. native-search-paths))
  106. #t)
  107. (define* (install-locale #:key
  108. (locale "en_US.utf8")
  109. (locale-category LC_ALL)
  110. #:allow-other-keys)
  111. "Try to install LOCALE; emit a warning if that fails. The main goal is to
  112. use a UTF-8 locale so that Guile correctly interprets UTF-8 file names.
  113. This phase must typically happen after 'set-paths' so that $LOCPATH has a
  114. chance to be set."
  115. (catch 'system-error
  116. (lambda ()
  117. (setlocale locale-category locale)
  118. ;; While we're at it, pass it to sub-processes.
  119. (setenv (locale-category->string locale-category) locale)
  120. (format (current-error-port) "using '~a' locale for category ~s~%"
  121. locale (locale-category->string locale-category))
  122. #t)
  123. (lambda args
  124. ;; This is known to fail for instance in early bootstrap where locales
  125. ;; are not available.
  126. (format (current-error-port)
  127. "warning: failed to install '~a' locale: ~a~%"
  128. locale (strerror (system-error-errno args)))
  129. #t)))
  130. (define* (unpack #:key source #:allow-other-keys)
  131. "Unpack SOURCE in the working directory, and change directory within the
  132. source. When SOURCE is a directory, copy it in a sub-directory of the current
  133. working directory."
  134. (if (file-is-directory? source)
  135. (begin
  136. (mkdir "source")
  137. (chdir "source")
  138. ;; Preserve timestamps (set to the Epoch) on the copied tree so that
  139. ;; things work deterministically.
  140. (copy-recursively source "."
  141. #:keep-mtime? #t))
  142. (begin
  143. (if (string-suffix? ".zip" source)
  144. (invoke "unzip" source)
  145. (invoke "tar" "xvf" source))
  146. (chdir (first-subdirectory "."))))
  147. #t)
  148. (define %bootstrap-scripts
  149. ;; Typical names of Autotools "bootstrap" scripts.
  150. '("bootstrap" "bootstrap.sh" "autogen.sh"))
  151. (define* (bootstrap #:key (bootstrap-scripts %bootstrap-scripts)
  152. #:allow-other-keys)
  153. "If the code uses Autotools and \"configure\" is missing, run
  154. \"autoreconf\". Otherwise do nothing."
  155. ;; Note: Run that right after 'unpack' so that the generated files are
  156. ;; visible when the 'patch-source-shebangs' phase runs.
  157. (define (script-exists? file)
  158. (and (file-exists? file)
  159. (not (file-is-directory? file))))
  160. (if (not (script-exists? "configure"))
  161. ;; First try one of the BOOTSTRAP-SCRIPTS. If none exists, and it's
  162. ;; clearly an Autoconf-based project, run 'autoreconf'. Otherwise, do
  163. ;; nothing (perhaps the user removed or overrode the 'configure' phase.)
  164. (let ((script (find script-exists? bootstrap-scripts)))
  165. ;; GNU packages often invoke the 'git-version-gen' script from
  166. ;; 'configure.ac' so make sure it has a valid shebang.
  167. (false-if-file-not-found
  168. (patch-shebang "build-aux/git-version-gen"))
  169. (if script
  170. (let ((script (string-append "./" script)))
  171. (setenv "NOCONFIGURE" "true")
  172. (format #t "running '~a'~%" script)
  173. (if (executable-file? script)
  174. (begin
  175. (patch-shebang script)
  176. (invoke script))
  177. (invoke "sh" script))
  178. ;; Let's clean up after ourselves.
  179. (unsetenv "NOCONFIGURE"))
  180. (if (or (file-exists? "configure.ac")
  181. (file-exists? "configure.in"))
  182. (invoke "autoreconf" "-vif")
  183. (format #t "no 'configure.ac' or anything like that, \
  184. doing nothing~%"))))
  185. (format #t "GNU build system bootstrapping not needed~%"))
  186. #t)
  187. ;; See <http://bugs.gnu.org/17840>.
  188. (define* (patch-usr-bin-file #:key native-inputs inputs
  189. (patch-/usr/bin/file? #t)
  190. #:allow-other-keys)
  191. "Patch occurrences of \"/usr/bin/file\" in all the executable 'configure'
  192. files found in the source tree. This works around Libtool's Autoconf macros,
  193. which generates invocations of \"/usr/bin/file\" that are used to determine
  194. things like the ABI being used."
  195. (when patch-/usr/bin/file?
  196. (for-each (lambda (file)
  197. (when (executable-file? file)
  198. (patch-/usr/bin/file file)))
  199. (find-files "." "^configure$")))
  200. #t)
  201. (define* (patch-source-shebangs #:key source #:allow-other-keys)
  202. "Patch shebangs in all source files; this includes non-executable
  203. files such as `.in' templates. Most scripts honor $SHELL and
  204. $CONFIG_SHELL, but some don't, such as `mkinstalldirs' or Automake's
  205. `missing' script."
  206. (for-each patch-shebang
  207. (find-files "."
  208. (lambda (file stat)
  209. ;; Filter out symlinks.
  210. (eq? 'regular (stat:type stat)))
  211. #:stat lstat))
  212. #t)
  213. (define (patch-generated-file-shebangs . rest)
  214. "Patch shebangs in generated files, including `SHELL' variables in
  215. makefiles."
  216. ;; Patch executable regular files, some of which might have been generated
  217. ;; by `configure'.
  218. (for-each patch-shebang
  219. (find-files "."
  220. (lambda (file stat)
  221. (and (eq? 'regular (stat:type stat))
  222. (not (zero? (logand (stat:mode stat) #o100)))))
  223. #:stat lstat))
  224. ;; Patch `SHELL' in generated makefiles.
  225. (for-each patch-makefile-SHELL (find-files "." "^(GNU)?[mM]akefile$"))
  226. #t)
  227. (define* (configure #:key build target native-inputs inputs outputs
  228. (configure-flags '()) out-of-source?
  229. #:allow-other-keys)
  230. (define (package-name)
  231. (let* ((out (assoc-ref outputs "out"))
  232. (base (basename out))
  233. (dash (string-rindex base #\-)))
  234. ;; XXX: We'd rather use `package-name->name+version' or similar.
  235. (string-drop (if dash
  236. (substring base 0 dash)
  237. base)
  238. (+ 1 (string-index base #\-)))))
  239. (let* ((prefix (assoc-ref outputs "out"))
  240. (bindir (assoc-ref outputs "bin"))
  241. (libdir (assoc-ref outputs "lib"))
  242. (includedir (assoc-ref outputs "include"))
  243. (docdir (assoc-ref outputs "doc"))
  244. (bash (or (and=> (assoc-ref (or native-inputs inputs) "bash")
  245. (cut string-append <> "/bin/bash"))
  246. "/bin/sh"))
  247. (flags `(,@(if target ; cross building
  248. '("CC_FOR_BUILD=gcc")
  249. '())
  250. ,(string-append "CONFIG_SHELL=" bash)
  251. ,(string-append "SHELL=" bash)
  252. ,(string-append "--prefix=" prefix)
  253. "--enable-fast-install" ; when using Libtool
  254. ;; Produce multiple outputs when specific output names
  255. ;; are recognized.
  256. ,@(if bindir
  257. (list (string-append "--bindir=" bindir "/bin"))
  258. '())
  259. ,@(if libdir
  260. (cons (string-append "--libdir=" libdir "/lib")
  261. (if includedir
  262. '()
  263. (list
  264. (string-append "--includedir="
  265. libdir "/include"))))
  266. '())
  267. ,@(if includedir
  268. (list (string-append "--includedir="
  269. includedir "/include"))
  270. '())
  271. ,@(if docdir
  272. (list (string-append "--docdir=" docdir
  273. "/share/doc/" (package-name)))
  274. '())
  275. ,@(if build
  276. (list (string-append "--build=" build))
  277. '())
  278. ,@(if target ; cross building
  279. (list (string-append "--host=" target))
  280. '())
  281. ,@configure-flags))
  282. (abs-srcdir (getcwd))
  283. (srcdir (if out-of-source?
  284. (string-append "../" (basename abs-srcdir))
  285. ".")))
  286. (format #t "source directory: ~s (relative from build: ~s)~%"
  287. abs-srcdir srcdir)
  288. (if out-of-source?
  289. (begin
  290. (mkdir "../build")
  291. (chdir "../build")))
  292. (format #t "build directory: ~s~%" (getcwd))
  293. (format #t "configure flags: ~s~%" flags)
  294. ;; Use BASH to reduce reliance on /bin/sh since it may not always be
  295. ;; reliable (see
  296. ;; <http://thread.gmane.org/gmane.linux.distributions.nixos/9748>
  297. ;; for a summary of the situation.)
  298. ;;
  299. ;; Call `configure' with a relative path. Otherwise, GCC's build system
  300. ;; (for instance) records absolute source file names, which typically
  301. ;; contain the hash part of the `.drv' file, leading to a reference leak.
  302. (apply invoke bash
  303. (string-append srcdir "/configure")
  304. flags)))
  305. (define* (build #:key (make-flags '()) (parallel-build? #t)
  306. #:allow-other-keys)
  307. (apply invoke "make"
  308. `(,@(if parallel-build?
  309. `("-j" ,(number->string (parallel-job-count)))
  310. '())
  311. ,@make-flags)))
  312. (define* (dump-file-contents directory file-regexp
  313. #:optional (port (current-error-port)))
  314. "Dump to PORT the contents of files in DIRECTORY that match FILE-REGEXP."
  315. (define (dump file)
  316. (let ((prefix (string-append "\n--- " file " ")))
  317. (display (if (< (string-length prefix) 78)
  318. (string-pad-right prefix 78 #\-)
  319. prefix)
  320. port)
  321. (display "\n\n" port)
  322. (call-with-input-file file
  323. (lambda (log)
  324. (dump-port log port)))
  325. (display "\n" port)))
  326. (for-each dump (find-files directory file-regexp)))
  327. (define %test-suite-log-regexp
  328. ;; Name of test suite log files as commonly found in GNU-based build systems
  329. ;; and CMake.
  330. "^(test-?suite\\.log|LastTestFailed\\.log)$")
  331. (define* (check #:key target (make-flags '()) (tests? (not target))
  332. (test-target "check") (parallel-tests? #t)
  333. (test-suite-log-regexp %test-suite-log-regexp)
  334. #:allow-other-keys)
  335. (if tests?
  336. (guard (c ((invoke-error? c)
  337. ;; Dump the test suite log to facilitate debugging.
  338. (display "\nTest suite failed, dumping logs.\n"
  339. (current-error-port))
  340. (dump-file-contents "." test-suite-log-regexp)
  341. (raise c)))
  342. (apply invoke "make" test-target
  343. `(,@(if parallel-tests?
  344. `("-j" ,(number->string (parallel-job-count)))
  345. '())
  346. ,@make-flags)))
  347. (format #t "test suite not run~%"))
  348. #t)
  349. (define* (install #:key (make-flags '()) #:allow-other-keys)
  350. (apply invoke "make" "install" make-flags))
  351. (define* (patch-shebangs #:key inputs outputs (patch-shebangs? #t)
  352. #:allow-other-keys)
  353. (define (list-of-files dir)
  354. (map (cut string-append dir "/" <>)
  355. (or (scandir dir (lambda (f)
  356. (let ((s (lstat (string-append dir "/" f))))
  357. (eq? 'regular (stat:type s)))))
  358. '())))
  359. (define bin-directories
  360. (match-lambda
  361. ((_ . dir)
  362. (list (string-append dir "/bin")
  363. (string-append dir "/sbin")))))
  364. (define output-bindirs
  365. (append-map bin-directories outputs))
  366. (define input-bindirs
  367. ;; Shebangs should refer to binaries of the target system---i.e., from
  368. ;; "inputs", not from "native-inputs".
  369. (append-map bin-directories inputs))
  370. (when patch-shebangs?
  371. (let ((path (append output-bindirs input-bindirs)))
  372. (for-each (lambda (dir)
  373. (let ((files (list-of-files dir)))
  374. (for-each (cut patch-shebang <> path) files)))
  375. output-bindirs)))
  376. #t)
  377. (define* (strip #:key target outputs (strip-binaries? #t)
  378. (strip-command (if target
  379. (string-append target "-strip")
  380. "strip"))
  381. (objcopy-command (if target
  382. (string-append target "-objcopy")
  383. "objcopy"))
  384. (strip-flags '("--strip-debug"
  385. "--enable-deterministic-archives"))
  386. (strip-directories '("lib" "lib64" "libexec"
  387. "bin" "sbin"))
  388. #:allow-other-keys)
  389. (define debug-output
  390. ;; If an output is called "debug", then that's where debugging information
  391. ;; will be stored instead of being discarded.
  392. (assoc-ref outputs "debug"))
  393. (define debug-file-extension
  394. ;; File name extension for debugging information.
  395. ".debug")
  396. (define (debug-file file)
  397. ;; Return the name of the debug file for FILE, an absolute file name.
  398. ;; Once installed in the user's profile, it is in $PROFILE/lib/debug/FILE,
  399. ;; which is where GDB looks for it (info "(gdb) Separate Debug Files").
  400. (string-append debug-output "/lib/debug/"
  401. file debug-file-extension))
  402. (define (make-debug-file file)
  403. ;; Create a file in DEBUG-OUTPUT containing the debugging info of FILE.
  404. (let ((debug (debug-file file)))
  405. (mkdir-p (dirname debug))
  406. (copy-file file debug)
  407. (invoke strip-command "--only-keep-debug" debug)
  408. (chmod debug #o400)))
  409. (define (add-debug-link file)
  410. ;; Add a debug link in FILE (info "(binutils) strip").
  411. ;; `objcopy --add-gnu-debuglink' wants to have the target of the debug
  412. ;; link around so it can compute a CRC of that file (see the
  413. ;; `bfd_fill_in_gnu_debuglink_section' function.) No reference to
  414. ;; DEBUG-OUTPUT is kept because bfd keeps only the basename of the debug
  415. ;; file.
  416. (invoke objcopy-command "--enable-deterministic-archives"
  417. (string-append "--add-gnu-debuglink="
  418. (debug-file file))
  419. file))
  420. (define (strip-dir dir)
  421. (format #t "stripping binaries in ~s with ~s and flags ~s~%"
  422. dir strip-command strip-flags)
  423. (when debug-output
  424. (format #t "debugging output written to ~s using ~s~%"
  425. debug-output objcopy-command))
  426. (for-each (lambda (file)
  427. (when (or (elf-file? file) (ar-file? file))
  428. ;; If an error occurs while processing a file, issue a
  429. ;; warning and continue to the next file.
  430. (guard (c ((invoke-error? c)
  431. (format (current-error-port)
  432. "warning: ~a: program ~s exited\
  433. ~@[ with non-zero exit status ~a~]\
  434. ~@[ terminated by signal ~a~]~%"
  435. file
  436. (invoke-error-program c)
  437. (invoke-error-exit-status c)
  438. (invoke-error-term-signal c))))
  439. (when debug-output
  440. (make-debug-file file))
  441. ;; Ensure the file is writable.
  442. (make-file-writable file)
  443. (apply invoke strip-command
  444. (append strip-flags (list file)))
  445. (when debug-output
  446. (add-debug-link file)))))
  447. (find-files dir
  448. (lambda (file stat)
  449. ;; Ignore symlinks such as:
  450. ;; libfoo.so -> libfoo.so.0.0.
  451. (eq? 'regular (stat:type stat)))
  452. #:stat lstat)))
  453. (when strip-binaries?
  454. (for-each
  455. strip-dir
  456. (append-map (match-lambda
  457. ((_ . dir)
  458. (filter-map (lambda (d)
  459. (let ((sub (string-append dir "/" d)))
  460. (and (directory-exists? sub) sub)))
  461. strip-directories)))
  462. outputs)))
  463. #t)
  464. (define* (validate-runpath #:key
  465. (validate-runpath? #t)
  466. (elf-directories '("lib" "lib64" "libexec"
  467. "bin" "sbin"))
  468. outputs #:allow-other-keys)
  469. "When VALIDATE-RUNPATH? is true, validate that all the ELF files in
  470. ELF-DIRECTORIES have their dependencies found in their 'RUNPATH'.
  471. Since the ELF parser needs to have a copy of files in memory, better run this
  472. phase after stripping."
  473. (define (sub-directory parent)
  474. (lambda (directory)
  475. (let ((directory (string-append parent "/" directory)))
  476. (and (directory-exists? directory) directory))))
  477. (define (validate directory)
  478. (define (file=? file1 file2)
  479. (let ((st1 (stat file1))
  480. (st2 (stat file2)))
  481. (= (stat:ino st1) (stat:ino st2))))
  482. ;; There are always symlinks from '.so' to '.so.1' and so on, so delete
  483. ;; duplicates.
  484. (let ((files (delete-duplicates (find-files directory (lambda (file stat)
  485. (elf-file? file)))
  486. file=?)))
  487. (format (current-error-port)
  488. "validating RUNPATH of ~a binaries in ~s...~%"
  489. (length files) directory)
  490. (every* validate-needed-in-runpath files)))
  491. (if validate-runpath?
  492. (let ((dirs (append-map (match-lambda
  493. (("debug" . _)
  494. ;; The "debug" output is full of ELF files
  495. ;; that are not worth checking.
  496. '())
  497. ((name . output)
  498. (filter-map (sub-directory output)
  499. elf-directories)))
  500. outputs)))
  501. (unless (every* validate dirs)
  502. (error "RUNPATH validation failed")))
  503. (format (current-error-port) "skipping RUNPATH validation~%"))
  504. #t)
  505. (define* (validate-documentation-location #:key outputs
  506. #:allow-other-keys)
  507. "Documentation should go to 'share/info' and 'share/man', not just 'info/'
  508. and 'man/'. This phase moves directories to the right place if needed."
  509. (define (validate-sub-directory output sub-directory)
  510. (let ((directory (string-append output "/" sub-directory)))
  511. (when (directory-exists? directory)
  512. (let ((target (string-append output "/share/" sub-directory)))
  513. (format #t "moving '~a' to '~a'~%" directory target)
  514. (mkdir-p (dirname target))
  515. (rename-file directory target)))))
  516. (define (validate-output output)
  517. (for-each (cut validate-sub-directory output <>)
  518. '("man" "info")))
  519. (match outputs
  520. (((names . directories) ...)
  521. (for-each validate-output directories)))
  522. #t)
  523. (define* (reset-gzip-timestamps #:key outputs #:allow-other-keys)
  524. "Reset embedded timestamps in gzip files found in OUTPUTS."
  525. (define (process-directory directory)
  526. (let ((files (find-files directory
  527. (lambda (file stat)
  528. (and (eq? 'regular (stat:type stat))
  529. (or (string-suffix? ".gz" file)
  530. (string-suffix? ".tgz" file))
  531. (gzip-file? file)))
  532. #:stat lstat)))
  533. (for-each reset-gzip-timestamp files)))
  534. (match outputs
  535. (((names . directories) ...)
  536. (for-each process-directory directories)))
  537. #t)
  538. (define* (compress-documentation #:key outputs
  539. (compress-documentation? #t)
  540. (documentation-compressor "gzip")
  541. (documentation-compressor-flags
  542. '("--best" "--no-name"))
  543. (compressed-documentation-extension ".gz")
  544. #:allow-other-keys)
  545. "When COMPRESS-DOCUMENTATION? is true, compress man pages and Info files
  546. found in OUTPUTS using DOCUMENTATION-COMPRESSOR, called with
  547. DOCUMENTATION-COMPRESSOR-FLAGS."
  548. (define (retarget-symlink link)
  549. (let ((target (readlink link)))
  550. (delete-file link)
  551. (symlink (string-append target compressed-documentation-extension)
  552. link)))
  553. (define (has-links? file)
  554. ;; Return #t if FILE has hard links.
  555. (> (stat:nlink (lstat file)) 1))
  556. (define (points-to-symlink? symlink)
  557. ;; Return #t if SYMLINK points to another symbolic link.
  558. (let* ((target (readlink symlink))
  559. (target-absolute (if (string-prefix? "/" target)
  560. target
  561. (string-append (dirname symlink)
  562. "/" target))))
  563. (catch 'system-error
  564. (lambda ()
  565. (symbolic-link? target-absolute))
  566. (lambda args
  567. (if (= ENOENT (system-error-errno args))
  568. (begin
  569. (format (current-error-port)
  570. "The symbolic link '~a' target is missing: '~a'\n"
  571. symlink target-absolute)
  572. #f)
  573. (apply throw args))))))
  574. (define (maybe-compress-directory directory regexp)
  575. (when (directory-exists? directory)
  576. (match (find-files directory regexp)
  577. (() ;nothing to compress
  578. #t)
  579. ((files ...) ;one or more files
  580. (format #t
  581. "compressing documentation in '~a' with ~s and flags ~s~%"
  582. directory documentation-compressor
  583. documentation-compressor-flags)
  584. (call-with-values
  585. (lambda ()
  586. (partition symbolic-link? files))
  587. (lambda (symlinks regular-files)
  588. ;; Compress the non-symlink files, and adjust symlinks to refer
  589. ;; to the compressed files. Leave files that have hard links
  590. ;; unchanged ('gzip' would refuse to compress them anyway.)
  591. ;; Also, do not retarget symbolic links pointing to other
  592. ;; symbolic links, since these are not compressed.
  593. (for-each retarget-symlink
  594. (filter (lambda (symlink)
  595. (and (not (points-to-symlink? symlink))
  596. (string-match regexp symlink)))
  597. symlinks))
  598. (apply invoke documentation-compressor
  599. (append documentation-compressor-flags
  600. (remove has-links? regular-files)))))))))
  601. (define (maybe-compress output)
  602. (maybe-compress-directory (string-append output "/share/man")
  603. "\\.[0-9]+$")
  604. (maybe-compress-directory (string-append output "/share/info")
  605. "\\.info(-[0-9]+)?$"))
  606. (if compress-documentation?
  607. (match outputs
  608. (((names . directories) ...)
  609. (for-each maybe-compress directories)))
  610. (format #t "not compressing documentation~%"))
  611. #t)
  612. (define* (delete-info-dir-file #:key outputs #:allow-other-keys)
  613. "Delete any 'share/info/dir' file from OUTPUTS."
  614. (for-each (match-lambda
  615. ((output . directory)
  616. (let ((info-dir-file (string-append directory "/share/info/dir")))
  617. (when (file-exists? info-dir-file)
  618. (delete-file info-dir-file)))))
  619. outputs)
  620. #t)
  621. (define* (patch-dot-desktop-files #:key outputs inputs #:allow-other-keys)
  622. "Replace any references to executables in '.desktop' files with their
  623. absolute file names."
  624. (define bin-directories
  625. (append-map (match-lambda
  626. ((_ . directory)
  627. (list (string-append directory "/bin")
  628. (string-append directory "/sbin"))))
  629. outputs))
  630. (define (which program)
  631. (or (search-path bin-directories program)
  632. (begin
  633. (format (current-error-port)
  634. "warning: '.desktop' file refers to '~a', \
  635. which cannot be found~%"
  636. program)
  637. program)))
  638. (for-each (match-lambda
  639. ((_ . directory)
  640. (let ((applications (string-append directory
  641. "/share/applications")))
  642. (when (directory-exists? applications)
  643. (let ((files (find-files applications "\\.desktop$")))
  644. (format #t "adjusting ~a '.desktop' files in ~s~%"
  645. (length files) applications)
  646. ;; '.desktop' files contain translations and are always
  647. ;; UTF-8-encoded.
  648. (with-fluids ((%default-port-encoding "UTF-8"))
  649. (substitute* files
  650. (("^Exec=([^/[:blank:]\r\n]*)(.*)$" _ binary rest)
  651. (string-append "Exec=" (which binary) rest))
  652. (("^TryExec=([^/[:blank:]\r\n]*)(.*)$" _ binary rest)
  653. (string-append "TryExec="
  654. (which binary) rest)))))))))
  655. outputs)
  656. #t)
  657. (define %license-file-regexp
  658. ;; Regexp matching license files.
  659. "^(COPYING.*|LICEN[CS]E.*|[Ll]icen[cs]e.*|Copy[Rr]ight(\\.(txt|md))?)$")
  660. (define* (install-license-files #:key outputs
  661. (license-file-regexp %license-file-regexp)
  662. out-of-source?
  663. #:allow-other-keys)
  664. "Install license files matching LICENSE-FILE-REGEXP to 'share/doc'."
  665. (define (find-source-directory package)
  666. ;; For an out-of-source build, guess the source directory location
  667. ;; relative to the current directory. Return #f on failure.
  668. (match (scandir ".."
  669. (lambda (file)
  670. (and (not (member file '("." ".." "build")))
  671. (file-is-directory?
  672. (string-append "../" file)))))
  673. (() ;hmm, no source
  674. #f)
  675. ((source) ;only one other file
  676. (string-append "../" source))
  677. ((directories ...) ;pick the most likely one
  678. ;; This happens for example with libstdc++, which lives within the GCC
  679. ;; source tree.
  680. (any (lambda (directory)
  681. (and (string-prefix? package directory)
  682. (string-append "../" directory)))
  683. directories))))
  684. (define (copy-to-directories directories sub-directory)
  685. (lambda (file)
  686. (for-each (if (file-is-directory? file)
  687. (cut copy-recursively file <>)
  688. (cut install-file file <>))
  689. (map (cut string-append <> "/" sub-directory)
  690. directories))))
  691. (let* ((regexp (make-regexp license-file-regexp))
  692. (out (or (assoc-ref outputs "out")
  693. (match outputs
  694. (((_ . output) _ ...)
  695. output))))
  696. (package (strip-store-file-name out))
  697. (outputs (match outputs
  698. (((_ . outputs) ...)
  699. outputs)))
  700. (source (if out-of-source?
  701. (find-source-directory
  702. (package-name->name+version package))
  703. "."))
  704. (files (and source
  705. (scandir source
  706. (lambda (file)
  707. (regexp-exec regexp file))))))
  708. (if files
  709. (begin
  710. (format #t "installing ~a license files from '~a'~%"
  711. (length files) source)
  712. (for-each (copy-to-directories outputs
  713. (string-append "share/doc/"
  714. package))
  715. (map (cut string-append source "/" <>) files)))
  716. (format (current-error-port)
  717. "failed to find license files~%"))
  718. #t))
  719. (define %standard-phases
  720. ;; Standard build phases, as a list of symbol/procedure pairs.
  721. (let-syntax ((phases (syntax-rules ()
  722. ((_ p ...) `((p . ,p) ...)))))
  723. (phases set-SOURCE-DATE-EPOCH set-paths install-locale unpack
  724. bootstrap
  725. patch-usr-bin-file
  726. patch-source-shebangs configure patch-generated-file-shebangs
  727. build check install
  728. patch-shebangs strip
  729. validate-runpath
  730. validate-documentation-location
  731. delete-info-dir-file
  732. patch-dot-desktop-files
  733. install-license-files
  734. reset-gzip-timestamps
  735. compress-documentation)))
  736. (define* (gnu-build #:key (source #f) (outputs #f) (inputs #f)
  737. (phases %standard-phases)
  738. #:allow-other-keys
  739. #:rest args)
  740. "Build from SOURCE to OUTPUTS, using INPUTS, and by running all of PHASES
  741. in order. Return #t if all the PHASES succeeded, #f otherwise."
  742. (define (elapsed-time end start)
  743. (let ((diff (time-difference end start)))
  744. (+ (time-second diff)
  745. (/ (time-nanosecond diff) 1e9))))
  746. (setvbuf (current-output-port) 'line)
  747. (setvbuf (current-error-port) 'line)
  748. ;; Encoding/decoding errors shouldn't be silent.
  749. (fluid-set! %default-port-conversion-strategy 'error)
  750. (guard (c ((invoke-error? c)
  751. (report-invoke-error c)
  752. (exit 1)))
  753. ;; The trick is to #:allow-other-keys everywhere, so that each procedure in
  754. ;; PHASES can pick the keyword arguments it's interested in.
  755. (every (match-lambda
  756. ((name . proc)
  757. (let ((start (current-time time-monotonic)))
  758. (format #t "starting phase `~a'~%" name)
  759. (let ((result (apply proc args))
  760. (end (current-time time-monotonic)))
  761. (format #t "phase `~a' ~:[failed~;succeeded~] after ~,1f seconds~%"
  762. name result
  763. (elapsed-time end start))
  764. ;; Issue a warning unless the result is #t.
  765. (unless (eqv? result #t)
  766. (format (current-error-port) "\
  767. ## WARNING: phase `~a' returned `~s'. Return values other than #t
  768. ## are deprecated. Please migrate this package so that its phase
  769. ## procedures report errors by raising an exception, and otherwise
  770. ## always return #t.~%"
  771. name result))
  772. ;; Dump the environment variables as a shell script, for handy debugging.
  773. (system "export > $NIX_BUILD_TOP/environment-variables")
  774. result))))
  775. phases)))