gnu-build-system.scm 35 KB

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