mirror of
git://git.savannah.gnu.org/guix.git
synced 2024-12-29 11:46:06 +01:00
gremlin: Add 'set-file-runpath', 'file-runpath', and 'file-needed'.
* guix/build/gremlin.scm (file-dynamic-info, file-runpath, file-needed): New procedures. (&missing-runpath-error, &runpath-too-long-error): New condition types. (set-file-runpath): New procedure. * tests/gremlin.scm ("set-file-runpath + file-runpath"): New test.
This commit is contained in:
parent
e0f31baacc
commit
49a1203d67
2 changed files with 103 additions and 3 deletions
|
@ -1,5 +1,5 @@
|
|||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2015, 2018 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2015, 2018, 2020 Ludovic Courtès <ludo@gnu.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
|
@ -41,6 +41,16 @@
|
|||
elf-dynamic-info-runpath
|
||||
expand-origin
|
||||
|
||||
file-dynamic-info
|
||||
file-runpath
|
||||
file-needed
|
||||
|
||||
missing-runpath-error?
|
||||
missing-runpath-error-file
|
||||
runpath-too-long-error?
|
||||
runpath-too-long-error-file
|
||||
set-file-runpath
|
||||
|
||||
validate-needed-in-runpath
|
||||
strip-runpath))
|
||||
|
||||
|
@ -232,6 +242,23 @@ string table if the type is a string."
|
|||
dynamic-entry-value))
|
||||
'()))))))
|
||||
|
||||
(define (file-dynamic-info file)
|
||||
"Return the <elf-dynamic-info> record of FILE, or #f if FILE lacks dynamic
|
||||
info."
|
||||
(call-with-input-file file
|
||||
(lambda (port)
|
||||
(elf-dynamic-info (parse-elf (get-bytevector-all port))))))
|
||||
|
||||
(define (file-runpath file)
|
||||
"Return the DT_RUNPATH dynamic entry of FILE as a list of string, or #f if
|
||||
FILE lacks dynamic info."
|
||||
(and=> (file-dynamic-info file) elf-dynamic-info-runpath))
|
||||
|
||||
(define (file-needed file)
|
||||
"Return the list of DT_NEEDED dynamic entries of FILE, or #f if FILE lacks
|
||||
dynamic info."
|
||||
(and=> (file-dynamic-info file) elf-dynamic-info-needed))
|
||||
|
||||
(define %libc-libraries
|
||||
;; List of libraries as of glibc 2.21 (there are more but those are
|
||||
;; typically mean to be LD_PRELOADed and thus do not appear as NEEDED.)
|
||||
|
@ -364,4 +391,49 @@ according to DT_NEEDED."
|
|||
(false-if-exception (close-port port))
|
||||
(apply throw key args))))
|
||||
|
||||
;;; gremlin.scm ends here
|
||||
|
||||
(define-condition-type &missing-runpath-error &elf-error
|
||||
missing-runpath-error?
|
||||
(file missing-runpath-error-file))
|
||||
|
||||
(define-condition-type &runpath-too-long-error &elf-error
|
||||
runpath-too-long-error?
|
||||
(file runpath-too-long-error-file))
|
||||
|
||||
(define (set-file-runpath file path)
|
||||
"Set the value of the DT_RUNPATH dynamic entry of FILE, which must name an
|
||||
ELF file, to PATH, a list of strings. Raise a &missing-runpath-error or
|
||||
&runpath-too-long-error when appropriate."
|
||||
(define (call-with-input+output-file file proc)
|
||||
(let ((port (open-file file "r+b")))
|
||||
(guard (c (#t (close-port port) (raise c)))
|
||||
(proc port)
|
||||
(close-port port))))
|
||||
|
||||
(call-with-input+output-file file
|
||||
(lambda (port)
|
||||
(let* ((elf (parse-elf (get-bytevector-all port)))
|
||||
(entries (dynamic-entries elf (dynamic-link-segment elf)))
|
||||
(runpath (find (lambda (entry)
|
||||
(= DT_RUNPATH (dynamic-entry-type entry)))
|
||||
entries))
|
||||
(path (string->utf8 (string-join path ":"))))
|
||||
(unless runpath
|
||||
(raise (condition (&missing-runpath-error (elf elf)
|
||||
(file file)))))
|
||||
|
||||
;; There might be padding left beyond RUNPATH in the string table, but
|
||||
;; we don't know, so assume there's no padding.
|
||||
(unless (<= (bytevector-length path)
|
||||
(bytevector-length
|
||||
(string->utf8 (dynamic-entry-value runpath))))
|
||||
(raise (condition (&runpath-too-long-error (elf #f #;elf)
|
||||
(file file)))))
|
||||
|
||||
(seek port (dynamic-entry-offset runpath) SEEK_SET)
|
||||
(put-bytevector port path)
|
||||
(put-u8 port 0)))))
|
||||
|
||||
;;; Local Variables:
|
||||
;;; eval: (put 'call-with-input+output-file 'scheme-indent-function 1)
|
||||
;;; End:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
;;; GNU Guix --- Functional package management for GNU
|
||||
;;; Copyright © 2015, 2018 Ludovic Courtès <ludo@gnu.org>
|
||||
;;; Copyright © 2015, 2018, 2020 Ludovic Courtès <ludo@gnu.org>
|
||||
;;;
|
||||
;;; This file is part of GNU Guix.
|
||||
;;;
|
||||
|
@ -23,6 +23,7 @@
|
|||
#:use-module (guix build gremlin)
|
||||
#:use-module (srfi srfi-1)
|
||||
#:use-module (srfi srfi-26)
|
||||
#:use-module (srfi srfi-34)
|
||||
#:use-module (srfi srfi-64)
|
||||
#:use-module (rnrs io ports)
|
||||
#:use-module (ice-9 popen)
|
||||
|
@ -96,4 +97,31 @@
|
|||
(close-pipe pipe)
|
||||
str)))))))
|
||||
|
||||
(unless c-compiler
|
||||
(test-skip 1))
|
||||
(test-equal "set-file-runpath + file-runpath"
|
||||
"hello\n"
|
||||
(call-with-temporary-directory
|
||||
(lambda (directory)
|
||||
(with-directory-excursion directory
|
||||
(call-with-output-file "t.c"
|
||||
(lambda (port)
|
||||
(display "int main () { puts(\"hello\"); }" port)))
|
||||
|
||||
(invoke c-compiler "t.c"
|
||||
"-Wl,--enable-new-dtags" "-Wl,-rpath=/xxxxxxxxx")
|
||||
|
||||
(let ((original-runpath (file-runpath "a.out")))
|
||||
(and (member "/xxxxxxxxx" original-runpath)
|
||||
(guard (c ((runpath-too-long-error? c)
|
||||
(string=? "a.out" (runpath-too-long-error-file c))))
|
||||
(set-file-runpath "a.out" (list (make-string 777 #\y))))
|
||||
(let ((runpath (delete "/xxxxxxxxx" original-runpath)))
|
||||
(set-file-runpath "a.out" runpath)
|
||||
(equal? runpath (file-runpath "a.out")))
|
||||
(let* ((pipe (open-input-pipe "./a.out"))
|
||||
(str (get-string-all pipe)))
|
||||
(close-pipe pipe)
|
||||
str)))))))
|
||||
|
||||
(test-end "gremlin")
|
||||
|
|
Loading…
Reference in a new issue