Subject: Re: bug#22138: Search paths of dependencies are not honored

From: Ludovic Courtès <[email-masked]>
Date: Fri, 23 Aug 2019 16:42:08 +0200

Hi Mark,

Mark H Weaver <[email-masked]> skribis:

> Julien Lepiller <[email-masked]> writes:
>
>> Hi, I've been looking at our current code and would like to propose the
>> attached patch for that issue.
>>
>> From cfd2c229087166ab4cc0a9e2bdb72c8b393bcdd5 Mon Sep 17 00:00:00 2001
>> From: Julien Lepiller <[email-masked]>
>> Date: Thu, 1 Aug 2019 22:09:38 +0200
>> Subject: [PATCH] guix: Recursively honor search paths of dependencies.
>>
>> * guix/packages.scm (all-transitive-inputs)
>> (package-all-transitive-inputs)
>> (package-all-transitive-native-search-paths): New procedures.
>> * guix/profiles.scm (package->manifest-entry): Use
>> package-all-transitive-native-search-paths to generate manifest search
>> paths.
>
> As I recall this kind of solution has been proposed in the past and
> rejected.  It's a reasonable suggestion, but I personally think that it
> goes too far, because it would include a great many packages whose code
> is nowhere to be found in the resulting profile.

I agree.

We need to take into account run-time dependencies (references), not
build-time dependencies, and that’s what makes things more difficult.

The attached procedure computes the search paths of a package based on
its run-time dependencies.  ‘profile-derivation’ could use this to
compute its ‘etc/profile’ file and its ‘manifest’ file.  Here’s what it
gives for ‘w3m’:

--8<---------------cut here---------------start------------->8---
(("BASH_LOADABLES_PATH"
  ("lib/bash")
  ":"
  directory
  #f)
 ("GUIX_LOCPATH" ("lib/locale") ":" directory #f)
 ("SSL_CERT_DIR"
  ("etc/ssl/certs")
  #f
  directory
  #f)
 ("SSL_CERT_FILE"
  ("etc/ssl/certs/ca-certificates.crt")
  #f
  regular
  #f)
 ("TERMINFO_DIRS"
  ("share/terminfo")
  ":"
  directory
  #f)
 ("XDG_DATA_DIRS" ("share") ":" directory #f)
 ("GIO_EXTRA_MODULES"
  ("lib/gio/modules")
  ":"
  directory
  #f)
 ("PERL5LIB"
  ("lib/perl5/site_perl")
  ":"
  directory
  #f))
--8<---------------cut here---------------end--------------->8---

We get GUIX_LOCPATH and SSL_CERT_DIR, which is exactly what we want.
However, the other search paths that we get look less desirable:
intuitively, it seems that we may not need them, and in the case of
XDG_DATA_DIRS, setting it may be detrimental.

For ‘icecat’ this gives additional things like PYTHONPATH,
GUILE_LOAD_PATH, XML_CATALOG_FILES, and so on.

In practice that’s probably OK though: if you only have ‘icecat’ and
other GUIs in your profile, Guix won’t suggest setting GUILE_LOAD_PATH
or PYTHONPATH.

So I think we can come up with a solution based on the patch below, but
we’ll have to test it on Guix System and on foreign distros to see if
the extra search paths that it brings are warranted.

Thoughts?

Ludo’.

diff --git a/guix/packages.scm b/guix/packages.scm
index c94a651f27..7d5c8198ac 100644
--- a/guix/packages.scm
+++ b/guix/packages.scm
@@ -26,6 +26,7 @@
   #:use-module (guix store)
   #:use-module (guix monads)
   #:use-module (guix gexp)
+  #:use-module (guix modules)
   #:use-module (guix base32)
   #:use-module (guix grafts)
   #:use-module (guix derivations)
@@ -749,6 +750,64 @@ recursively."
                          '()))
                       (package-transitive-propagated-inputs package))))
 
+(define (package-run-time-search-paths package)
+  "Return a file that contains a list of search path specifications
+corresponding to the run-time references of PACKAGE."
+  (define search-paths
+    (map (lambda (package)
+           (cons (package-full-name package "-")
+                 (map search-path-specification->sexp
+                      (package-native-search-paths package))))
+         (package-closure (list package))))
+
+  (define build
+    (with-imported-modules (source-module-closure
+                            '((guix build utils)
+                              (guix search-paths)
+                              (guix build store-copy)))
+      #~(begin
+          (use-modules (guix build utils)
+                       (guix build store-copy)
+                       (guix search-paths)
+                       (srfi srfi-1)
+                       (ice-9 match)
+                       (ice-9 pretty-print))
+
+          (define search-paths
+            ;; Map items like "coreutils-8.20" to their search path specs.
+            (map (match-lambda
+                   ((item . paths)
+                    (cons item (map sexp->search-path-specification paths))))
+                 '#$search-paths))
+
+          (define (store-item-search-paths item)
+            "Return the search paths that apply to ITEM, a store item."
+            (or (any (match-lambda
+                       ((entry . paths)
+                        (and (string-suffix? entry item)
+                             paths)))
+                     search-paths)
+                '()))
+
+          (let* ((references (map store-info-item
+                                  (call-with-input-file "graph"
+                                    read-reference-graph)))
+                 (paths      (delete-duplicates
+                              (append-map store-item-search-paths
+                                          references))))
+            (call-with-output-file #$output
+              (lambda (port)
+                (pretty-print (map search-path-specification->sexp
+                                   paths)
+                              port)))))))
+
+  (computed-file (string-append (package-full-name package "-")
+                                "-search-paths")
+                 build
+                 #:options
+                 `(#:references-graphs (("graph" ,package))
+                   #:properties '((type . search-paths)))))
+
 (define (transitive-input-references alist inputs)
   "Return a list of (assoc-ref ALIST <label>) for each (<label> <package> . _)
 in INPUTS and their transitive propagated inputs."