gnu-build-system.scm 39 KB

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