summaryrefslogtreecommitdiff
path: root/guix/build
diff options
context:
space:
mode:
Diffstat (limited to 'guix/build')
-rw-r--r--guix/build/cmake-build-system.scm4
-rw-r--r--guix/build/glib-or-gtk-build-system.scm6
-rw-r--r--guix/build/gnu-build-system.scm73
-rw-r--r--guix/build/gnu-dist.scm10
-rw-r--r--guix/build/gremlin.scm89
-rw-r--r--guix/build/perl-build-system.scm8
-rw-r--r--guix/build/python-build-system.scm12
-rw-r--r--guix/build/ruby-build-system.scm10
-rw-r--r--guix/build/utils.scm81
-rw-r--r--guix/build/waf-build-system.scm8
10 files changed, 220 insertions, 81 deletions
diff --git a/guix/build/cmake-build-system.scm b/guix/build/cmake-build-system.scm
index d8d437c653..f57622e0f4 100644
--- a/guix/build/cmake-build-system.scm
+++ b/guix/build/cmake-build-system.scm
@@ -73,8 +73,8 @@
;; Everything is as with the GNU Build System except for the `configure'
;; and 'check' phases.
(modify-phases gnu:%standard-phases
- (replace check check)
- (replace configure configure)))
+ (replace 'check check)
+ (replace 'configure configure)))
(define* (cmake-build #:key inputs (phases %standard-phases)
#:allow-other-keys #:rest args)
diff --git a/guix/build/glib-or-gtk-build-system.scm b/guix/build/glib-or-gtk-build-system.scm
index 40f1bb85fa..15d7de2236 100644
--- a/guix/build/glib-or-gtk-build-system.scm
+++ b/guix/build/glib-or-gtk-build-system.scm
@@ -242,9 +242,9 @@ needed."
(define %standard-phases
(modify-phases gnu:%standard-phases
- (add-after install glib-or-gtk-compile-schemas compile-glib-schemas)
- (add-after install glib-or-gtk-icon-cache generate-icon-cache)
- (add-after install glib-or-gtk-wrap wrap-all-programs)))
+ (add-after 'install 'glib-or-gtk-compile-schemas compile-glib-schemas)
+ (add-after 'install 'glib-or-gtk-icon-cache generate-icon-cache)
+ (add-after 'install 'glib-or-gtk-wrap wrap-all-programs)))
(define* (glib-or-gtk-build #:key inputs (phases %standard-phases)
#:allow-other-keys #:rest args)
diff --git a/guix/build/gnu-build-system.scm b/guix/build/gnu-build-system.scm
index 5ae537150f..c60f8ba162 100644
--- a/guix/build/gnu-build-system.scm
+++ b/guix/build/gnu-build-system.scm
@@ -18,12 +18,15 @@
(define-module (guix build gnu-build-system)
#:use-module (guix build utils)
+ #:use-module (guix build gremlin)
+ #:use-module (guix elf)
#:use-module (ice-9 ftw)
#:use-module (ice-9 match)
#:use-module (ice-9 regex)
#:use-module (ice-9 format)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-26)
+ #:use-module (rnrs io ports)
#:export (%standard-phases
gnu-build))
@@ -398,6 +401,64 @@ makefiles."
strip-directories)))
outputs))))
+(define (every* pred lst)
+ "This is like 'every', but process all the elements of LST instead of
+stopping as soon as PRED returns false. This is useful when PRED has side
+effects, such as displaying warnings or error messages."
+ (let loop ((lst lst)
+ (result #t))
+ (match lst
+ (()
+ result)
+ ((head . tail)
+ (loop tail (and (pred head) result))))))
+
+(define* (validate-runpath #:key
+ validate-runpath?
+ (elf-directories '("lib" "lib64" "libexec"
+ "bin" "sbin"))
+ outputs #:allow-other-keys)
+ "When VALIDATE-RUNPATH? is true, validate that all the ELF files in
+ELF-DIRECTORIES have their dependencies found in their 'RUNPATH'.
+
+Since the ELF parser needs to have a copy of files in memory, better run this
+phase after stripping."
+ (define (sub-directory parent)
+ (lambda (directory)
+ (let ((directory (string-append parent "/" directory)))
+ (and (directory-exists? directory) directory))))
+
+ (define (validate directory)
+ (define (file=? file1 file2)
+ (let ((st1 (stat file1))
+ (st2 (stat file2)))
+ (= (stat:ino st1) (stat:ino st2))))
+
+ ;; There are always symlinks from '.so' to '.so.1' and so on, so delete
+ ;; duplicates.
+ (let ((files (delete-duplicates (find-files directory (lambda (file stat)
+ (elf-file? file)))
+ file=?)))
+ (format (current-error-port)
+ "validating RUNPATH of ~a binaries in ~s...~%"
+ (length files) directory)
+ (every* validate-needed-in-runpath files)))
+
+ (if validate-runpath?
+ (let ((dirs (append-map (match-lambda
+ (("debug" . _)
+ ;; The "debug" output is full of ELF files
+ ;; that are not worth checking.
+ '())
+ ((name . output)
+ (filter-map (sub-directory output)
+ elf-directories)))
+ outputs)))
+ (every* validate dirs))
+ (begin
+ (format (current-error-port) "skipping RUNPATH validation~%")
+ #t)))
+
(define* (validate-documentation-location #:key outputs
#:allow-other-keys)
"Documentation should go to 'share/info' and 'share/man', not just 'info/'
@@ -477,6 +538,16 @@ DOCUMENTATION-COMPRESSOR-FLAGS."
(format #t "not compressing documentation~%")
#t)))
+(define* (delete-info-dir-file #:key outputs #:allow-other-keys)
+ "Delete any 'share/info/dir' file from OUTPUTS."
+ (for-each (match-lambda
+ ((output . directory)
+ (let ((info-dir-file (string-append directory "/share/info/dir")))
+ (when (file-exists? info-dir-file)
+ (delete-file info-dir-file)))))
+ outputs)
+ #t)
+
(define %standard-phases
;; Standard build phases, as a list of symbol/procedure pairs.
(let-syntax ((phases (syntax-rules ()
@@ -486,7 +557,9 @@ DOCUMENTATION-COMPRESSOR-FLAGS."
patch-source-shebangs configure patch-generated-file-shebangs
build check install
patch-shebangs strip
+ validate-runpath
validate-documentation-location
+ delete-info-dir-file
compress-documentation)))
diff --git a/guix/build/gnu-dist.scm b/guix/build/gnu-dist.scm
index 887b5e94e9..ad69c6cf16 100644
--- a/guix/build/gnu-dist.scm
+++ b/guix/build/gnu-dist.scm
@@ -83,10 +83,10 @@
(define %dist-phases
;; Phases for building a source tarball.
(modify-phases %standard-phases
- (delete strip)
- (replace install install-dist)
- (replace build build)
- (add-before configure autoreconf autoreconf)
- (replace unpack copy-source)))
+ (delete 'strip)
+ (replace 'install install-dist)
+ (replace 'build build)
+ (add-before 'configure 'autoreconf autoreconf)
+ (replace 'unpack copy-source)))
;;; gnu-dist.scm ends here
diff --git a/guix/build/gremlin.scm b/guix/build/gremlin.scm
index e8429129e1..30b06034dd 100644
--- a/guix/build/gremlin.scm
+++ b/guix/build/gremlin.scm
@@ -18,14 +18,22 @@
(define-module (guix build gremlin)
#:use-module (guix elf)
+ #:use-module ((guix build utils) #:select (store-file-name?))
#:use-module (ice-9 match)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-9)
#:use-module (srfi srfi-26)
+ #:use-module (srfi srfi-34)
+ #:use-module (srfi srfi-35)
#:use-module (system foreign)
#:use-module (rnrs bytevectors)
#:use-module (rnrs io ports)
- #:export (elf-dynamic-info
+ #:export (elf-error?
+ elf-error-elf
+ invalid-segment-size?
+ invalid-segment-size-segment
+
+ elf-dynamic-info
elf-dynamic-info?
elf-dynamic-info-sopath
elf-dynamic-info-needed
@@ -41,12 +49,31 @@
;;;
;;; Code:
+(define-condition-type &elf-error &error
+ elf-error?
+ (elf elf-error-elf))
+
+(define-condition-type &invalid-segment-size &elf-error
+ invalid-segment-size?
+ (segment invalid-segment-size-segment))
+
+
(define (dynamic-link-segment elf)
"Return the 'PT_DYNAMIC' segment of ELF--i.e., the segment that contains
dynamic linking information."
- (find (lambda (segment)
- (= (elf-segment-type segment) PT_DYNAMIC))
- (elf-segments elf)))
+ (let ((size (bytevector-length (elf-bytes elf))))
+ (find (lambda (segment)
+ (unless (<= (+ (elf-segment-offset segment)
+ (elf-segment-filesz segment))
+ size)
+ ;; This happens on separate debug output files created by
+ ;; 'strip --only-keep-debug' (Binutils 2.25.)
+ (raise (condition (&invalid-segment-size
+ (elf elf)
+ (segment segment)))))
+
+ (= (elf-segment-type segment) PT_DYNAMIC))
+ (elf-segments elf))))
(define (word-reader size byte-order)
"Return a procedure to read a word of SIZE bytes according to BYTE-ORDER."
@@ -197,6 +224,7 @@ value of DT_NEEDED entries is a string.)"
"libc.so"
"libdl.so"
"libm.so"
+ "libnsl.so" ;NEEDED by nscd
"libpthread.so"
"libresolv.so"
"librt.so"
@@ -214,23 +242,42 @@ value of DT_NEEDED entries is a string.)"
present in its RUNPATH, or if FILE lacks dynamic-link information. Return #f
otherwise. Libraries whose name matches ALWAYS-FOUND? are considered to be
always available."
- (let* ((elf (call-with-input-file file
- (compose parse-elf get-bytevector-all)))
- (dyninfo (elf-dynamic-info elf)))
- (when dyninfo
- (let* ((runpath (elf-dynamic-info-runpath dyninfo))
- (needed (remove always-found?
- (elf-dynamic-info-needed dyninfo)))
- (not-found (remove (cut search-path runpath <>)
- needed)))
- (for-each (lambda (lib)
- (format (current-error-port)
- "error: '~a' depends on '~a', which cannot \
+ (guard (c ((invalid-segment-size? c)
+ (let ((segment (invalid-segment-size-segment c)))
+ (format (current-error-port)
+ "~a: error: offset + size of segment ~a (type ~a) \
+exceeds total size~%"
+ file
+ (elf-segment-index segment)
+ (elf-segment-type segment))
+ #f)))
+
+ (let* ((elf (call-with-input-file file
+ (compose parse-elf get-bytevector-all)))
+ (dyninfo (elf-dynamic-info elf)))
+ (when dyninfo
+ (let* ((runpath (filter store-file-name?
+ (elf-dynamic-info-runpath dyninfo)))
+ (bogus (remove store-file-name?
+ (elf-dynamic-info-runpath dyninfo)))
+ (needed (remove always-found?
+ (elf-dynamic-info-needed dyninfo)))
+ (not-found (remove (cut search-path runpath <>)
+ needed)))
+ ;; XXX: $ORIGIN is not supported.
+ (unless (null? bogus)
+ (format (current-error-port)
+ "~a: warning: RUNPATH contains bogus entries: ~s~%"
+ file bogus))
+
+ (for-each (lambda (lib)
+ (format (current-error-port)
+ "~a: error: depends on '~a', which cannot \
be found in RUNPATH ~s~%"
- file lib runpath))
- not-found)
- ;; (when (null? not-found)
- ;; (format (current-error-port) "~a is OK~%" file))
- (null? not-found)))))
+ file lib runpath))
+ not-found)
+ ;; (when (null? not-found)
+ ;; (format (current-error-port) "~a is OK~%" file))
+ (null? not-found))))))
;;; gremlin.scm ends here
diff --git a/guix/build/perl-build-system.scm b/guix/build/perl-build-system.scm
index 9ca5353bb9..8f480eae16 100644
--- a/guix/build/perl-build-system.scm
+++ b/guix/build/perl-build-system.scm
@@ -72,10 +72,10 @@
;; Everything is as with the GNU Build System except for the `configure',
;; `build', `check', and `install' phases.
(modify-phases gnu:%standard-phases
- (replace install install)
- (replace check check)
- (replace build build)
- (replace configure configure)))
+ (replace 'install install)
+ (replace 'check check)
+ (replace 'build build)
+ (replace 'configure configure)))
(define* (perl-build #:key inputs (phases %standard-phases)
#:allow-other-keys #:rest args)
diff --git a/guix/build/python-build-system.scm b/guix/build/python-build-system.scm
index 9f853134bd..26a7254db9 100644
--- a/guix/build/python-build-system.scm
+++ b/guix/build/python-build-system.scm
@@ -123,12 +123,12 @@ installed with setuptools."
;; 'configure' and 'build' phases are not needed. Everything is done during
;; 'install'.
(modify-phases gnu:%standard-phases
- (delete configure)
- (replace install install)
- (replace check check)
- (replace build build)
- (add-after install wrap wrap)
- (add-before strip rename-pth-file rename-pth-file)))
+ (delete 'configure)
+ (replace 'install install)
+ (replace 'check check)
+ (replace 'build build)
+ (add-after 'install 'wrap wrap)
+ (add-before 'strip 'rename-pth-file rename-pth-file)))
(define* (python-build #:key inputs (phases %standard-phases)
#:allow-other-keys #:rest args)
diff --git a/guix/build/ruby-build-system.scm b/guix/build/ruby-build-system.scm
index a143df467f..531cf382ae 100644
--- a/guix/build/ruby-build-system.scm
+++ b/guix/build/ruby-build-system.scm
@@ -72,11 +72,11 @@ directory."
(define %standard-phases
(modify-phases gnu:%standard-phases
- (delete configure)
- (add-after unpack gitify gitify)
- (replace build build)
- (replace install install)
- (replace check check)))
+ (delete 'configure)
+ (add-after 'unpack 'gitify gitify)
+ (replace 'build build)
+ (replace 'install install)
+ (replace 'check check)))
(define* (ruby-build #:key inputs (phases %standard-phases)
#:allow-other-keys #:rest args)
diff --git a/guix/build/utils.scm b/guix/build/utils.scm
index a5a6167a8c..676a0120e3 100644
--- a/guix/build/utils.scm
+++ b/guix/build/utils.scm
@@ -32,6 +32,7 @@
#:re-export (alist-cons
alist-delete)
#:export (%store-directory
+ store-file-name?
parallel-job-count
directory-exists?
@@ -44,6 +45,7 @@
mkdir-p
copy-recursively
delete-file-recursively
+ file-name-predicate
find-files
search-path-as-list
@@ -80,6 +82,10 @@
(or (getenv "NIX_STORE")
"/gnu/store"))
+(define (store-file-name? file)
+ "Return true if FILE is in the store."
+ (string-prefix? (%store-directory) file))
+
(define parallel-job-count
;; Number of processes to be passed next to GNU Make's `-j' argument.
(make-parameter
@@ -263,33 +269,46 @@ errors."
;; Don't follow symlinks.
lstat)))
-(define (find-files dir regexp)
- "Return the lexicographically sorted list of files under DIR whose basename
-matches REGEXP."
- (define file-rx
- (if (regexp? regexp)
- regexp
- (make-regexp regexp)))
-
- ;; Sort the result to get deterministic results.
- (sort (file-system-fold (const #t)
- (lambda (file stat result) ; leaf
- (if (regexp-exec file-rx (basename file))
- (cons file result)
- result))
- (lambda (dir stat result) ; down
- result)
- (lambda (dir stat result) ; up
- result)
- (lambda (file stat result) ; skip
- result)
- (lambda (file stat errno result)
- (format (current-error-port) "find-files: ~a: ~a~%"
- file (strerror errno))
- result)
- '()
- dir)
- string<?))
+(define (file-name-predicate regexp)
+ "Return a predicate that returns true when passed a file name whose base
+name matches REGEXP."
+ (let ((file-rx (if (regexp? regexp)
+ regexp
+ (make-regexp regexp))))
+ (lambda (file stat)
+ (regexp-exec file-rx (basename file)))))
+
+(define* (find-files dir #:optional (pred (const #t))
+ #:key (stat lstat))
+ "Return the lexicographically sorted list of files under DIR for which PRED
+returns true. PRED is passed two arguments: the absolute file name, and its
+stat buffer; the default predicate always returns true. PRED can also be a
+regular expression, in which case it is equivalent to (file-name-predicate
+PRED). STAT is used to obtain file information; using 'lstat' means that
+symlinks are not followed."
+ (let ((pred (if (procedure? pred)
+ pred
+ (file-name-predicate pred))))
+ ;; Sort the result to get deterministic results.
+ (sort (file-system-fold (const #t)
+ (lambda (file stat result) ; leaf
+ (if (pred file stat)
+ (cons file result)
+ result))
+ (lambda (dir stat result) ; down
+ result)
+ (lambda (dir stat result) ; up
+ result)
+ (lambda (file stat result) ; skip
+ result)
+ (lambda (file stat errno result)
+ (format (current-error-port) "find-files: ~a: ~a~%"
+ file (strerror errno))
+ result)
+ '()
+ dir
+ stat)
+ string<?)))
;;;
@@ -446,13 +465,13 @@ an expression evaluating to a procedure."
(define-syntax %modify-phases
(syntax-rules (delete replace add-before add-after)
((_ phases (delete old-phase-name))
- (alist-delete 'old-phase-name phases))
+ (alist-delete old-phase-name phases))
((_ phases (replace old-phase-name new-phase))
- (alist-replace 'old-phase-name new-phase phases))
+ (alist-replace old-phase-name new-phase phases))
((_ phases (add-before old-phase-name new-phase-name new-phase))
- (alist-cons-before 'old-phase-name 'new-phase-name new-phase phases))
+ (alist-cons-before old-phase-name new-phase-name new-phase phases))
((_ phases (add-after old-phase-name new-phase-name new-phase))
- (alist-cons-after 'old-phase-name 'new-phase-name new-phase phases))))
+ (alist-cons-after old-phase-name new-phase-name new-phase phases))))
;;;
diff --git a/guix/build/waf-build-system.scm b/guix/build/waf-build-system.scm
index d172c5a836..85f0abcfd6 100644
--- a/guix/build/waf-build-system.scm
+++ b/guix/build/waf-build-system.scm
@@ -70,10 +70,10 @@
(define %standard-phases
(modify-phases gnu:%standard-phases
- (replace configure configure)
- (replace build build)
- (replace check check)
- (replace install install)))
+ (replace 'configure configure)
+ (replace 'build build)
+ (replace 'check check)
+ (replace 'install install)))
(define* (waf-build #:key inputs (phases %standard-phases)
#:allow-other-keys #:rest args)