aboutsummaryrefslogtreecommitdiff
;;; GNU Guix --- Functional package management for GNU
;;; Copyright © 2015, 2018, 2020, 2022 Ludovic Courtès <ludo@gnu.org>
;;; Copyright © 2022 Chris Marusich <cmmarusich@gmail.com>
;;; Copyright © 2022 Pierre Langlois <pierre.langlois@gmx.com>
;;;
;;; This file is part of GNU Guix.
;;;
;;; GNU Guix is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 3 of the License, or (at
;;; your option) any later version.
;;;
;;; GNU Guix is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with GNU Guix.  If not, see <http://www.gnu.org/licenses/>.

(define-module (test-gremlin)
  #:use-module (guix elf)
  #:use-module (guix tests)
  #:use-module ((guix utils) #:select (call-with-temporary-directory
                                       target-aarch64?))
  #:use-module (guix build utils)
  #:use-module (guix build gremlin)
  #:use-module (gnu packages bootstrap)
  #: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)
  #:use-module (ice-9 rdelim)
  #:use-module (ice-9 regex)
  #:use-module (ice-9 match))

(define %guile-executable
  (match (false-if-exception (readlink "/proc/self/exe"))
    ((? string? program)
     (and (file-exists? program) (elf-file? program)
          program))
    (_
     #f)))

(define read-elf
  (compose parse-elf get-bytevector-all))

(define c-compiler
  (or (which "gcc") (which "cc") (which "g++")))


(test-begin "gremlin")

(unless %guile-executable (test-skip 1))
(test-assert "elf-dynamic-info-needed, executable"
  (let* ((elf     (call-with-input-file %guile-executable read-elf))
         (dyninfo (elf-dynamic-info elf)))
    (or (not dyninfo)                             ;static executable
        (lset<= string=?
                (list (string-append "libguile-" (effective-version))
                      "libc")
                (map (lambda (lib)
                       (string-take lib (string-contains lib ".so")))
                     (elf-dynamic-info-needed dyninfo))))))

(unless (and %guile-executable (not (getenv "LD_LIBRARY_PATH"))
             (file-needed %guile-executable) ;statically linked?
             ;; When Guix has been built on a foreign distro, using a
             ;; toolchain and libraries from that foreign distro, it is not
             ;; unusual for the runpath to be empty.
             (pair? (file-runpath %guile-executable)))
  (test-skip 1))
(test-assert "file-needed/recursive"
  (let* ((needed (file-needed/recursive %guile-executable))
         (pipe   (dynamic-wind
                   (lambda ()
                     ;; Tell ld.so to list loaded objects, like 'ldd' does.
                     (setenv "LD_TRACE_LOADED_OBJECTS" "yup"))
                   (lambda ()
                     (open-pipe* OPEN_READ %guile-executable))
                   (lambda ()
                     (unsetenv "LD_TRACE_LOADED_OBJECTS")))))
    (define ldd-rx
      (make-regexp "^[[:blank:]]+([[:graph:]]+ => )?([[:graph:]]+) .*$"))

    (define (read-ldd-output port)
      ;; Read from PORT output in GNU ldd format.
      (let loop ((result '()))
        (match (read-line port)
          ((? eof-object?)
           (reverse result))
          ((= (cut regexp-exec ldd-rx <>) m)
           (if m
               (loop (cons (match:substring m 2) result))
               (loop result))))))
    (define ground-truth
      (remove (lambda (entry)
                ;; See vdso(7) for the list of vDSO names across
                ;; architectures.
                (or (string-prefix? "linux-vdso.so" entry)
                    (string-prefix? "linux-vdso32.so" entry) ;32-bit powerpc
                    (string-prefix? "linux-vdso64.so" entry) ;64-bit powerpc
                    (string-prefix? "linux-gate.so" entry)   ;i386
                    ;; FIXME: ELF files on aarch64 do not always include a
                    ;; NEEDED entry for the dynamic linker, and it is unclear
                    ;; if that is OK.  See: https://issues.guix.gnu.org/52943
                    (and (target-aarch64?)
                         (string-contains entry (glibc-dynamic-linker)))))
              (read-ldd-output pipe)))

    (and (zero? (close-pipe pipe))
         ;; It's OK if file-needed/recursive returns multiple entries that are
         ;; different strings referring to the same file.  This appears to be a
         ;; benign edge case.  See: https://issues.guix.gnu.org/52940
         (lset= file=? (pk 'truth ground-truth) (pk 'needed needed)))))

(test-equal "expand-origin"
  '("OOO/../lib"
    "OOO"
    "../OOO/bar/OOO/baz"
    "ORIGIN/foo")
  (map (cut expand-origin <> "OOO")
       '("$ORIGIN/../lib"
         "${ORIGIN}"
         "../${ORIGIN}/bar/$ORIGIN/baz"
         "ORIGIN/foo")))

(unless c-compiler
  (test-skip 1))
(test-equal "strip-runpath"
  "hello\n"
  (call-with-temporary-directory
   (lambda (directory)
     (with-directory-excursion directory
       (call-with-output-file "t.c"
         (lambda (port)
           (display "#include <stdio.h>\n" port)
           (display "int main () { puts(\"hello\"); }" port)))
       (invoke c-compiler "t.c"
               "-Wl,--enable-new-dtags" "-Wl,-rpath=/foo" "-Wl,-rpath=/bar")
       (let* ((dyninfo (elf-dynamic-info
                        (parse-elf (call-with-input-file "a.out"
                                     get-bytevector-all))))
              (old     (elf-dynamic-info-runpath dyninfo))
              (new     (strip-runpath "a.out"))
              (new*    (strip-runpath "a.out")))
         (validate-needed-in-runpath "a.out")
         (and (member "/foo" old) (member "/bar" old)
              (not (member "/foo" new))
              (not (member "/bar" new))
              (equal? new* new)
              (let* ((pipe (open-input-pipe "./a.out"))
                     (str  (get-string-all pipe)))
                (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 "#include <stdio.h>\n" 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)))))))

(unless c-compiler
  (test-skip 1))
(test-equal "elf-dynamic-info-soname"
  "libfoo.so.2"
  (call-with-temporary-directory
   (lambda (directory)
     (with-directory-excursion directory
       (call-with-output-file "t.c"
         (lambda (port)
           (display "// empty file" port)))
       (invoke c-compiler "t.c"
               "-shared" "-Wl,-soname,libfoo.so.2")
       (let* ((dyninfo (elf-dynamic-info
                       (parse-elf (call-with-input-file "a.out"
                                    get-bytevector-all))))
              (soname  (elf-dynamic-info-soname dyninfo)))
	 soname)))))

(test-end "gremlin")
c: cookbook: Fix typos....* doc/guix-cookbook.texi (Extended example): Fix typos. Ludovic Courtès 2020-06-23doc: cookbook: Tweak intro to the REPL....* doc/guix-cookbook.texi (A Scheme Crash Course): Reword first paragraph. Remove extra paren. Ludovic Courtès 2020-06-23doc: cookbook: Mention "guix hash -rx" for Git checkouts....* doc/guix-cookbook.texi (Extended example): Mention "guix hash -rx ." Ludovic Courtès 2020-06-23doc: cookbook: Clarify 'git-fetch' conventions....* doc/guix-cookbook.texi (Extended example): Clarify use of 'git-file-name' and 'git-version'. Ludovic Courtès 2020-06-04doc: cookbook: Add entry about getting substitutes through Tor....* doc/guix-cookbook.texi (Getting substitutes from Tor): New section. Brice Waegeneire 2020-06-02doc: cookbook: Add entry about Wireguard VPN....Co-authored-by: Brice Waegeneire <brice@waegenei.re> * doc/guix-cookbook.texi (Connect to Wireguard VPN): New section. Marcin Karpezo 2020-05-25doc: cookbook: Add subsection about session locking with xss-lock....* doc/guix-cookbook.texi (Session lock): New node. Signed-off-by: Ludovic Courtès <ludo@gnu.org> Chris Bøg 2020-05-05doc: cookbook: Fix sbcl-ttf-fonts package name....* doc/guix-cookbook.texi (StumpWM): Adjust sbcl-ttf-fonts package name. Signed-off-by: Marius Bakke <mbakke@fastmail.com> Jean-Baptiste Note 2020-04-30doc: cookbook: Rename stumpwm package to current state....* doc/guix-cookbook.texi (StumpWM): Rename STUMPWM package to current state. Signed-off-by: Oleg Pykhalov <go.wigust@gmail.com> Marcin Karpezo 2020-04-25doc: cookbook: Fix quotes....* doc/guix-cookbook.texi (Basic setup with manifests): (Default profile): (The benefits of manifests): Use proper quotes in regular texts. Nicolas Goaziou 2020-04-24doc: cookbook: Use @file for file names and extensions....* doc/guix-cookbook.texi (@samp{GUIX_PACKAGE_PATH}): (Extended example): (Setting up a bind mount): (Basic setup with manifests): (Default profile): Use @file instead of @samp or @code for file names and extensions. Nicolas Goaziou 2020-04-24doc: cookbook: Fix misuses of double spacing....* doc/guix-cookbook.texi (Extended example): (StumpWM): (Basic setup with manifests): Prevent Texinfo from ending a sentence where it should not. (Setting up a bind mount): Add two spaces where needed. Nicolas Goaziou 2020-04-22doc: cookbook: Explain how to use bind mounts....* doc/guix-cookbook.texi (Setting up a bind mount): Add example. Signed-off-by: Leo Famulari <leo@famulari.name> Matthew Brooks 2020-03-30gnu: Add sbcl-stumpwm-ttf-fonts....* gnu/packages/wm.scm (sbcl-stumpwm-ttf-fonts): New variable. * doc/guix-cookbook.texi (Customizing a Window Manager): Document SBCL-STUMPWM-TTF-FONTS installation and configuration. Oleg Pykhalov 2020-01-17doc: cookbook: Avoid URL reference to the manual....* doc/guix-cookbook.texi (Other build systems): Use @xref instead of @uref, and remove section number. Ludovic Courtès 2019-11-26doc: cookbook: Add cross-references to the Guile manual....* doc/guix-cookbook.texi (A Scheme Crash Course): Add cross-reference to the Guile manual. Ludovic Courtès 2019-11-26doc: cookbook: Use @result{} & co. instead of a '>' prompt....* doc/guix-cookbook.texi (A Scheme Crash Course) (Extended example): Use @result{}, @print{}, and @error{}. Ludovic Courtès 2019-11-26doc: cookbook: Use Texinfo quotes....* doc/guix-cookbook.texi: Use Texinfo quotes ``like this'' instead of straight quotes or curly quotes. Ludovic Courtès 2019-11-26doc: cookbook: Add cross-reference about ./pre-inst-env....* doc/guix-cookbook.texi (Direct checkout hacking): Refer to "Running Guix Before It Is Installed". Ludovic Courtès 2019-11-26doc: cookbook: Use @lisp for Scheme snippets....* doc/guix-cookbook.texi: Use @lisp instead of @example where appropriate. Ludovic Courtès 2019-10-30doc: Explain how to switch profile from empty shell in "Profiles in Practice"....* doc/guix-cookbook.texi (Profiles in Practice): Add example. Pierre Neidhardt 2019-10-28doc: Link to SICP Info page in "A Scheme Crash Course"....* doc/guix-cookbook.texi (Scheme tutorials): Replace Emacs Info reader hint with more useful interactive link to SICP Info page. Pierre Neidhardt 2019-10-28doc: Finish importing the "Packaging Tutorial"....* doc/guix-cookbook.texi (Packaging Tutorial): Import all sections after the Scheme crash course. Pierre Neidhardt 2019-10-28doc: Fix some typos in "Guix Profiles in Practice"....* doc/guix-cookbook.texi (Guix Profiles in Practice): Fix typos. Pierre Neidhardt 2019-10-25doc: cookbook: Use "@lisp" for Scheme snippets....* doc/guix-cookbook.texi: Use @lisp for Scheme snippets instead of "@example scheme". This allows for syntax highlighting of the HTML output. Ludovic Courtès 2019-10-24doc: Add "Guix Profiles in Practice" to the cookbook....* doc/guix-cookbook.texi (Advanced package management): New chapter. * doc/guix-cookbook.texi (Guix Profiles in Practice): New section. Pierre Neidhardt 2019-09-18doc: Add Guix Cookbook....* .gitignore: Update ignore list. * Makefile.am (assert-no-store-file-names): Exclude the cookbook. * bootstrap: Generate po files for cookbook translations. * doc/guix-cookbook.texi: New file. * doc/local.mk (info_TEXINFOS): Add it; add a rule to build cookbook translations. * po/doc/local.mk (DOC_COOKBOOK_PO_FILES): New variable. (EXTRA_DIST): Add cookbook pot file and po files. (doc-po-update-cookbook-%): New target. (doc-pot-update): Also update cookbook pot file. (doc-po-update): Also update cookbook po files. Ricardo Wurmus