summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/guix.texi22
-rw-r--r--guix/scripts/package.scm66
-rw-r--r--tests/guix-package.sh8
3 files changed, 94 insertions, 2 deletions
diff --git a/doc/guix.texi b/doc/guix.texi
index e23eab0f81..d571de95a0 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -517,8 +517,13 @@ Thus, when installing MPC, the MPFR and GMP libraries also get installed
 in the profile; removing MPC also removes MPFR and GMP---unless they had
 also been explicitly installed independently.
 
+Besides, packages sometime rely on the definition of environment
+variables for their search paths (see explanation of
+@code{--search-paths} below.)  Any missing or possibly incorrect
+environment variable definitions are reported here.
+
 @c XXX: keep me up-to-date
-Besides, when installing a GNU package, the tool reports the
+Finally, when installing a GNU package, the tool reports the
 availability of a newer upstream version.  In the future, it may provide
 the option of installing directly from the upstream version, even if
 that version is not yet in the distribution.
@@ -566,6 +571,21 @@ Installing, removing, or upgrading packages from a generation that has
 been rolled back to overwrites previous future generations.  Thus, the
 history of a profile's generations is always linear.
 
+@item --search-paths
+@cindex search paths
+Report environment variable definitions, in Bash syntax, that may be
+needed in order to use the set of installed packages.  These environment
+variables are used to specify @dfn{search paths} for files used by some
+of the installed packages.
+
+For example, GCC needs the @code{CPATH} and @code{LIBRARY_PATH}
+environment variables to be defined so it can look for headers and
+libraries in the user's profile (@pxref{Environment Variables,,, gcc,
+Using the GNU Compiler Collection (GCC)}).  If GCC and, say, the C
+library are installed in the profile, then @code{--search-paths} will
+suggest setting these variables to @code{@var{profile}/include} and
+@code{@var{profile}/lib}, respectively.
+
 @item --profile=@var{profile}
 @itemx -p @var{profile}
 Use @var{profile} instead of the user's default profile.
diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm
index c5656efc14..560b673618 100644
--- a/guix/scripts/package.scm
+++ b/guix/scripts/package.scm
@@ -330,6 +330,53 @@ but ~a is available upstream~%")
         ((getaddrinfo-error ftp-error) #f)
         (else (apply throw key args))))))
 
+(define* (search-path-environment-variables packages profile
+                                            #:optional (getenv getenv))
+  "Return environment variable definitions that may be needed for the use of
+PACKAGES in PROFILE.  Use GETENV to determine the current settings and report
+only settings not already effective."
+
+  ;; The search path info is not stored in the manifest.  Thus, we infer the
+  ;; search paths from same-named packages found in the distro.
+
+  (define package-in-manifest->package
+    (match-lambda
+     ((name version _ ...)
+      (match (append (find-packages-by-name name version)
+                     (find-packages-by-name name))
+        ((p _ ...) p)
+        (_ #f)))))
+
+  (define search-path-definition
+    (match-lambda
+     (($ <search-path-specification> variable directories separator)
+      (let ((values      (or (and=> (getenv variable)
+                                    (cut string-tokenize* <> separator))
+                             '()))
+            (directories (filter file-exists?
+                                 (map (cut string-append profile
+                                           "/" <>)
+                                      directories))))
+        (if (every (cut member <> values) directories)
+            #f
+            (format #f "export ~a=\"~a\""
+                    variable
+                    (string-join directories separator)))))))
+
+  (let* ((packages     (filter-map package-in-manifest->package packages))
+         (search-paths (delete-duplicates
+                        (append-map package-native-search-paths
+                                    packages))))
+    (filter-map search-path-definition search-paths)))
+
+(define (display-search-paths packages profile)
+  "Display the search path environment variables that may need to be set for
+PACKAGES, in the context of PROFILE."
+  (let ((settings (search-path-environment-variables packages profile)))
+    (unless (null? settings)
+      (format #t (_ "The following environment variable definitions may be needed:~%"))
+      (format #t "~{    ~a~%~}" settings))))
+
 
 ;;;
 ;;; Command-line options.
@@ -354,6 +401,8 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n"))
   -u, --upgrade[=REGEXP] upgrade all the installed packages matching REGEXP"))
   (display (_ "
       --roll-back        roll back to the previous generation"))
+  (display (_ "
+      --search-paths     display needed environment variable definitions"))
   (newline)
   (display (_ "
   -p, --profile=PROFILE  use PROFILE instead of the user's default profile"))
@@ -408,6 +457,9 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n"))
         (option '("roll-back") #f #f
                 (lambda (opt name arg result)
                   (alist-cons 'roll-back? #t result)))
+        (option '("search-paths") #f #f
+                (lambda (opt name arg result)
+                  (cons `(query search-paths) result)))
         (option '(#\p "profile") #t #f
                 (lambda (opt name arg result)
                   (alist-cons 'profile arg
@@ -728,7 +780,9 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n"))
                                 (build-derivations (%store) (list prof-drv)))
                               (begin
                                 (switch-symlinks name prof)
-                                (switch-symlinks profile name))))))))))
+                                (switch-symlinks profile name)
+                                (display-search-paths packages
+                                                      profile))))))))))
 
   (define (process-query opts)
     ;; Process any query specified by OPTS.  Return #t when a query was
@@ -776,6 +830,16 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n"))
            (for-each (cute package->recutils <> (current-output-port))
                      (find-packages-by-description regexp))
            #t))
+
+        (('search-paths)
+         (let* ((manifest (profile-manifest profile))
+                (packages (manifest-packages manifest))
+                (settings (search-path-environment-variables packages
+                                                             profile
+                                                             (const #f))))
+           (format #t "~{~a~%~}" settings)
+           #t))
+
         (_ #f))))
 
   (let ((opts (parse-options)))
diff --git a/tests/guix-package.sh b/tests/guix-package.sh
index 7b101aa501..5a514a0dc0 100644
--- a/tests/guix-package.sh
+++ b/tests/guix-package.sh
@@ -47,6 +47,10 @@ test -L "$profile" && test -L "$profile-1-link"
 ! test -f "$profile-2-link"
 test -f "$profile/bin/guile"
 
+# No search path env. var. here.
+guix package --search-paths -p "$profile"
+test "`guix package --search-paths -p "$profile" | wc -l`" = 0
+
 # Check whether we have network access.
 if guile -c '(getaddrinfo "www.gnu.org" "80" AI_NUMERICSERV)' 2> /dev/null
 then
@@ -119,6 +123,10 @@ then
     rm "$profile-1-link"
     guix package --bootstrap -p "$profile" --roll-back
     test "`readlink_base "$profile"`" = "$profile-0-link"
+
+    # Make sure LIBRARY_PATH gets listed by `--search-paths'.
+    guix package --bootstrap -p "$profile" -i guile-bootstrap -i gcc-bootstrap
+    guix package --search-paths -p "$profile" | grep LIBRARY_PATH
 fi
 
 # Make sure the `:' syntax works.