* gnu/packages/patches/glibc-versioned-locpath.patch: New file.
* gnu-system.am (dist_patch_DATA): Add it.
* gnu/packages/base.scm (glibc)[source]: Use it.
  [arguments]: Remove explicit version sub-directory from
  libc_cv_localedir.
  (glibc-locales, glibc-utf8-locales): Write to a VERSION
  sub-directory.
---
 gnu-system.am                                      |  1 +
 gnu/packages/base.scm                              | 17 ++++----
 gnu/packages/patches/glibc-versioned-locpath.patch | 47 ++++++++++++++++++++++
 3 files changed, 56 insertions(+), 9 deletions(-)
 create mode 100644 gnu/packages/patches/glibc-versioned-locpath.patch

diff --git a/gnu-system.am b/gnu-system.am
index aba8f8d..3aa9144 100644
--- a/gnu-system.am
+++ b/gnu-system.am
@@ -473,6 +473,7 @@ dist_patch_DATA =						\
   gnu/packages/patches/glibc-ldd-x86_64.patch			\
   gnu/packages/patches/glibc-locales.patch			\
   gnu/packages/patches/glibc-o-largefile.patch			\
+  gnu/packages/patches/glibc-versioned-locpath.patch		\
   gnu/packages/patches/gmp-arm-asm-nothumb.patch		\
   gnu/packages/patches/gnucash-price-quotes-perl.patch		\
   gnu/packages/patches/gnutls-doc-fix.patch			\
diff --git a/gnu/packages/base.scm b/gnu/packages/base.scm
index 337fdae..443c54e 100644
--- a/gnu/packages/base.scm
+++ b/gnu/packages/base.scm
@@ -477,6 +477,7 @@ store.")
             (patches (map search-patch
                           '("glibc-ldd-x86_64.patch"
                             "glibc-guix-locpath.patch"
+                            "glibc-versioned-locpath.patch"
                             "glibc-o-largefile.patch")))))
    (build-system gnu-build-system)
 
@@ -510,16 +511,12 @@ store.")
             ;; Set the default locale path.  In practice, $LOCPATH may be
             ;; defined to point whatever locales users want.  However, setuid
             ;; binaries don't honor $LOCPATH, so they'll instead look into
-            ;; $libc_cv_localedir; we choose /run/current-system/locale/X.Y,
+            ;; $libc_cv_localedir; we choose /run/current-system/locale
             ;; with the idea that it is going to be populated by the sysadmin.
-            ;; The "X.Y" sub-directory is because locale data formats are
-            ;; incompatible across libc versions; see
-            ;; <https://lists.gnu.org/archive/html/guix-devel/2015-08/msg00737.html>.
             ;;
             ;; `--localedir' is not honored, so work around it.
             ;; See <http://sourceware.org/ml/libc-alpha/2013-03/msg00093.html>.
-            (string-append "libc_cv_localedir=/run/current-system/locale/"
-                           ,version)
+            "libc_cv_localedir=/run/current-system/locale"
 
             (string-append "--with-headers="
                            (assoc-ref %build-inputs "linux-headers")
@@ -655,7 +652,8 @@ the 'share/locale' sub-directory of this package.")
                    ;; Use $(libdir)/locale as is the case by default.
                    (list (string-append "libc_cv_localedir="
                                         (assoc-ref %outputs "out")
-                                        "/lib/locale")))))))))
+                                        "/lib/locale/"
+                                        ,(package-version glibc))))))))))
 
 (define-public glibc-utf8-locales
   (package
@@ -664,7 +662,7 @@ the 'share/locale' sub-directory of this package.")
     (source #f)
     (build-system trivial-build-system)
     (arguments
-     '(#:modules ((guix build utils))
+     `(#:modules ((guix build utils))
        #:builder (begin
                    (use-modules (srfi srfi-1)
                                 (guix build utils))
@@ -672,7 +670,8 @@ the 'share/locale' sub-directory of this package.")
                    (let* ((libc      (assoc-ref %build-inputs "glibc"))
                           (gzip      (assoc-ref %build-inputs "gzip"))
                           (out       (assoc-ref %outputs "out"))
-                          (localedir (string-append out "/lib/locale")))
+                          (localedir (string-append out "/lib/locale/"
+                                                    ,version)))
                      ;; 'localedef' needs 'gzip'.
                      (setenv "PATH" (string-append libc "/bin:" gzip "/bin"))
 
diff --git a/gnu/packages/patches/glibc-versioned-locpath.patch b/gnu/packages/patches/glibc-versioned-locpath.patch
new file mode 100644
index 0000000..b643399
--- /dev/null
+++ b/gnu/packages/patches/glibc-versioned-locpath.patch
@@ -0,0 +1,47 @@
+The format of locale data can be incompatible between libc versions, and
+loading incompatible data can lead to 'setlocale' returning EINVAL at best
+or triggering an assertion failure at worst.  See
+https://lists.gnu.org/archive/html/guix-devel/2015-09/msg00717.html
+for background information.
+
+To address that, this patch changes libc to look for locale data in
+version-specific sub-directories.  So, if LOCPATH=/foo:/bar, locale data
+is searched for in /foo/X.Y and /bar/X.Y, where X.Y is the libc version
+number.
+
+That way, a single 'LOCPATH' setting can work even if different libc versions
+coexist on the system.
+
+--- a/intl/l10nflist.c
++++ b/intl/l10nflist.c
+@@ -25,6 +25,10 @@
+ # include <config.h>
+ #endif
+ 
++#ifdef _LIBC
++# include <version.h>
++#endif
++
+ #include <string.h>
+ 
+ #if defined _LIBC || defined HAVE_ARGZ_H
+@@ -164,6 +168,9 @@ _nl_make_l10nflist (struct loaded_l10nfile **l10nfile_list,
+ 
+   /* Allocate room for the full file name.  */
+   abs_filename = (char *) malloc (dirlist_len
++#ifdef _LIBC
++				  + strlen (VERSION) + 1
++#endif
+ 				  + strlen (language)
+ 				  + ((mask & XPG_TERRITORY) != 0
+ 				     ? strlen (territory) + 1 : 0)
+@@ -185,6 +192,10 @@ _nl_make_l10nflist (struct loaded_l10nfile **l10nfile_list,
+   memcpy (abs_filename, dirlist, dirlist_len);
+   __argz_stringify (abs_filename, dirlist_len, ':');
+   cp = abs_filename + (dirlist_len - 1);
++#ifdef _LIBC
++  *cp++ = '/';
++  cp = stpcpy (cp, VERSION);
++#endif
+   *cp++ = '/';
+   cp = stpcpy (cp, language);

Reply via email to