unofficial mirror of guix-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Jan Nieuwenhuizen <janneke@gnu.org>
To: "Ludovic Courtès" <ludo@gnu.org>
Cc: guix-devel@gnu.org, bootstrappable@freelists.org
Subject: Re: [bootstrappable] diverse double compilation: using $ORIGIN?
Date: Fri, 10 Nov 2017 20:19:17 +0100	[thread overview]
Message-ID: <87efp6x7pm.fsf@gnu.org> (raw)
In-Reply-To: <87k1z4668j.fsf@gnu.org> (Jan Nieuwenhuizen's message of "Sun, 05 Nov 2017 17:27:24 +0100")

[-- Attachment #1: Type: text/plain, Size: 1868 bytes --]

Jan Nieuwenhuizen writes:

>>> Usage: guix build gcc-dcc
>>>
>>> Building gcc-dcc tests the diverse double compilation property
>>> of the gcc that Guix is using.
>>>
>>> * gnu/packages/bootstrappable.scm: New file.
>>> * gnu/local.mk (GNU_SYSTEM_MODULES): Add it.
>>
>> Awesome!  Does it build fine out-of-the-box?  I didn’t expect it to be
>> “this easy.”  :-)
>
> I got very positive feedback from a slightly guix-sceptic person saying
> something like: you lisp guys can do quite a lot with very little code.
>
> However, all this patch adds is a test that fails: gcc built with gcc is
> not bit-for-bit the same as gcc built with clang.
>
> Since then I have included the build-path-prefix-map patch, use -rpath
> $ORIGIN instead of -rpath "-lib", switched to gcc-7.2.0.  Still, no
> bit-reproducibility.
>
> I'll be sending updated patches soon.

Well, that took more time than I expected.

I switched from 7.2.0 to 4.7.4 as the first target for diverse double
compilation as it seems that 7.2 uses some non-reproducible hash map
that I cannot track down _and_ 4.7.x is the latest bootstrappable gcc.

Finally, I succeeded in building repro-gcc@4.7.4 using $ORIGIN for
rpath.  However, gcc-ddc@4.7.4 still shows that some absolute file names
are embedded in bin/gcc (yes, I know cpp, cc1 and ../lib* hold most of
the functionality):

    /gnu/store/zw672zcmykdwzm4x7l098hb94c34ak85-repro-gcc-4.7.4/bin/
    /gnu/store/zw672zcmykdwzm4x7l098hb94c34ak85-repro-gcc-4.7.4/lib/gcc/
    /gnu/store/zw672zcmykdwzm4x7l098hb94c34ak85repro-gcc-4.7.4._ROOT

the first one most probably comes from

    static const char *const standard_bindir_prefix = STANDARD_BINDIR_PREFIX;

I haven't looked a the other two yet.  I'm attaching the diffoscope diff
and the new patch.  Could do with some help here.

Thanks,
janneke


[-- Attachment #2: 0001-gnu-Add-clang-gcc-gcc-ddc.-WIP.patch --]
[-- Type: text/x-patch, Size: 85165 bytes --]

From 761ec12aa3a34cd3b95a1c3d828d8bb45558d383 Mon Sep 17 00:00:00 2001
From: Jan Nieuwenhuizen <janneke@gnu.org>
Date: Thu, 2 Nov 2017 06:52:46 +0100
Subject: [PATCH] gnu: Add clang-gcc, gcc-ddc.  WIP

Usage: guix build gcc-dcc

Building gcc-dcc tests the diverse double compilation property
of the gcc that Guix is using.

gcc-dcc is a meta-package that depends on repro-gcc-4.7.4 and on
clang-gcc-4.7.4 (the same GCC built with clang).  The builder
checks if both gcc's are bit-by-bit identical and fails if
they differ.

* gnu/packages/patches/gcc-4-build-path-prefix-map.patch: New file.
* gnu/packages/patches/gcc-7-build-path-prefix-map.patch: New file.
* gnu/packages/bootstrappable.scm: New file.
* gnu/local.mk (GNU_SYSTEM_MODULES,dist_patch_DATA): Add them.
---
 gnu/local.mk                                       |   2 +
 gnu/packages/bootstrappable.scm                    | 356 ++++++++
 .../patches/gcc-4-build-path-prefix-map.patch      | 780 +++++++++++++++++
 ...fns-fix-mismatch-in-gnu_inline-attributes.patch |  65 ++
 .../gcc-5-reproducibility-drop-profile.patch       |  36 +
 .../patches/gcc-7-build-path-prefix-map.patch      | 934 +++++++++++++++++++++
 6 files changed, 2173 insertions(+)
 create mode 100644 gnu/packages/bootstrappable.scm
 create mode 100644 gnu/packages/patches/gcc-4-build-path-prefix-map.patch
 create mode 100644 gnu/packages/patches/gcc-4-cfns-fix-mismatch-in-gnu_inline-attributes.patch
 create mode 100644 gnu/packages/patches/gcc-5-reproducibility-drop-profile.patch
 create mode 100644 gnu/packages/patches/gcc-7-build-path-prefix-map.patch

diff --git a/gnu/local.mk b/gnu/local.mk
index 71392d86c..335678160 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -79,6 +79,7 @@ GNU_SYSTEM_MODULES =				\
   %D%/packages/boost.scm			\
   %D%/packages/bootloaders.scm			\
   %D%/packages/bootstrap.scm			\
+  %D%/packages/bootstrappable.scm		\
   %D%/packages/build-tools.scm			\
   %D%/packages/busybox.scm			\
   %D%/packages/c.scm				\
@@ -646,6 +647,7 @@ dist_patch_DATA =						\
   %D%/packages/patches/gcc-5-source-date-epoch-2.patch		\
   %D%/packages/patches/gcc-6-arm-none-eabi-multilib.patch	\
   %D%/packages/patches/gcc-6-cross-environment-variables.patch	\
+  %D%/packages/patches/gcc-7-build-path-prefix-map.patch	\
   %D%/packages/patches/gcr-disable-failing-tests.patch		\
   %D%/packages/patches/gcr-fix-collection-tests-to-work-with-gpg-21.patch	\
   %D%/packages/patches/gd-fix-tests-on-i686.patch		\
diff --git a/gnu/packages/bootstrappable.scm b/gnu/packages/bootstrappable.scm
new file mode 100644
index 000000000..cbd7592db
--- /dev/null
+++ b/gnu/packages/bootstrappable.scm
@@ -0,0 +1,356 @@
+;;; GNU Guix --- Functional package management for GNU
+;;; Copyright © 2017 Jan Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; 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 (gnu packages bootstrappable)
+  #:use-module ((guix licenses)
+                #:select (gpl3+))
+  #:use-module (gnu packages)
+  #:use-module (gnu packages bootstrap) ; glibc-dynamic-linker
+  #:use-module (gnu packages gcc)
+  #:use-module (gnu packages llvm)
+
+  #:use-module (gnu packages package-management) ; diffosscope
+  #:use-module (gnu packages acl)                ; diffosscope->getfacl
+  #:use-module (gnu packages base)               ; diffoscope->cmp
+  #:use-module (gnu packages vim)                ; diffosscope->xxd
+
+  #:use-module (guix download)
+  #:use-module (guix packages)
+  #:use-module (guix build-system trivial)
+  #:use-module (guix utils)
+  #:use-module (srfi srfi-1))
+
+
+(define-public gcc-1.4
+  (package
+    (inherit hello)
+    (name "gcc")
+    (version "1.40")
+    (source (origin
+              (method url-fetch)
+              (uri (string-append "http://ftp.gnu.org/pub/old-gnu/gcc/gcc-"
+                                  version "/gcc-" version ".tar.bz2"))
+              (sha256
+               (base32
+                "0z4wzpc3cdlzn35iwkc8xsykcxz23msxgsc96r8f5s124rncadd8"))))
+    (arguments
+     `(#:make-flags ("CC=gcc")
+       #:phases
+       (modify-phases %standard-phases
+         (delete 'configure))))))
+
+(define-public gcc-4.7-$ORIGIN
+  (package
+    (inherit gcc-4.7)
+    (name "gcc-$ORIGIN")
+    ;; Using $ORIGIN we cannot have a separate "lib" output
+    ;; so let's remove lib output
+    (outputs '("out"                    ;commands, etc. (60+ MiB)
+               "debug"))                ;debug symbols of run-time libraries
+    (arguments
+     (substitute-keyword-arguments (package-arguments gcc-4.7)
+       ((#:configure-flags original-flags)
+        ;;--with-stage1-ldflags="-Wl,-rpath,/path/to/isl/lib,-rpath,/path/to/cloog/lib,-rpath,/path/to/gmp/lib"
+        ;;`(cons "--with-boot-ldflags=-Wl,-rpath,\\$ORIGIN/../lib" ,original-flags)
+        `(cons* "--enable-languages=c"
+                "--enable-relocatable"
+                "--disable-nls"
+                "--disable-rpath"
+                ;;"--with-boot-ldflags=-Wl,-rpath,\\$$\\$$ORIGIN/../lib -Wl,-rpath,../lib -Wl,-rpath=../prev-x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/"
+                (delete "--enable-languages=c,c++" ,original-flags)))
+       ((#:phases original-phases)
+        `(modify-phases ,original-phases
+           (replace 'pre-configure
+             (lambda* (#:key inputs outputs #:allow-other-keys)
+               (let* ((libdir-suffix (or ,(%current-target-system) ""))
+                      (libdir (string-append
+                               (assoc-ref outputs "out")
+                               libdir-suffix))
+                      (origin-libdir (string-append "$ORIGIN/.." libdir-suffix))
+                      (libc (assoc-ref inputs "libc")))
+                 (when libc
+                   ;; The following is not performed for `--without-headers'
+                   ;; cross-compiler builds.
+
+                   ;; Join multi-line definitions of GLIBC_DYNAMIC_LINKER* into a
+                   ;; single line, to allow the next step to work properly.
+                   (for-each
+                    (lambda (x)
+                      (substitute* (find-files "gcc/config"
+                                               "^(linux|gnu|sysv4)(64|-elf|-eabi)?\\.h$")
+                        (("(#define (GLIBC|GNU_USER)_DYNAMIC_LINKER.*)\\\\\n$" _ line)
+                         line)))
+                    '(1 2 3))
+
+                   ;; Fix the dynamic linker's file name.
+                   (substitute* (find-files "gcc/config"
+                                            "^(linux|gnu|sysv4)(64|-elf|-eabi)?\\.h$")
+                     (("#define (GLIBC|GNU_USER)_DYNAMIC_LINKER([^ \t]*).*$"
+                       _ gnu-user suffix)
+                      (format #f "#define ~a_DYNAMIC_LINKER~a \"~a\"~%"
+                              gnu-user suffix
+                              (string-append libc ,(glibc-dynamic-linker)))))
+
+                   ;; Tell where to find libstdc++, libc, and `?crt*.o', except
+                   ;; `crt{begin,end}.o', which come with GCC.
+                   (substitute* (find-files "gcc/config"
+                                            "^gnu-user.*\\.h$")
+                     (("#define GNU_USER_TARGET_LIB_SPEC (.*)$" _ suffix)
+                      ;; Help libgcc_s.so be found (see also below.)  Always use
+                      ;; '-lgcc_s' so that libgcc_s.so is always found by those
+                      ;; programs that use 'pthread_cancel' (glibc dlopens
+                      ;; libgcc_s.so when pthread_cancel support is needed, but
+                      ;; having it in the application's RUNPATH isn't enough; see
+                      ;; <http://sourceware.org/ml/libc-help/2013-11/msg00023.html>.)
+                      ;;
+                      ;; NOTE: The '-lgcc_s' added below needs to be removed in a
+                      ;; later phase of %gcc-static.  If you change the string
+                      ;; below, make sure to update the relevant code in
+                      ;; %gcc-static package as needed.
+                      (format #f "#define GNU_USER_TARGET_LIB_SPEC \
+\"-L~a/lib %{!static:-rpath=~a/lib %{!static-libgcc:\
+-rpath=~a/lib \
+-rpath=~a/gcc \
+-rpath=~a/../lib \
+-rpath=~a/../gcc \
+-rpath=~a/../../lib \
+-rpath=~a/../../../lib \
+-rpath=~a/../../../../lib \
+-lgcc_s}} \" ~a"
+                              libc libc
+                              origin-libdir origin-libdir origin-libdir origin-libdir
+                              origin-libdir origin-libdir origin-libdir
+                              suffix))
+                     (("#define GNU_USER_TARGET_STARTFILE_SPEC.*$" line)
+                      (format #f "#define STANDARD_STARTFILE_PREFIX_1 \"~a/lib\"
+#define STANDARD_STARTFILE_PREFIX_2 \"\"
+~a"
+                              libc line)))
+
+                   ;; The rs6000 (a.k.a. powerpc) config in GCC does not use
+                   ;; GNU_USER_* defines.  Do the above for this case.
+                   (substitute*
+                       "gcc/config/rs6000/sysv4.h"
+                     (("#define LIB_LINUX_SPEC (.*)$" _ suffix)
+                      (format #f "#define LIB_LINUX_SPEC \
+\"-L~a/lib %{!static:-rpath=~a/lib %{!static-libgcc:-rpath=~a/lib -lgcc_s}} \" ~a"
+                              libc libc origin-libdir suffix))
+                     (("#define	STARTFILE_LINUX_SPEC.*$" line)
+                      (format #f "#define STANDARD_STARTFILE_PREFIX_1 \"~a/lib\"
+#define STANDARD_STARTFILE_PREFIX_2 \"\"
+~a"
+                              libc line))))
+
+                 ;; Don't retain a dependency on the build-time sed.
+                 (substitute* "fixincludes/fixincl.x"
+                   (("static char const sed_cmd_z\\[\\] =.*;")
+                    "static char const sed_cmd_z[] = \"sed\";"))
+
+                 ;; Aarch64 support didn't land in GCC until the 4.8 series.
+                 (when (file-exists? "gcc/config/aarch64")
+                   ;; Force Aarch64 libdir to be /lib and not /lib64
+                   (substitute* "gcc/config/aarch64/t-aarch64-linux"
+                     (("lib64") "lib")))
+
+                 (when (file-exists? "libbacktrace")
+                   ;; GCC 4.8+ comes with libbacktrace.  By default it builds
+                   ;; with -Werror, which fails with a -Wcast-qual error in glibc
+                   ;; 2.21's stdlib-bsearch.h.  Remove -Werror.
+                   (substitute* "libbacktrace/configure"
+                     (("WARN_FLAGS=(.*)-Werror" _ flags)
+                      (string-append "WARN_FLAGS=" flags)))
+
+                   (when (file-exists? "libsanitizer/libbacktrace")
+                     ;; Same in libsanitizer's bundled copy (!) found in 4.9+.
+                     (substitute* "libsanitizer/libbacktrace/Makefile.in"
+                       (("-Werror")
+                        ""))))
+
+                 ;; Add a RUNPATH to libstdc++.so so that it finds libgcc_s.
+                 ;; See <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=32354>
+                 ;; and <http://bugs.gnu.org/20358>.
+                 (substitute* "libstdc++-v3/src/Makefile.in"
+                   (("^OPT_LDFLAGS = ")
+                    ;;"OPT_LDFLAGS = -Wl,-rpath=$(libdir) "
+                    (string-append "OPT_LDFLAGS ="
+                                   " '-Wl,-rpath=$" origin-libdir "//lib'"
+                                   " '-Wl,-rpath=$" origin-libdir "//gcc'"
+                                   " '-Wl,-rpath=$" origin-libdir "//../lib'"
+                                   " '-Wl,-rpath=$" origin-libdir "//../gcc' "
+                                   " '-Wl,-rpath=$" origin-libdir "//../lib'"
+                                   ;; FIXME?
+;;; /gnu/store/qxwsck61dm7h3n1pgzzs2psj06ihsslj-repro-gcc-4.7.4/libexec/gcc/x86_64-unknown-linux-gnu/4.7.4/install-tools/fixincl: error: depends on 'libgcc_s.so.1'
+                                   " '-Wl,-rpath=$" origin-libdir "//../../lib'"
+                                   " '-Wl,-rpath=$" origin-libdir "//../../../lib'"
+
+                                   )))
+
+                 ;; Move libstdc++*-gdb.py to the "lib" output to avoid a
+                 ;; circularity between "out" and "lib".  (Note:
+                 ;; --with-python-dir is useless because it imposes $(prefix) as
+                 ;; the parent directory.)
+                 (substitute* "libstdc++-v3/python/Makefile.in"
+                   (("pythondir = .*$")
+                    (string-append "pythondir = " libdir "/share"
+                                   "/gcc-$(gcc_version)/python\n")))
+
+                 ;; Avoid another circularity between the outputs: this #define
+                 ;; ends up in auto-host.h in the "lib" output, referring to
+                 ;; "out".  (This variable is used to augment cpp's search path,
+                 ;; but there's nothing useful to look for here.)
+                 (substitute* "gcc/config.in"
+                   (("PREFIX_INCLUDE_DIR")
+                    "PREFIX_INCLUDE_DIR_isnt_necessary_here")))))
+
+           (replace 'post-configure
+             (lambda _
+               ;; Don't store configure flags, to avoid retaining references to
+               ;; build-time dependencies---e.g., `--with-ppl=/gnu/store/xxx'.
+               (substitute* "Makefile"
+                 (("^TOPLEVEL_CONFIGURE_ARGUMENTS=(.*)$" _ rest)
+                  "TOPLEVEL_CONFIGURE_ARGUMENTS=\n"))))))))))
+
+
+(define-public repro-gcc-4.7
+  (package
+    (inherit gcc-4.7-$ORIGIN)
+    (source
+     (origin
+       (inherit (package-source gcc-4.7-$ORIGIN))
+       (patches (append ((compose origin-patches package-source) gcc-4.7)
+                        (search-patches "gcc-5-reproducibility-drop-profile.patch"
+                                        ;;"gcc-4-compile-with-gcc-5.patch"
+                                        "gcc-4-build-path-prefix-map.patch")))))
+    (name "repro-gcc")
+    (version "4.7.4")
+    (arguments
+     (substitute-keyword-arguments (package-arguments gcc-4.7-$ORIGIN)
+       ((#:phases original-phases)
+        `(modify-phases ,original-phases
+           (add-before 'configure 'build-prefix-path
+             (lambda* (#:key inputs #:allow-other-keys)
+               (setenv "BUILD_PATH_PREFIX_MAP"
+                       (string-append "gcc" "-" ,version "=" (getcwd)))
+               (format (current-error-port)
+                       "BUILD_PATH_PREFIX_MAP=~s\n"
+                       (getenv "BUILD_PATH_PREFIX_MAP"))))))))))
+
+(define-public repr2-gcc-4.7
+  (package
+    (inherit repro-gcc-4.7)
+    (name "repr2-gcc")))
+
+(define-public repro-gcc-7
+  (package
+    (inherit gcc-4.7-$ORIGIN)
+    (source
+     (origin
+       (inherit (package-source gcc-7))
+       (patches (append (search-patches "gcc-5-reproducibility-drop-profile.patch"
+                                        "gcc-7-build-path-prefix-map.patch")
+                        ((compose origin-patches package-source) gcc-7)))))
+    (name "repro-gcc")
+    (version "7.2.0")
+    (arguments
+     (substitute-keyword-arguments (package-arguments gcc-4.7-$ORIGIN)
+       ((#:phases original-phases)
+        `(modify-phases ,original-phases
+           (add-before 'configure 'build-prefix-path
+             (lambda* (#:key inputs #:allow-other-keys)
+               (setenv "BUILD_PATH_PREFIX_MAP"
+                       (string-append "gcc" "-" ,version "=" (getcwd)))
+               (format (current-error-port)
+                       "BUILD_PATH_PREFIX_MAP=~s\n"
+                       (getenv "BUILD_PATH_PREFIX_MAP"))))))))))
+
+(define-public repr2-gcc-7
+  (package
+    (inherit repro-gcc-7)
+    (name "repr2-gcc")))
+
+(define-public clang-gcc-7
+  (package
+    (inherit repro-gcc-7)
+    (name "clang-gcc")
+    (native-inputs `(("clang" ,clang)
+                     ,@(alist-delete "gcc" (package-native-inputs gcc-7))))
+    (arguments
+     (substitute-keyword-arguments (package-arguments repro-gcc-7)
+       ((#:phases original-phases)
+        `(modify-phases ,original-phases
+           (add-before 'configure 'setenv
+             (lambda* (#:key inputs #:allow-other-keys)
+               (let ((clang (assoc-ref inputs "clang")))
+                 (setenv "CC" (string-append clang "/bin/clang"))
+                 (setenv "CXX "(string-append clang "/bin/clang++")))))))))))
+
+(define-public gcc-ddc-gcc+clang
+  (package
+    (name "gcc-ddc")
+    (version "4.7.4")
+    (source #f)
+    (native-inputs `(;;("clang-gcc" ,clang-gcc-7)
+                     ("clang-gcc" ,repr2-gcc-4.7)
+                     ("gcc" ,repro-gcc-4.7)
+
+                     ("diffoscope" ,diffoscope)
+                     ("acl" ,acl)       ; For diffoscope
+                     ("binutils" ,binutils)
+                     ("coreutils" ,coreutils)
+                     ("diffutils" ,diffutils)
+                     ("xxd" ,xxd)))
+    (build-system trivial-build-system)
+    (arguments
+     `(#:modules ((guix build utils))
+       #:builder
+       (begin
+         (use-modules (guix build utils))
+         (let* ((diffoscope (assoc-ref %build-inputs "diffoscope"))
+                (acl (assoc-ref %build-inputs "acl"))
+                (binutils (assoc-ref %build-inputs "binutils"))
+                (coreutils (assoc-ref %build-inputs "coreutils"))
+                (diffutils (assoc-ref %build-inputs "diffutils"))
+                (xxd (assoc-ref %build-inputs "xxd"))
+                (gcc (assoc-ref %build-inputs "gcc"))
+                (gcc/bin/gcc (string-append gcc "/bin/gcc"))
+                (clang-gcc (assoc-ref %build-inputs "clang-gcc"))
+                (clang-gcc/bin/gcc (string-append clang-gcc "/bin/gcc")))
+           ;; diffoscope.exc.RequiredToolNotFound: cmp
+           ;; diffoscope.comparators.directory: 'stat' not found! Is PATH wrong?
+           ;; FileNotFoundError: [Errno 2] No such file or directory: 'readelf'
+           ;; diffoscope.comparators.directory: Unable to find 'getfacl'
+           (setenv "PATH" (string-append diffoscope "/bin:"
+
+                                         acl "/acl:"
+                                         binutils "/bin:"
+                                         coreutils "/bin:"
+                                         diffutils "/bin:"
+                                         xxd "/bin:"))
+           ;; ?? xxd not available in path. Falling back to Python hexlify.
+           ;; diffoscope.presenters.formats: Console is unable to print Unicode characters. Set e.g. PYTHONIOENCODING=utf-8
+           (setenv "PYTHONIOENCODING" "utf-8")
+           ;; for starters, only check the gcc binary
+           (zero? (system* "diffoscope" gcc/bin/gcc clang-gcc/bin/gcc))
+           ;;(zero? (system* "diffoscope" gcc clang-gcc))
+           ))))
+    (synopsis "test gcc+clang DDC property for gcc-7.2.0")
+    (description "gcc-dcc is a meta-package that depends on repro-gcc-7.2.0
+and on clang-gcc-7.2.0 (the same GCC built with clang).  The builder checks if
+both gcc's are bit-for-bit identical and fails if they differ.")
+    (home-page "http://bootstrappable.org")
+    (license gpl3+)))
diff --git a/gnu/packages/patches/gcc-4-build-path-prefix-map.patch b/gnu/packages/patches/gcc-4-build-path-prefix-map.patch
new file mode 100644
index 000000000..738a59c8d
--- /dev/null
+++ b/gnu/packages/patches/gcc-4-build-path-prefix-map.patch
@@ -0,0 +1,780 @@
+From 1bfd15d4f07f7d76ec399b1a45bc16c404f1465a Mon Sep 17 00:00:00 2001
+From: Jan Nieuwenhuizen <janneke@gnu.org>
+Date: Mon, 6 Nov 2017 07:35:24 +0100
+Subject: [PATCH] backport build path prefix map. WIP
+
+---
+ gcc/c-family/c-common.c                            |  20 ++
+ gcc/c-family/c-common.h                            |   5 +
+ gcc/c-family/c-lex.c                               |   1 +
+ gcc/cp/cfns.gperf                                  |   2 +-
+ gcc/debug.h                                        |   1 +
+ gcc/final.c                                        |  54 +++--
+ gcc/opts-global.c                                  |   2 +
+ gcc/testsuite/gcc.dg/cpp/build_path_prefix_map-1.c |  11 +
+ gcc/testsuite/gcc.dg/cpp/build_path_prefix_map-2.c |  12 ++
+ .../gcc.dg/debug/dwarf2/build_path_prefix_map-1.c  |   9 +
+ .../gcc.dg/debug/dwarf2/build_path_prefix_map-2.c  |   8 +
+ include/prefix-map.h                               | 108 ++++++++++
+ libcpp/include/cpplib.h                            |   3 +
+ libcpp/init.c                                      |   3 +
+ libcpp/internal.h                                  |   5 +
+ libcpp/macro.c                                     |  16 ++
+ libiberty/Makefile.in                              |  14 +-
+ libiberty/prefix-map.c                             | 226 +++++++++++++++++++++
+ 18 files changed, 467 insertions(+), 33 deletions(-)
+ create mode 100644 gcc/testsuite/gcc.dg/cpp/build_path_prefix_map-1.c
+ create mode 100644 gcc/testsuite/gcc.dg/cpp/build_path_prefix_map-2.c
+ create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/build_path_prefix_map-1.c
+ create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/build_path_prefix_map-2.c
+ create mode 100644 include/prefix-map.h
+ create mode 100644 libiberty/prefix-map.c
+
+diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
+index 82a2b8d6c..b4ca42b73 100644
+--- a/gcc/c-family/c-common.c
++++ b/gcc/c-family/c-common.c
+@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3.  If not see
+ 
+ #include "config.h"
+ #include "system.h"
++#include "prefix-map.h"
+ #include "coretypes.h"
+ #include "tm.h"
+ #include "intl.h"
+@@ -10736,4 +10737,23 @@ build_userdef_literal (tree suffix_id, tree value, tree num_string)
+   return literal;
+ }
+ 
++/* Read BUILD_PATH_PREFIX_MAP from environment to have deterministic relative
++   paths to replace embedded absolute paths to get reproducible results.
++   Returns NULL if BUILD_PATH_PREFIX_MAP is badly formed.  */
++
++struct prefix_map **
++cb_get_build_path_prefix_map (cpp_reader *pfile ATTRIBUTE_UNUSED)
++{
++  struct prefix_map **map = XCNEW (struct prefix_map *);
++
++  const char *arg = getenv ("BUILD_PATH_PREFIX_MAP");
++  if (!arg || prefix_map_parse (map, arg))
++    return map;
++
++  free (map);
++  error_at (input_location, "environment variable BUILD_PATH_PREFIX_MAP is "
++	    "not well formed; see the GCC documentation for more details.");
++  return NULL;
++}
++
+ #include "gt-c-family-c-common.h"
+diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
+index 835b13bbc..7591bd6b0 100644
+--- a/gcc/c-family/c-common.h
++++ b/gcc/c-family/c-common.h
+@@ -1116,4 +1116,9 @@ struct GTY(()) tree_userdef_literal {
+ 
+ extern tree build_userdef_literal (tree suffix_id, tree value, tree num_string);
+ 
++/* Read BUILD_PATH_PREFIX_MAP from environment to have deterministic relative
++   paths to replace embedded absolute paths to get reproducible results.
++   Returns NULL if BUILD_PATH_PREFIX_MAP is badly formed.  */
++extern struct prefix_map **cb_get_build_path_prefix_map (cpp_reader *pfile);
++
+ #endif /* ! GCC_C_COMMON_H */
+diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
+index 7e2029ce0..8cef0f2a8 100644
+--- a/gcc/c-family/c-lex.c
++++ b/gcc/c-family/c-lex.c
+@@ -84,6 +84,7 @@ init_c_lex (void)
+   cb->def_pragma = cb_def_pragma;
+   cb->valid_pch = c_common_valid_pch;
+   cb->read_pch = c_common_read_pch;
++  cb->get_build_path_prefix_map = cb_get_build_path_prefix_map;
+ 
+   /* Set the debug callbacks if we can use them.  */
+   if ((debug_info_level == DINFO_LEVEL_VERBOSE
+diff --git a/gcc/cp/cfns.gperf b/gcc/cp/cfns.gperf
+index ba0c487a6..0f9a79ac7 100644
+--- a/gcc/cp/cfns.gperf
++++ b/gcc/cp/cfns.gperf
+@@ -26,7 +26,7 @@ __inline
+ __attribute__ ((__gnu_inline__))
+ #endif
+ #endif
+-const char * libc_name_p (const char *, unsigned int);
++inline const char * libc_name_p (const char *, unsigned int);
+ %}
+ %%
+ # The standard C library functions, for feeding to gperf; the result is used
+diff --git a/gcc/debug.h b/gcc/debug.h
+index 828ede230..1f9a69e56 100644
+--- a/gcc/debug.h
++++ b/gcc/debug.h
+@@ -187,6 +187,7 @@ extern void dwarf2out_switch_text_section (void);
+ 
+ const char *remap_debug_filename (const char *);
+ void add_debug_prefix_map (const char *);
++void add_debug_prefix_map_from_envvar ();
+ 
+ /* For -fdump-go-spec.  */
+ 
+diff --git a/gcc/final.c b/gcc/final.c
+index 718caf154..d72dec2e5 100644
+--- a/gcc/final.c
++++ b/gcc/final.c
+@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3.  If not see
+ #include "config.h"
+ #include "system.h"
+ #include "coretypes.h"
++#include "prefix-map.h"
+ #include "tm.h"
+ 
+ #include "tree.h"
+@@ -1435,22 +1436,9 @@ asm_str_count (const char *templ)
+   return count;
+ }
+ \f
+-/* ??? This is probably the wrong place for these.  */
+-/* Structure recording the mapping from source file and directory
+-   names at compile time to those to be embedded in debug
+-   information.  */
+-typedef struct debug_prefix_map
+-{
+-  const char *old_prefix;
+-  const char *new_prefix;
+-  size_t old_len;
+-  size_t new_len;
+-  struct debug_prefix_map *next;
+-} debug_prefix_map;
+-
+-/* Linked list of such structures.  */
+-debug_prefix_map *debug_prefix_maps;
+ 
++/* Linked list of `struct prefix_map'.  */
++static struct prefix_map *debug_prefix_maps = NULL;
+ 
+ /* Record a debug file prefix mapping.  ARG is the argument to
+    -fdebug-prefix-map and must be of the form OLD=NEW.  */
+@@ -1458,7 +1446,7 @@ debug_prefix_map *debug_prefix_maps;
+ void
+ add_debug_prefix_map (const char *arg)
+ {
+-  debug_prefix_map *map;
++  struct prefix_map *map;
+   const char *p;
+ 
+   p = strchr (arg, '=');
+@@ -1467,7 +1455,7 @@ add_debug_prefix_map (const char *arg)
+       error ("invalid argument %qs to -fdebug-prefix-map", arg);
+       return;
+     }
+-  map = XNEW (debug_prefix_map);
++  map = XNEW (struct prefix_map);
+   map->old_prefix = xstrndup (arg, p - arg);
+   map->old_len = p - arg;
+   p++;
+@@ -1477,28 +1465,32 @@ add_debug_prefix_map (const char *arg)
+   debug_prefix_maps = map;
+ }
+ 
++/* Add debug-prefix-maps from BUILD_PATH_PREFIX_MAP environment variable.  */
++
++void
++add_debug_prefix_map_from_envvar ()
++{
++  const char *arg = getenv ("BUILD_PATH_PREFIX_MAP");
++
++  if (!arg || prefix_map_parse (&debug_prefix_maps, arg))
++    return;
++
++  error ("environment variable BUILD_PATH_PREFIX_MAP is "
++	 "not well formed; see the GCC documentation for more details.");
++}
++
+ /* Perform user-specified mapping of debug filename prefixes.  Return
+    the new name corresponding to FILENAME.  */
+ 
+ const char *
+ remap_debug_filename (const char *filename)
+ {
+-  debug_prefix_map *map;
+-  char *s;
+-  const char *name;
+-  size_t name_len;
++  const char *name = prefix_map_remap_alloca (debug_prefix_maps, filename);
+ 
+-  for (map = debug_prefix_maps; map; map = map->next)
+-    if (filename_ncmp (filename, map->old_prefix, map->old_len) == 0)
+-      break;
+-  if (!map)
++  if (name == filename)
+     return filename;
+-  name = filename + map->old_len;
+-  name_len = strlen (name) + 1;
+-  s = (char *) alloca (name_len + map->new_len);
+-  memcpy (s, map->new_prefix, map->new_len);
+-  memcpy (s + map->new_len, name, name_len);
+-  return ggc_strdup (s);
++
++  return ggc_strdup (name);
+ }
+ \f
+ /* Return true if DWARF2 debug info can be emitted for DECL.  */
+diff --git a/gcc/opts-global.c b/gcc/opts-global.c
+index b93d56fcd..f3c653bc1 100644
+--- a/gcc/opts-global.c
++++ b/gcc/opts-global.c
+@@ -322,6 +322,8 @@ handle_common_deferred_options (void)
+   if (flag_dump_all_passed)
+     enable_rtl_dump_file ();
+ 
++  add_debug_prefix_map_from_envvar ();
++
+   FOR_EACH_VEC_ELT (cl_deferred_option, vec, i, opt)
+     {
+       switch (opt->opt_index)
+diff --git a/gcc/testsuite/gcc.dg/cpp/build_path_prefix_map-1.c b/gcc/testsuite/gcc.dg/cpp/build_path_prefix_map-1.c
+new file mode 100644
+index 000000000..960503813
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/cpp/build_path_prefix_map-1.c
+@@ -0,0 +1,11 @@
++/* __FILE__ should strip BUILD_PATH_PREFIX_MAP if the latter is a prefix. */
++/* { dg-do run } */
++/* { dg-set-compiler-env-var BUILD_PATH_PREFIX_MAP "MACROTEST=$srcdir" } */
++
++int
++main ()
++{
++  if (__builtin_strcmp (__FILE__, "MACROTEST/gcc.dg/cpp/build_path_prefix_map-1.c") != 0)
++    __builtin_abort ();
++  return 0;
++}
+diff --git a/gcc/testsuite/gcc.dg/cpp/build_path_prefix_map-2.c b/gcc/testsuite/gcc.dg/cpp/build_path_prefix_map-2.c
+new file mode 100644
+index 000000000..4b0aacd5e
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/cpp/build_path_prefix_map-2.c
+@@ -0,0 +1,12 @@
++/* __FILE__ should not be relative if BUILD_PATH_PREFIX_MAP is not set, and gcc is
++   asked to compile an absolute filename as is the case with this test.  */
++/* { dg-do run } */
++/* { dg-set-compiler-env-var BUILD_PATH_PREFIX_MAP } */
++
++int
++main ()
++{
++  if (__builtin_strcmp (__FILE__, "./gcc.dg/cpp/build_path_prefix_map-2.c") == 0)
++    __builtin_abort ();
++  return 0;
++}
+diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/build_path_prefix_map-1.c b/gcc/testsuite/gcc.dg/debug/dwarf2/build_path_prefix_map-1.c
+new file mode 100644
+index 000000000..af2b0ed33
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/debug/dwarf2/build_path_prefix_map-1.c
+@@ -0,0 +1,9 @@
++/* DW_AT_comp_dir should be relative if BUILD_PATH_PREFIX_MAP is a prefix of it.  */
++/* { dg-do compile } */
++/* { dg-options "-gdwarf -dA" } */
++/* { dg-set-compiler-env-var BUILD_PATH_PREFIX_MAP "DWARF2TEST=[file dirname [pwd]]" } */
++/* { dg-final { scan-assembler "DW_AT_comp_dir: \"DWARF2TEST/gcc" } } */
++
++void func (void)
++{
++}
+diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/build_path_prefix_map-2.c b/gcc/testsuite/gcc.dg/debug/dwarf2/build_path_prefix_map-2.c
+new file mode 100644
+index 000000000..4c66bf521
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/debug/dwarf2/build_path_prefix_map-2.c
+@@ -0,0 +1,8 @@
++/* DW_AT_comp_dir should be absolute if BUILD_PATH_PREFIX_MAP is not set.  */
++/* { dg-do compile } */
++/* { dg-options "-gdwarf -dA" } */
++/* { dg-final { scan-assembler "DW_AT_comp_dir: \"/" } } */
++
++void func (void)
++{
++}
+diff --git a/include/prefix-map.h b/include/prefix-map.h
+new file mode 100644
+index 000000000..f8edb547e
+--- /dev/null
++++ b/include/prefix-map.h
+@@ -0,0 +1,108 @@
++/* Declarations for manipulating filename prefixes.
++
++   Copyright (C) 2017 Free Software Foundation, Inc.
++
++   This program 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 2, or (at your option)
++   any later version.
++
++   This program 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 this program; if not, write to the Free Software Foundation,
++   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
++
++#ifndef _PREFIX_MAP_H
++#define _PREFIX_MAP_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#ifdef HAVE_STDLIB_H
++#include <stdlib.h>
++#endif
++
++/* Linked-list of mappings from old prefixes to new prefixes.  */
++
++struct prefix_map
++{
++  const char *old_prefix;
++  const char *new_prefix;
++  size_t old_len;
++  size_t new_len;
++  struct prefix_map *next;
++};
++
++
++/* Find a mapping suitable for the given OLD_NAME in the linked list MAP.\
++
++   If a mapping is found, writes a pointer to the non-matching suffix part of
++   OLD_NAME in SUFFIX, and its length in SUF_LEN.
++
++   Returns NULL if there was no suitable mapping.  */
++struct prefix_map *
++prefix_map_find (struct prefix_map *map, const char *old_name,
++		 const char **suffix, size_t *suf_len);
++
++/* Prepend a prefix map before a given SUFFIX.
++
++   The remapped name is written to NEW_NAME and returned as a const pointer. No
++   allocations are performed; the caller must ensure it can hold at least
++   MAP->NEW_LEN + SUF_LEN + 1 characters.  */
++const char *
++prefix_map_prepend (struct prefix_map *map, char *new_name,
++		    const char *suffix, size_t suf_len);
++
++/* Remap a filename.
++
++   Returns OLD_NAME unchanged if there was no remapping, otherwise returns a
++   pointer to newly-allocated memory for the remapped filename.  The memory is
++   allocated by the given ALLOC function, which also determines who is
++   responsible for freeing it.  */
++#define prefix_map_remap_alloc_(map_head, old_name, alloc)		       \
++  __extension__								       \
++  ({									       \
++    const char *__suffix;						       \
++    size_t __suf_len;							       \
++    struct prefix_map *__map;						       \
++    (__map = prefix_map_find ((map_head), (old_name), &__suffix, &__suf_len))  \
++      ? prefix_map_prepend (__map,					       \
++			    (char *) alloc (__map->new_len + __suf_len + 1),   \
++			    __suffix, __suf_len)			       \
++      : (old_name);							       \
++  })
++
++/* Remap a filename.
++
++   Returns OLD_NAME unchanged if there was no remapping, otherwise returns a
++   stack-allocated pointer to the newly-remapped filename.  */
++#define prefix_map_remap_alloca(map_head, old_name) \
++  prefix_map_remap_alloc_ (map_head, old_name, alloca)
++
++
++/* Parse prefix-maps according to the BUILD_PATH_PREFIX_MAP standard.
++
++   The input string value is of the form
++
++     dst[0]=src[0]:dst[1]=src[1]...
++
++   Every dst[i] and src[i] has had "%", "=" and ":" characters replaced with
++   "%#", "%+", and "%." respectively; this function reverses this replacement.
++
++   Rightmost entries are stored at the head of the parsed structure.
++
++   Returns 0 on failure and 1 on success.  */
++int
++prefix_map_parse (struct prefix_map **map_head, const char *arg);
++
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _PREFIX_MAP_H */
+diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h
+index bf59d0162..082770d04 100644
+--- a/libcpp/include/cpplib.h
++++ b/libcpp/include/cpplib.h
+@@ -541,6 +541,9 @@ struct cpp_callbacks
+ 
+   /* Callback that can change a user builtin into normal macro.  */
+   bool (*user_builtin_macro) (cpp_reader *, cpp_hashnode *);
++
++  /* Callback to parse BUILD_PATH_PREFIX_MAP from environment.  */
++  struct prefix_map **(*get_build_path_prefix_map) (cpp_reader *);
+ };
+ 
+ #ifdef VMS
+diff --git a/libcpp/init.c b/libcpp/init.c
+index 5fa82ca9c..270d42b95 100644
+--- a/libcpp/init.c
++++ b/libcpp/init.c
+@@ -231,6 +231,9 @@ cpp_create_reader (enum c_lang lang, hash_table *table,
+   /* Do not force token locations by default.  */
+   pfile->forced_token_location_p = NULL;
+ 
++  /* Initialize build_path_prefix_map to NULL (not yet set).  */
++  pfile->build_path_prefix_map = NULL;
++
+   /* The expression parser stack.  */
+   _cpp_expand_op_stack (pfile);
+ 
+diff --git a/libcpp/internal.h b/libcpp/internal.h
+index 5b3731bba..5b09bf1a4 100644
+--- a/libcpp/internal.h
++++ b/libcpp/internal.h
+@@ -485,6 +485,11 @@ struct cpp_reader
+   const unsigned char *date;
+   const unsigned char *time;
+ 
++  /* Externally set prefix-map to transform absolute paths, useful for
++     reproducibility.  It should be initialized to NULL (not yet set or
++     disabled) or to a `struct prefix_map` double pointer to enable it.  */
++  struct prefix_map **build_path_prefix_map;
++
+   /* EOF token, and a token forcing paste avoidance.  */
+   cpp_token avoid_paste;
+   cpp_token eof;
+diff --git a/libcpp/macro.c b/libcpp/macro.c
+index 54de3e3fc..6cdd1e5d3 100644
+--- a/libcpp/macro.c
++++ b/libcpp/macro.c
+@@ -28,6 +28,7 @@ along with this program; see the file COPYING3.  If not see
+ #include "system.h"
+ #include "cpplib.h"
+ #include "internal.h"
++#include "prefix-map.h"
+ 
+ typedef struct macro_arg macro_arg;
+ /* This structure represents the tokens of a macro argument.  These
+@@ -271,7 +272,17 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node)
+ 	unsigned int len;
+ 	const char *name;
+ 	uchar *buf;
++	struct prefix_map **map = pfile->build_path_prefix_map;
+ 	
++	/* Set a prefix-map for __FILE__ if BUILD_PATH_PREFIX_MAP is defined.  */
++	if (map == NULL && pfile->cb.get_build_path_prefix_map != NULL)
++	  {
++	    map = pfile->cb.get_build_path_prefix_map (pfile);
++	    if (map == NULL)
++	      abort ();
++	    pfile->build_path_prefix_map = map;
++	  }
++
+ 	if (node->value.builtin == BT_FILE)
+ 	  name = linemap_get_expansion_filename (pfile->line_table,
+ 						 pfile->line_table->highest_line);
+@@ -281,6 +292,11 @@ _cpp_builtin_macro_text (cpp_reader *pfile, cpp_hashnode *node)
+ 	    if (!name)
+ 	      abort ();
+ 	  }
++
++	/* Apply the prefix-map for deterministic path output.  */
++	if (map != NULL)
++	  name = prefix_map_remap_alloca (*map, name);
++
+ 	len = strlen (name);
+ 	buf = _cpp_unaligned_alloc (pfile, len * 2 + 3);
+ 	result = buf;
+diff --git a/libiberty/Makefile.in b/libiberty/Makefile.in
+index 5280bc158..bc098496a 100644
+--- a/libiberty/Makefile.in
++++ b/libiberty/Makefile.in
+@@ -143,6 +143,7 @@ CFILES = alloca.c argv.c asprintf.c atexit.c				\
+ 	 pex-common.c pex-djgpp.c pex-msdos.c pex-one.c			\
+ 	 pex-unix.c pex-win32.c						\
+          physmem.c putenv.c						\
++	prefix-map.c 							\
+ 	random.c regex.c rename.c rindex.c				\
+ 	safe-ctype.c setenv.c setproctitle.c sha1.c sigsetmask.c        \
+ 	 simple-object.c simple-object-coff.c simple-object-elf.c	\
+@@ -179,6 +180,7 @@ REQUIRED_OFILES =							\
+ 	./partition.$(objext) ./pexecute.$(objext) ./physmem.$(objext)	\
+ 	./pex-common.$(objext) ./pex-one.$(objext)			\
+ 	./@pexecute@.$(objext)						\
++	./prefix-map.$(objext)						\
+ 	./safe-ctype.$(objext)						\
+ 	./simple-object.$(objext) ./simple-object-coff.$(objext)	\
+ 	./simple-object-elf.$(objext) ./simple-object-mach-o.$(objext)	\
+@@ -887,7 +889,8 @@ $(CONFIGURED_OFILES): stamp-picdir
+ 	$(COMPILE.c) $(srcdir)/pex-one.c $(OUTPUT_OPTION)
+ 
+ ./pex-unix.$(objext): $(srcdir)/pex-unix.c config.h $(INCDIR)/ansidecl.h \
+-	$(INCDIR)/libiberty.h $(srcdir)/pex-common.h
++	$(INCDIR)/libiberty.h \
++	$(srcdir)/pex-common.h
+ 	if [ x"$(PICFLAG)" != x ]; then \
+ 	  $(COMPILE.c) $(PICFLAG) $(srcdir)/pex-unix.c -o pic/$@; \
+ 	else true; fi
+@@ -914,6 +917,15 @@ $(CONFIGURED_OFILES): stamp-picdir
+ 	else true; fi
+ 	$(COMPILE.c) $(srcdir)/physmem.c $(OUTPUT_OPTION)
+ 
++./prefix-map.$(objext): $(srcdir)/prefix-map.c config.h $(INCDIR)/prefix-map.h
++	if [ x"$(PICFLAG)" != x ]; then \
++	  $(COMPILE.c) $(PICFLAG) $(srcdir)/prefix-map.c -o pic/$@; \
++	else true; fi
++	if [ x"$(NOASANFLAG)" != x ]; then \
++	  $(COMPILE.c) $(PICFLAG) $(NOASANFLAG) $(srcdir)/prefix-map.c -o noasan/$@; \
++	else true; fi
++	$(COMPILE.c) $(srcdir)/prefix-map.c $(OUTPUT_OPTION)
++
+ ./putenv.$(objext): $(srcdir)/putenv.c config.h $(INCDIR)/ansidecl.h
+ 	if [ x"$(PICFLAG)" != x ]; then \
+ 	  $(COMPILE.c) $(PICFLAG) $(srcdir)/putenv.c -o pic/$@; \
+diff --git a/libiberty/prefix-map.c b/libiberty/prefix-map.c
+new file mode 100644
+index 000000000..ecb408856
+--- /dev/null
++++ b/libiberty/prefix-map.c
+@@ -0,0 +1,226 @@
++/* Definitions for manipulating filename prefixes.
++
++   Copyright (C) 2017 Free Software Foundation, Inc.
++
++   This program 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 2, or (at your option)
++   any later version.
++
++   This program 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 this program; if not, write to the Free Software Foundation,
++   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
++
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
++#ifdef HAVE_STRING_H
++#include <string.h>
++#endif
++
++#ifdef HAVE_STDLIB_H
++#include <stdlib.h>
++#endif
++
++#include "filenames.h"
++#include "libiberty.h"
++#include "prefix-map.h"
++
++
++/* Add a new mapping.
++
++   The input strings are duplicated and a new prefix_map struct is allocated.
++   Ownership of the duplicates, as well as the new prefix_map, is the same as
++   the ownership of the old struct.
++
++   Returns 0 on failure and 1 on success.  */
++int
++prefix_map_push (struct prefix_map **map_head,
++		 const char *new_prefix, const char *old_prefix)
++{
++  struct prefix_map *map = XNEW (struct prefix_map);
++  if (!map)
++    goto rewind_0;
++
++  map->old_prefix = xstrdup (old_prefix);
++  if (!map->old_prefix)
++    goto rewind_1;
++  map->old_len = strlen (old_prefix);
++
++  map->new_prefix = xstrdup (new_prefix);
++  if (!map->new_prefix)
++    goto rewind_2;
++  map->new_len = strlen (new_prefix);
++
++  map->next = *map_head;
++  *map_head = map;
++  return 1;
++
++rewind_2:
++  free ((void *) map->old_prefix);
++rewind_1:
++  free (map);
++rewind_0:
++  return 0;
++}
++
++/* Rewind a prefix map.
++
++   Everything up to the given OLD_HEAD is freed.  */
++void
++prefix_map_pop_until (struct prefix_map **map_head, struct prefix_map *old_head)
++{
++  struct prefix_map *map;
++  struct prefix_map *next;
++
++  for (map = *map_head; map != old_head; map = next)
++    {
++      free ((void *) map->old_prefix);
++      free ((void *) map->new_prefix);
++      next = map->next;
++      free (map);
++    }
++
++  *map_head = map;
++}
++
++
++/* Find a mapping suitable for the given OLD_NAME in the linked list MAP.\
++
++   If a mapping is found, writes a pointer to the non-matching suffix part of
++   OLD_NAME in SUFFIX, and its length in SUF_LEN.
++
++   Returns NULL if there was no suitable mapping.  */
++struct prefix_map *
++prefix_map_find (struct prefix_map *map, const char *old_name,
++		 const char **suffix, size_t *suf_len)
++{
++  size_t len;
++
++  for (; map; map = map->next)
++    {
++      len = map->old_len;
++      /* Ignore trailing path separators at the end of old_prefix */
++      while (len > 0 && IS_DIR_SEPARATOR (map->old_prefix[len-1])) len--;
++      /* Check if old_name matches old_prefix at a path component boundary */
++      if (! filename_ncmp (old_name, map->old_prefix, len)
++	  && (IS_DIR_SEPARATOR (old_name[len])
++	      || old_name[len] == '\0'))
++	{
++	  *suf_len = strlen (*suffix = old_name + len);
++	  break;
++	}
++    }
++
++  return map;
++}
++
++/* Prepend a prefix map before a given SUFFIX.
++
++   The remapped name is written to NEW_NAME and returned as a const pointer. No
++   allocations are performed; the caller must ensure it can hold at least
++   MAP->NEW_LEN + SUF_LEN + 1 characters.  */
++const char *
++prefix_map_prepend (struct prefix_map *map, char *new_name,
++		    const char *suffix, size_t suf_len)
++{
++  memcpy (new_name, map->new_prefix, map->new_len);
++  memcpy (new_name + map->new_len, suffix, suf_len + 1);
++  return new_name;
++}
++
++
++/* Parse a single part of a single prefix-map pair.
++
++   Returns 0 on failure and 1 on success.  */
++int
++prefix_map_parse_unquote (char *src)
++{
++  char *dest;
++  for (dest = src; 0 != (*dest = *src); ++dest, ++src)
++    switch (*src)
++      {
++      case ':':
++      case '=':
++	return 0; // should have been escaped
++      case '%':
++	switch (*(src + 1))
++	  {
++	  case '.':
++	    *dest = ':';
++	    goto unquoted;
++	  case '+':
++	    *dest = '=';
++	  unquoted:
++	  case '#':
++	    ++src;
++	    break;
++	  default:
++	    return 0; // invalid
++	  }
++      }
++  return 1;
++}
++
++/* Parse a single prefix-map.
++
++   Returns 0 on failure and 1 on success.  */
++int
++prefix_map_parse1 (struct prefix_map **map_head, char *arg)
++{
++  char *p;
++  p = strchr (arg, '=');
++  if (!p)
++    return 0;
++  *p = '\0';
++  if (!prefix_map_parse_unquote (arg))
++    return 0;
++  p++;
++  if (!prefix_map_parse_unquote (p))
++    return 0;
++
++  return prefix_map_push (map_head, arg, p);
++}
++
++/* Parse a prefix-map according to the BUILD_PATH_PREFIX_MAP standard.
++
++   The input string value is of the form
++
++     dst[0]=src[0]:dst[1]=src[1]...
++
++   Every dst[i] and src[i] has had "%", "=" and ":" characters replaced with
++   "%#", "%+", and "%." respectively; this function reverses this replacement.
++
++   Rightmost entries are stored at the head of the parsed structure.
++
++   Returns 0 on failure and 1 on success.  */
++int
++prefix_map_parse (struct prefix_map **map_head, const char *arg)
++{
++  struct prefix_map *old_head = *map_head;
++
++  size_t len = strlen (arg);
++  char *copy = (char *) alloca (len + 1);
++  memcpy (copy, arg, len + 1);
++
++  const char *sep = ":";
++  char *end, *tok = strtok_r (copy, sep, &end);
++  while (tok != NULL)
++    {
++      if (!prefix_map_parse1 (map_head, tok))
++	{
++	  prefix_map_pop_until (map_head, old_head);
++	  return 0;
++	}
++
++      tok = strtok_r (NULL, sep, &end);
++    }
++
++  return 1;
++}
+-- 
+Jan Nieuwenhuizen <janneke@gnu.org> | GNU LilyPond http://lilypond.org
+Freelance IT http://JoyofSource.com | Avatar® http://AvatarAcademy.com
+
diff --git a/gnu/packages/patches/gcc-4-cfns-fix-mismatch-in-gnu_inline-attributes.patch b/gnu/packages/patches/gcc-4-cfns-fix-mismatch-in-gnu_inline-attributes.patch
new file mode 100644
index 000000000..861cd4857
--- /dev/null
+++ b/gnu/packages/patches/gcc-4-cfns-fix-mismatch-in-gnu_inline-attributes.patch
@@ -0,0 +1,65 @@
+Taken from  https://gcc.gnu.org/cgi-bin/get-raw-msg?listname=gcc-patches&date=2016-01&msgid=1451802493-17406-1-git-send-email-vapier%40gentoo.org
+
+Since the 3.0.3 release of gperf (made in May 2007), the generated func
+has had the gnu_inline attribute applied to it.  The gcc source however
+has not been updated to include that which has lead to a mismatch.
+
+In practice, this hasn't been an issue for two reasons:
+(1) Before gcc-5, the default standard was (gnu) C89, and gcc does not
+warn or throw an error in this mode.
+(2) Starting with gcc-4.8, the compiler driver used to build gcc was
+changed to C++, and g++ does not warn or throw an error in this mode.
+
+This error does show up though when using gcc-5 to build gcc-4.7 or
+older as then the default is (gnu) C11 and the C compiler driver is
+used.  That failure looks like:
+In file included from .../gcc-4.7.4/gcc/cp/except.c:990:0:
+cfns.gperf: At top level:
+cfns.gperf:101:1: error: 'gnu_inline' attribute present on 'libc_name_p'
+cfns.gperf:26:14: error: but not here
+
+Whether the compiler should always emit this error regardless of the
+active standard or compiler driver is debatable (I think it should be
+consistent -- either always do it or never do it).
+
+2015-08-06  Mike Frysinger  <vapier@gentoo.org>
+
+	* cfns.gperf [__GNUC__, __GNUC_STDC_INLINE__]: Apply the
+	__gnu_inline__ attribute.
+	* cfns.h: Regenerated.
+---
+ gcc/cp/cfns.gperf | 3 +++
+ gcc/cp/cfns.h     | 3 +++
+ 2 files changed, 6 insertions(+)
+
+diff --git a/gcc/cp/cfns.gperf b/gcc/cp/cfns.gperf
+index 68acd3d..953262f 100644
+--- a/gcc/cp/cfns.gperf
++++ b/gcc/cp/cfns.gperf
+@@ -22,6 +22,9 @@ __inline
+ static unsigned int hash (const char *, unsigned int);
+ #ifdef __GNUC__
+ __inline
++#ifdef __GNUC_STDC_INLINE__
++__attribute__ ((__gnu_inline__))
++#endif
+ #endif
+ const char * libc_name_p (const char *, unsigned int);
+ %}
+diff --git a/gcc/cp/cfns.h b/gcc/cp/cfns.h
+index 1c6665d..6d00c0e 100644
+--- a/gcc/cp/cfns.h
++++ b/gcc/cp/cfns.h
+@@ -53,6 +53,9 @@ __inline
+ static unsigned int hash (const char *, unsigned int);
+ #ifdef __GNUC__
+ __inline
++#ifdef __GNUC_STDC_INLINE__
++__attribute__ ((__gnu_inline__))
++#endif
+ #endif
+ const char * libc_name_p (const char *, unsigned int);
+ /* maximum key range = 391, duplicates = 0 */
+-- 
+2.6.2
+
diff --git a/gnu/packages/patches/gcc-5-reproducibility-drop-profile.patch b/gnu/packages/patches/gcc-5-reproducibility-drop-profile.patch
new file mode 100644
index 000000000..a3974ad8d
--- /dev/null
+++ b/gnu/packages/patches/gcc-5-reproducibility-drop-profile.patch
@@ -0,0 +1,36 @@
+Courtesy "Bernhard M. Wiedemann" <bernhardout@lsmod.de>
+
+Removing -fprofile-generate, -fprofile-use makes gcc build bit-for-bit reproducible.
+
+diff -purN gcc-5.4.0.orig/Makefile.in gcc-5.4.0/Makefile.in
+--- gcc-5.4.0.orig/Makefile.in	1970-01-01 01:00:00.000000000 +0100
++++ gcc-5.4.0/Makefile.in	2017-11-03 15:34:56.415033525 +0100
+@@ -502,10 +502,10 @@ STAGE1_CONFIGURE_FLAGS = --disable-inter
+ 	  --disable-coverage --enable-languages="$(STAGE1_LANGUAGES)" \
+ 	  --disable-build-format-warnings
+ 
+-STAGEprofile_CFLAGS = $(STAGE2_CFLAGS) -fprofile-generate
++STAGEprofile_CFLAGS = $(STAGE2_CFLAGS)
+ STAGEprofile_TFLAGS = $(STAGE2_TFLAGS)
+ 
+-STAGEfeedback_CFLAGS = $(STAGE3_CFLAGS) -fprofile-use
++STAGEfeedback_CFLAGS = $(STAGE3_CFLAGS)
+ STAGEfeedback_TFLAGS = $(STAGE3_TFLAGS)
+ 
+ do-compare = @do_compare@
+diff -purN gcc-5.4.0.orig/Makefile.tpl gcc-5.4.0/Makefile.tpl
+--- gcc-5.4.0.orig/Makefile.tpl	1970-01-01 01:00:00.000000000 +0100
++++ gcc-5.4.0/Makefile.tpl	2017-11-03 15:34:27.146557384 +0100
+@@ -455,10 +455,10 @@ STAGE1_CONFIGURE_FLAGS = --disable-inter
+ 	  --disable-coverage --enable-languages="$(STAGE1_LANGUAGES)" \
+ 	  --disable-build-format-warnings
+ 
+-STAGEprofile_CFLAGS = $(STAGE2_CFLAGS) -fprofile-generate
++STAGEprofile_CFLAGS = $(STAGE2_CFLAGS)
+ STAGEprofile_TFLAGS = $(STAGE2_TFLAGS)
+ 
+-STAGEfeedback_CFLAGS = $(STAGE3_CFLAGS) -fprofile-use
++STAGEfeedback_CFLAGS = $(STAGE3_CFLAGS)
+ STAGEfeedback_TFLAGS = $(STAGE3_TFLAGS)
+ 
+ do-compare = @do_compare@
diff --git a/gnu/packages/patches/gcc-7-build-path-prefix-map.patch b/gnu/packages/patches/gcc-7-build-path-prefix-map.patch
new file mode 100644
index 000000000..098cbbd41
--- /dev/null
+++ b/gnu/packages/patches/gcc-7-build-path-prefix-map.patch
@@ -0,0 +1,934 @@
+This is the combined BUILD_PATH_PREFIX_MAP patch set.  Only using this here as
+a proof of concept to reach bit-by-bit reproducibility for diverse double
+compilation.  It will be reworked to meet the needs of GNU GCC upstream.
+
+Subject: [PATCH 1/3] Use BUILD_PATH_PREFIX_MAP envvar for debug-prefix-map
+
+Define the BUILD_PATH_PREFIX_MAP environment variable, and treat it as implicit
+-fdebug-prefix-map CLI options specified before any explicit such options.
+
+Much of the generic code for applying and parsing prefix-maps is implemented in
+libiberty instead of the dwarf2 parts of the code, in order to make subsequent
+patches unrelated to debuginfo easier.
+
+Acknowledgements
+----------------
+
+Daniel Kahn Gillmor who wrote the patch for r231835, which saved me a lot of
+time figuring out what to edit.
+
+HW42 for discussion on the details of the proposal, and for suggesting that we
+retain the ability to map the prefix to something other than ".".
+
+Other contributors to the BUILD_PATH_PREFIX_MAP specification, see
+https://reproducible-builds.org/specs/build-path-prefix-map/
+
+ChangeLogs
+----------
+
+include/ChangeLog:
+
+2017-03-27  Ximin Luo  <infinity0@pwned.gg>
+
+	* prefix-map.h: New file implementing the BUILD_PATH_PREFIX_MAP
+	specification; includes code from /gcc/final.c and code adapted from
+	examples attached to the specification.
+
+libiberty/ChangeLog:
+
+2017-03-27  Ximin Luo  <infinity0@pwned.gg>
+
+	* prefix-map.c: New file implementing the BUILD_PATH_PREFIX_MAP
+	specification; includes code from /gcc/final.c and code adapted from
+	examples attached to the specification.
+	* Makefile.in: Update for new files.
+
+gcc/ChangeLog:
+
+2017-03-27  Ximin Luo  <infinity0@pwned.gg>
+
+	* debug.h: Declare add_debug_prefix_map_from_envvar.
+	* final.c: Define add_debug_prefix_map_from_envvar, and refactor
+	prefix-map utilities to use equivalent code from libiberty instead.
+	* opts-global.c: (handle_common_deferred_options): Call
+	add_debug_prefix_map_from_envvar before processing options.
+
+gcc/testsuite/ChangeLog:
+
+2017-03-27  Ximin Luo  <infinity0@pwned.gg>
+
+	* gcc.dg/debug/dwarf2/build_path_prefix_map-1.c: New test.
+	* gcc.dg/debug/dwarf2/build_path_prefix_map-2.c: New test.
+
+Index: b/include/prefix-map.h
+===================================================================
+--- /dev/null
++++ b/include/prefix-map.h
+@@ -0,0 +1,108 @@
++/* Declarations for manipulating filename prefixes.
++
++   Copyright (C) 2017 Free Software Foundation, Inc.
++
++   This program 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 2, or (at your option)
++   any later version.
++
++   This program 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 this program; if not, write to the Free Software Foundation,
++   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
++
++#ifndef _PREFIX_MAP_H
++#define _PREFIX_MAP_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#ifdef HAVE_STDLIB_H
++#include <stdlib.h>
++#endif
++
++/* Linked-list of mappings from old prefixes to new prefixes.  */
++
++struct prefix_map
++{
++  const char *old_prefix;
++  const char *new_prefix;
++  size_t old_len;
++  size_t new_len;
++  struct prefix_map *next;
++};
++
++
++/* Find a mapping suitable for the given OLD_NAME in the linked list MAP.\
++
++   If a mapping is found, writes a pointer to the non-matching suffix part of
++   OLD_NAME in SUFFIX, and its length in SUF_LEN.
++
++   Returns NULL if there was no suitable mapping.  */
++struct prefix_map *
++prefix_map_find (struct prefix_map *map, const char *old_name,
++		 const char **suffix, size_t *suf_len);
++
++/* Prepend a prefix map before a given SUFFIX.
++
++   The remapped name is written to NEW_NAME and returned as a const pointer. No
++   allocations are performed; the caller must ensure it can hold at least
++   MAP->NEW_LEN + SUF_LEN + 1 characters.  */
++const char *
++prefix_map_prepend (struct prefix_map *map, char *new_name,
++		    const char *suffix, size_t suf_len);
++
++/* Remap a filename.
++
++   Returns OLD_NAME unchanged if there was no remapping, otherwise returns a
++   pointer to newly-allocated memory for the remapped filename.  The memory is
++   allocated by the given ALLOC function, which also determines who is
++   responsible for freeing it.  */
++#define prefix_map_remap_alloc_(map_head, old_name, alloc)		       \
++  __extension__								       \
++  ({									       \
++    const char *__suffix;						       \
++    size_t __suf_len;							       \
++    struct prefix_map *__map;						       \
++    (__map = prefix_map_find ((map_head), (old_name), &__suffix, &__suf_len))  \
++      ? prefix_map_prepend (__map,					       \
++			    (char *) alloc (__map->new_len + __suf_len + 1),   \
++			    __suffix, __suf_len)			       \
++      : (old_name);							       \
++  })
++
++/* Remap a filename.
++
++   Returns OLD_NAME unchanged if there was no remapping, otherwise returns a
++   stack-allocated pointer to the newly-remapped filename.  */
++#define prefix_map_remap_alloca(map_head, old_name) \
++  prefix_map_remap_alloc_ (map_head, old_name, alloca)
++
++
++/* Parse prefix-maps according to the BUILD_PATH_PREFIX_MAP standard.
++
++   The input string value is of the form
++
++     dst[0]=src[0]:dst[1]=src[1]...
++
++   Every dst[i] and src[i] has had "%", "=" and ":" characters replaced with
++   "%#", "%+", and "%." respectively; this function reverses this replacement.
++
++   Rightmost entries are stored at the head of the parsed structure.
++
++   Returns 0 on failure and 1 on success.  */
++int
++prefix_map_parse (struct prefix_map **map_head, const char *arg);
++
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* _PREFIX_MAP_H */
+Index: b/libiberty/Makefile.in
+===================================================================
+--- a/libiberty/Makefile.in
++++ b/libiberty/Makefile.in
+@@ -143,6 +143,7 @@ CFILES = alloca.c argv.c asprintf.c atex
+ 	 pex-common.c pex-djgpp.c pex-msdos.c pex-one.c			\
+ 	 pex-unix.c pex-win32.c						\
+          physmem.c putenv.c						\
++	prefix-map.c \
+ 	random.c regex.c rename.c rindex.c				\
+ 	rust-demangle.c							\
+ 	safe-ctype.c setenv.c setproctitle.c sha1.c sigsetmask.c        \
+@@ -182,6 +183,7 @@ REQUIRED_OFILES =							\
+ 	./partition.$(objext) ./pexecute.$(objext) ./physmem.$(objext)	\
+ 	./pex-common.$(objext) ./pex-one.$(objext)			\
+ 	./@pexecute@.$(objext) ./vprintf-support.$(objext)		\
++	./prefix-map.$(objext) \
+ 	./rust-demangle.$(objext)					\
+ 	./safe-ctype.$(objext)						\
+ 	./simple-object.$(objext) ./simple-object-coff.$(objext)	\
+@@ -757,7 +759,7 @@ $(CONFIGURED_OFILES): stamp-picdir stamp
+ 	$(COMPILE.c) $(srcdir)/fibheap.c $(OUTPUT_OPTION)
+ 
+ ./filename_cmp.$(objext): $(srcdir)/filename_cmp.c config.h $(INCDIR)/ansidecl.h \
+-	$(INCDIR)/filenames.h $(INCDIR)/hashtab.h \
++	$(INCDIR)/filenames.h $(INCDIR)/hashtab.h $(INCDIR)/libiberty.h \
+ 	$(INCDIR)/safe-ctype.h
+ 	if [ x"$(PICFLAG)" != x ]; then \
+ 	  $(COMPILE.c) $(PICFLAG) $(srcdir)/filename_cmp.c -o pic/$@; \
+@@ -1104,7 +1106,8 @@ $(CONFIGURED_OFILES): stamp-picdir stamp
+ 	$(COMPILE.c) $(srcdir)/pex-one.c $(OUTPUT_OPTION)
+ 
+ ./pex-unix.$(objext): $(srcdir)/pex-unix.c config.h $(INCDIR)/ansidecl.h \
+-	$(INCDIR)/libiberty.h $(srcdir)/pex-common.h
++	$(INCDIR)/environ.h $(INCDIR)/libiberty.h \
++	$(srcdir)/pex-common.h
+ 	if [ x"$(PICFLAG)" != x ]; then \
+ 	  $(COMPILE.c) $(PICFLAG) $(srcdir)/pex-unix.c -o pic/$@; \
+ 	else true; fi
+@@ -1143,6 +1146,15 @@ $(CONFIGURED_OFILES): stamp-picdir stamp
+ 	else true; fi
+ 	$(COMPILE.c) $(srcdir)/physmem.c $(OUTPUT_OPTION)
+ 
++./prefix-map.$(objext): $(srcdir)/prefix-map.c config.h $(INCDIR)/prefix-map.h
++	if [ x"$(PICFLAG)" != x ]; then \
++	  $(COMPILE.c) $(PICFLAG) $(srcdir)/prefix-map.c -o pic/$@; \
++	else true; fi
++	if [ x"$(NOASANFLAG)" != x ]; then \
++	  $(COMPILE.c) $(PICFLAG) $(NOASANFLAG) $(srcdir)/prefix-map.c -o noasan/$@; \
++	else true; fi
++	$(COMPILE.c) $(srcdir)/prefix-map.c $(OUTPUT_OPTION)
++
+ ./putenv.$(objext): $(srcdir)/putenv.c config.h $(INCDIR)/ansidecl.h
+ 	if [ x"$(PICFLAG)" != x ]; then \
+ 	  $(COMPILE.c) $(PICFLAG) $(srcdir)/putenv.c -o pic/$@; \
+@@ -1210,7 +1222,8 @@ $(CONFIGURED_OFILES): stamp-picdir stamp
+ 	else true; fi
+ 	$(COMPILE.c) $(srcdir)/safe-ctype.c $(OUTPUT_OPTION)
+ 
+-./setenv.$(objext): $(srcdir)/setenv.c config.h $(INCDIR)/ansidecl.h
++./setenv.$(objext): $(srcdir)/setenv.c config.h $(INCDIR)/ansidecl.h \
++	$(INCDIR)/environ.h
+ 	if [ x"$(PICFLAG)" != x ]; then \
+ 	  $(COMPILE.c) $(PICFLAG) $(srcdir)/setenv.c -o pic/$@; \
+ 	else true; fi
+@@ -1661,7 +1674,7 @@ $(CONFIGURED_OFILES): stamp-picdir stamp
+ 	$(COMPILE.c) $(srcdir)/xexit.c $(OUTPUT_OPTION)
+ 
+ ./xmalloc.$(objext): $(srcdir)/xmalloc.c config.h $(INCDIR)/ansidecl.h \
+-	$(INCDIR)/libiberty.h
++	$(INCDIR)/environ.h $(INCDIR)/libiberty.h
+ 	if [ x"$(PICFLAG)" != x ]; then \
+ 	  $(COMPILE.c) $(PICFLAG) $(srcdir)/xmalloc.c -o pic/$@; \
+ 	else true; fi
+@@ -1719,3 +1732,4 @@ $(CONFIGURED_OFILES): stamp-picdir stamp
+ 	  $(COMPILE.c) $(PICFLAG) $(NOASANFLAG) $(srcdir)/xvasprintf.c -o noasan/$@; \
+ 	else true; fi
+ 	$(COMPILE.c) $(srcdir)/xvasprintf.c $(OUTPUT_OPTION)
++
+Index: b/libiberty/prefix-map.c
+===================================================================
+--- /dev/null
++++ b/libiberty/prefix-map.c
+@@ -0,0 +1,215 @@
++/* Definitions for manipulating filename prefixes.
++
++   Copyright (C) 2017 Free Software Foundation, Inc.
++
++   This program 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 2, or (at your option)
++   any later version.
++
++   This program 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 this program; if not, write to the Free Software Foundation,
++   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
++
++#ifdef HAVE_CONFIG_H
++#include "config.h"
++#endif
++
++#ifdef HAVE_STRING_H
++#include <string.h>
++#endif
++
++#ifdef HAVE_STDLIB_H
++#include <stdlib.h>
++#endif
++
++#include "filenames.h"
++#include "libiberty.h"
++#include "prefix-map.h"
++
++
++/* Add a new mapping.
++
++   The input strings are duplicated and a new prefix_map struct is allocated.
++   Ownership of the duplicates, as well as the new prefix_map, is the same as
++   the ownership of the old struct.
++
++   Returns 0 on failure and 1 on success.  */
++int
++prefix_map_push (struct prefix_map **map_head,
++		 const char *new_prefix, const char *old_prefix)
++{
++  struct prefix_map *map = XNEW (struct prefix_map);
++  if (!map)
++    goto rewind_0;
++
++  map->old_prefix = xstrdup (old_prefix);
++  if (!map->old_prefix)
++    goto rewind_1;
++  map->old_len = strlen (old_prefix);
++
++  map->new_prefix = xstrdup (new_prefix);
++  if (!map->new_prefix)
++    goto rewind_2;
++  map->new_len = strlen (new_prefix);
++
++  map->next = *map_head;
++  *map_head = map;
++  return 1;
++
++rewind_2:
++  free ((void *) map->old_prefix);
++rewind_1:
++  free (map);
++rewind_0:
++  return 0;
++}
++
++/* Rewind a prefix map.
++
++   Everything up to the given OLD_HEAD is freed.  */
++void
++prefix_map_pop_until (struct prefix_map **map_head, struct prefix_map *old_head)
++{
++  struct prefix_map *map;
++  struct prefix_map *next;
++
++  for (map = *map_head; map != old_head; map = next)
++    {
++      free ((void *) map->old_prefix);
++      free ((void *) map->new_prefix);
++      next = map->next;
++      free (map);
++    }
++
++  *map_head = map;
++}
++
++
++/* Find a mapping suitable for the given OLD_NAME in the linked list MAP.\
++
++   If a mapping is found, writes a pointer to the non-matching suffix part of
++   OLD_NAME in SUFFIX, and its length in SUF_LEN.
++
++   Returns NULL if there was no suitable mapping.  */
++struct prefix_map *
++prefix_map_find (struct prefix_map *map, const char *old_name,
++		 const char **suffix, size_t *suf_len)
++{
++  for (; map; map = map->next)
++    if (filename_ncmp (old_name, map->old_prefix, map->old_len) == 0)
++      {
++	*suf_len = strlen (*suffix = old_name + map->old_len);
++	break;
++      }
++
++  return map;
++}
++
++/* Prepend a prefix map before a given SUFFIX.
++
++   The remapped name is written to NEW_NAME and returned as a const pointer. No
++   allocations are performed; the caller must ensure it can hold at least
++   MAP->NEW_LEN + SUF_LEN + 1 characters.  */
++const char *
++prefix_map_prepend (struct prefix_map *map, char *new_name,
++		    const char *suffix, size_t suf_len)
++{
++  memcpy (new_name, map->new_prefix, map->new_len);
++  memcpy (new_name + map->new_len, suffix, suf_len + 1);
++  return new_name;
++}
++
++
++/* Parse a single part of a single prefix-map pair.
++
++   Returns 0 on failure and 1 on success.  */
++int
++prefix_map_parse_unquote (char *src)
++{
++  for (char *dest = src; 0 != (*dest = *src); ++dest, ++src)
++    switch (*src)
++      {
++      case ':':
++      case '=':
++	return 0; // should have been escaped
++      case '%':
++	switch (*(src + 1))
++	  {
++	  case '.':
++	    *dest = ':';
++	    goto unquoted;
++	  case '+':
++	    *dest = '=';
++	  unquoted:
++	  case '#':
++	    ++src;
++	    break;
++	  default:
++	    return 0; // invalid
++	  }
++      }
++  return 1;
++}
++
++/* Parse a single prefix-map.
++
++   Returns 0 on failure and 1 on success.  */
++int
++prefix_map_parse1 (struct prefix_map **map_head, char *arg)
++{
++  char *p;
++  p = strchr (arg, '=');
++  if (!p)
++    return 0;
++  *p = '\0';
++  if (!prefix_map_parse_unquote (arg))
++    return 0;
++  p++;
++  if (!prefix_map_parse_unquote (p))
++    return 0;
++
++  return prefix_map_push (map_head, arg, p);
++}
++
++/* Parse a prefix-map according to the BUILD_PATH_PREFIX_MAP standard.
++
++   The input string value is of the form
++
++     dst[0]=src[0]:dst[1]=src[1]...
++
++   Every dst[i] and src[i] has had "%", "=" and ":" characters replaced with
++   "%#", "%+", and "%." respectively; this function reverses this replacement.
++
++   Rightmost entries are stored at the head of the parsed structure.
++
++   Returns 0 on failure and 1 on success.  */
++int
++prefix_map_parse (struct prefix_map **map_head, const char *arg)
++{
++  struct prefix_map *old_head = *map_head;
++
++  size_t len = strlen (arg);
++  char *copy = (char *) alloca (len + 1);
++  memcpy (copy, arg, len + 1);
++
++  const char *sep = ":";
++  char *end, *tok = strtok_r (copy, sep, &end);
++  while (tok != NULL)
++    {
++      if (!prefix_map_parse1 (map_head, tok))
++	{
++	  prefix_map_pop_until (map_head, old_head);
++	  return 0;
++	}
++
++      tok = strtok_r (NULL, sep, &end);
++    }
++
++  return 1;
++}
+Index: b/gcc/debug.h
+===================================================================
+--- a/gcc/debug.h
++++ b/gcc/debug.h
+@@ -236,6 +236,7 @@ extern void dwarf2out_switch_text_sectio
+ 
+ const char *remap_debug_filename (const char *);
+ void add_debug_prefix_map (const char *);
++void add_debug_prefix_map_from_envvar ();
+ 
+ /* For -fdump-go-spec.  */
+ 
+Index: b/gcc/final.c
+===================================================================
+--- a/gcc/final.c
++++ b/gcc/final.c
+@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3.
+ #define INCLUDE_ALGORITHM /* reverse */
+ #include "system.h"
+ #include "coretypes.h"
++#include "prefix-map.h"
+ #include "backend.h"
+ #include "target.h"
+ #include "rtl.h"
+@@ -1506,22 +1507,9 @@ asm_str_count (const char *templ)
+   return count;
+ }
+ \f
+-/* ??? This is probably the wrong place for these.  */
+-/* Structure recording the mapping from source file and directory
+-   names at compile time to those to be embedded in debug
+-   information.  */
+-struct debug_prefix_map
+-{
+-  const char *old_prefix;
+-  const char *new_prefix;
+-  size_t old_len;
+-  size_t new_len;
+-  struct debug_prefix_map *next;
+-};
+-
+-/* Linked list of such structures.  */
+-static debug_prefix_map *debug_prefix_maps;
+ 
++/* Linked list of `struct prefix_map'.  */
++static prefix_map *debug_prefix_maps = NULL;
+ 
+ /* Record a debug file prefix mapping.  ARG is the argument to
+    -fdebug-prefix-map and must be of the form OLD=NEW.  */
+@@ -1529,7 +1517,7 @@ static debug_prefix_map *debug_prefix_ma
+ void
+ add_debug_prefix_map (const char *arg)
+ {
+-  debug_prefix_map *map;
++  prefix_map *map;
+   const char *p;
+ 
+   p = strchr (arg, '=');
+@@ -1538,7 +1526,7 @@ add_debug_prefix_map (const char *arg)
+       error ("invalid argument %qs to -fdebug-prefix-map", arg);
+       return;
+     }
+-  map = XNEW (debug_prefix_map);
++  map = XNEW (prefix_map);
+   map->old_prefix = xstrndup (arg, p - arg);
+   map->old_len = p - arg;
+   p++;
+@@ -1548,28 +1536,32 @@ add_debug_prefix_map (const char *arg)
+   debug_prefix_maps = map;
+ }
+ 
++/* Add debug-prefix-maps from BUILD_PATH_PREFIX_MAP environment variable.  */
++
++void
++add_debug_prefix_map_from_envvar ()
++{
++  const char *arg = getenv ("BUILD_PATH_PREFIX_MAP");
++
++  if (!arg || prefix_map_parse (&debug_prefix_maps, arg))
++    return;
++
++  error ("environment variable BUILD_PATH_PREFIX_MAP is "
++	 "not well formed; see the GCC documentation for more details.");
++}
++
+ /* Perform user-specified mapping of debug filename prefixes.  Return
+    the new name corresponding to FILENAME.  */
+ 
+ const char *
+ remap_debug_filename (const char *filename)
+ {
+-  debug_prefix_map *map;
+-  char *s;
+-  const char *name;
+-  size_t name_len;
+-
+-  for (map = debug_prefix_maps; map; map = map->next)
+-    if (filename_ncmp (filename, map->old_prefix, map->old_len) == 0)
+-      break;
+-  if (!map)
++  const char *name = prefix_map_remap_alloca (debug_prefix_maps, filename);
++
++  if (name == filename)
+     return filename;
+-  name = filename + map->old_len;
+-  name_len = strlen (name) + 1;
+-  s = (char *) alloca (name_len + map->new_len);
+-  memcpy (s, map->new_prefix, map->new_len);
+-  memcpy (s + map->new_len, name, name_len);
+-  return ggc_strdup (s);
++
++  return ggc_strdup (name);
+ }
+ \f
+ /* Return true if DWARF2 debug info can be emitted for DECL.  */
+Index: b/gcc/opts-global.c
+===================================================================
+--- a/gcc/opts-global.c
++++ b/gcc/opts-global.c
+@@ -335,6 +335,8 @@ handle_common_deferred_options (void)
+   if (flag_opt_info)
+     opt_info_switch_p (NULL);
+ 
++  add_debug_prefix_map_from_envvar ();
++
+   FOR_EACH_VEC_ELT (v, i, opt)
+     {
+       switch (opt->opt_index)
+Index: b/gcc/testsuite/gcc.dg/debug/dwarf2/build_path_prefix_map-1.c
+===================================================================
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/debug/dwarf2/build_path_prefix_map-1.c
+@@ -0,0 +1,9 @@
++/* DW_AT_comp_dir should be relative if BUILD_PATH_PREFIX_MAP is a prefix of it.  */
++/* { dg-do compile } */
++/* { dg-options "-gdwarf -dA" } */
++/* { dg-set-compiler-env-var BUILD_PATH_PREFIX_MAP "DWARF2TEST=[file dirname [pwd]]" } */
++/* { dg-final { scan-assembler "DW_AT_comp_dir: \"DWARF2TEST/gcc" } } */
++
++void func (void)
++{
++}
+Index: b/gcc/testsuite/gcc.dg/debug/dwarf2/build_path_prefix_map-2.c
+===================================================================
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/debug/dwarf2/build_path_prefix_map-2.c
+@@ -0,0 +1,8 @@
++/* DW_AT_comp_dir should be absolute if BUILD_PATH_PREFIX_MAP is not set.  */
++/* { dg-do compile } */
++/* { dg-options "-gdwarf -dA" } */
++/* { dg-final { scan-assembler "DW_AT_comp_dir: \"/" } } */
++
++void func (void)
++{
++}
+Subject: [PATCH 2/3] Use BUILD_PATH_PREFIX_MAP envvar to transform __FILE__
+
+Use the BUILD_PATH_PREFIX_MAP environment variable when expanding the __FILE__
+macro, in the same way that debug-prefix-map works for debugging symbol paths.
+
+This patch follows similar lines to the earlier patch for SOURCE_DATE_EPOCH.
+Specifically, we read the environment variable not in libcpp but via a hook
+which has an implementation defined in gcc/c-family.  However, to achieve this
+is more complex than the earlier patch: we need to share the prefix_map data
+structure and associated functions between libcpp and c-family.  Therefore, we
+need to move these to libiberty.  (For comparison, the SOURCE_DATE_EPOCH patch
+did not need this because time_t et. al. are in the standard C library.)
+
+Acknowledgements
+----------------
+
+Dhole <dhole@openmailbox.org> who wrote the earlier patch for SOURCE_DATE_EPOCH
+which saved me a lot of time on figuring out what to edit.
+
+ChangeLogs
+----------
+
+gcc/c-family/ChangeLog:
+
+2017-07-21  Ximin Luo  <infinity0@pwned.gg>
+
+	* c-common.c (cb_get_build_path_prefix_map): Define new call target.
+	* c-common.h (cb_get_build_path_prefix_map): Declare call target.
+	* c-lex.c (init_c_lex): Set the get_build_path_prefix_map callback.
+
+libcpp/ChangeLog:
+
+2017-07-21  Ximin Luo  <infinity0@pwned.gg>
+
+	* include/cpplib.h (cpp_callbacks): Add get_build_path_prefix_map
+	callback.
+	* init.c (cpp_create_reader): Initialise build_path_prefix_map field.
+	* internal.h (cpp_reader): Add new field build_path_prefix_map.
+	* macro.c (_cpp_builtin_macro_text): Set the build_path_prefix_map
+	field if unset and apply it when expanding __FILE__ macros.
+
+gcc/testsuite/ChangeLog:
+
+2017-07-21  Ximin Luo  <infinity0@pwned.gg>
+
+	* gcc.dg/cpp/build_path_prefix_map-1.c: New test.
+	* gcc.dg/cpp/build_path_prefix_map-2.c: New test.
+
+Index: b/gcc/c-family/c-common.c
+===================================================================
+--- a/gcc/c-family/c-common.c
++++ b/gcc/c-family/c-common.c
+@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3.
+ 
+ #include "config.h"
+ #include "system.h"
++#include "prefix-map.h"
+ #include "coretypes.h"
+ #include "target.h"
+ #include "function.h"
+@@ -7905,6 +7906,25 @@ cb_get_source_date_epoch (cpp_reader *pf
+   return (time_t) epoch;
+ }
+ 
++/* Read BUILD_PATH_PREFIX_MAP from environment to have deterministic relative
++   paths to replace embedded absolute paths to get reproducible results.
++   Returns NULL if BUILD_PATH_PREFIX_MAP is badly formed.  */
++
++prefix_map **
++cb_get_build_path_prefix_map (cpp_reader *pfile ATTRIBUTE_UNUSED)
++{
++  prefix_map **map = XCNEW (prefix_map *);
++
++  const char *arg = getenv ("BUILD_PATH_PREFIX_MAP");
++  if (!arg || prefix_map_parse (map, arg))
++    return map;
++
++  free (map);
++  error_at (input_location, "environment variable BUILD_PATH_PREFIX_MAP is "
++	    "not well formed; see the GCC documentation for more details.");
++  return NULL;
++}
++
+ /* Callback for libcpp for offering spelling suggestions for misspelled
+    directives.  GOAL is an unrecognized string; CANDIDATES is a
+    NULL-terminated array of candidate strings.  Return the closest
+Index: b/gcc/c-family/c-common.h
+===================================================================
+--- a/gcc/c-family/c-common.h
++++ b/gcc/c-family/c-common.h
+@@ -1084,6 +1084,11 @@ extern time_t cb_get_source_date_epoch (
+    __TIME__ can store.  */
+ #define MAX_SOURCE_DATE_EPOCH HOST_WIDE_INT_C (253402300799)
+ 
++/* Read BUILD_PATH_PREFIX_MAP from environment to have deterministic relative
++   paths to replace embedded absolute paths to get reproducible results.
++   Returns NULL if BUILD_PATH_PREFIX_MAP is badly formed.  */
++extern prefix_map **cb_get_build_path_prefix_map (cpp_reader *pfile);
++
+ /* Callback for libcpp for offering spelling suggestions for misspelled
+    directives.  */
+ extern const char *cb_get_suggestion (cpp_reader *, const char *,
+Index: b/gcc/c-family/c-lex.c
+===================================================================
+--- a/gcc/c-family/c-lex.c
++++ b/gcc/c-family/c-lex.c
+@@ -81,6 +81,7 @@ init_c_lex (void)
+   cb->read_pch = c_common_read_pch;
+   cb->has_attribute = c_common_has_attribute;
+   cb->get_source_date_epoch = cb_get_source_date_epoch;
++  cb->get_build_path_prefix_map = cb_get_build_path_prefix_map;
+   cb->get_suggestion = cb_get_suggestion;
+ 
+   /* Set the debug callbacks if we can use them.  */
+Index: b/libcpp/include/cpplib.h
+===================================================================
+--- a/libcpp/include/cpplib.h
++++ b/libcpp/include/cpplib.h
+@@ -607,6 +607,9 @@ struct cpp_callbacks
+   /* Callback to parse SOURCE_DATE_EPOCH from environment.  */
+   time_t (*get_source_date_epoch) (cpp_reader *);
+ 
++  /* Callback to parse BUILD_PATH_PREFIX_MAP from environment.  */
++  struct prefix_map **(*get_build_path_prefix_map) (cpp_reader *);
++
+   /* Callback for providing suggestions for misspelled directives.  */
+   const char *(*get_suggestion) (cpp_reader *, const char *, const char *const *);
+ 
+Index: b/libcpp/init.c
+===================================================================
+--- a/libcpp/init.c
++++ b/libcpp/init.c
+@@ -261,6 +261,9 @@ cpp_create_reader (enum c_lang lang, cpp
+   /* Initialize source_date_epoch to -2 (not yet set).  */
+   pfile->source_date_epoch = (time_t) -2;
+ 
++  /* Initialize build_path_prefix_map to NULL (not yet set).  */
++  pfile->build_path_prefix_map = NULL;
++
+   /* The expression parser stack.  */
+   _cpp_expand_op_stack (pfile);
+ 
+Index: b/libcpp/internal.h
+===================================================================
+--- a/libcpp/internal.h
++++ b/libcpp/internal.h
+@@ -507,6 +507,11 @@ struct cpp_reader
+      set to -1 to disable it or to a non-negative value to enable it.  */
+   time_t source_date_epoch;
+ 
++  /* Externally set prefix-map to transform absolute paths, useful for
++     reproducibility.  It should be initialized to NULL (not yet set or
++     disabled) or to a `struct prefix_map` double pointer to enable it.  */
++  struct prefix_map **build_path_prefix_map;
++
+   /* EOF token, and a token forcing paste avoidance.  */
+   cpp_token avoid_paste;
+   cpp_token eof;
+Index: b/libcpp/macro.c
+===================================================================
+--- a/libcpp/macro.c
++++ b/libcpp/macro.c
+@@ -26,6 +26,7 @@ along with this program; see the file CO
+ #include "system.h"
+ #include "cpplib.h"
+ #include "internal.h"
++#include "prefix-map.h"
+ 
+ typedef struct macro_arg macro_arg;
+ /* This structure represents the tokens of a macro argument.  These
+@@ -291,7 +292,17 @@ _cpp_builtin_macro_text (cpp_reader *pfi
+ 	unsigned int len;
+ 	const char *name;
+ 	uchar *buf;
++	prefix_map **map = pfile->build_path_prefix_map;
+ 	
++	/* Set a prefix-map for __FILE__ if BUILD_PATH_PREFIX_MAP is defined.  */
++	if (map == NULL && pfile->cb.get_build_path_prefix_map != NULL)
++	  {
++	    map = pfile->cb.get_build_path_prefix_map (pfile);
++	    if (map == NULL)
++	      abort ();
++	    pfile->build_path_prefix_map = map;
++	  }
++
+ 	if (node->value.builtin == BT_FILE)
+ 	  name = linemap_get_expansion_filename (pfile->line_table,
+ 						 pfile->line_table->highest_line);
+@@ -301,6 +312,11 @@ _cpp_builtin_macro_text (cpp_reader *pfi
+ 	    if (!name)
+ 	      abort ();
+ 	  }
++
++	/* Apply the prefix-map for deterministic path output.  */
++	if (map != NULL)
++	  name = prefix_map_remap_alloca (*map, name);
++
+ 	len = strlen (name);
+ 	buf = _cpp_unaligned_alloc (pfile, len * 2 + 3);
+ 	result = buf;
+Index: b/gcc/testsuite/gcc.dg/cpp/build_path_prefix_map-1.c
+===================================================================
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/cpp/build_path_prefix_map-1.c
+@@ -0,0 +1,11 @@
++/* __FILE__ should strip BUILD_PATH_PREFIX_MAP if the latter is a prefix. */
++/* { dg-do run } */
++/* { dg-set-compiler-env-var BUILD_PATH_PREFIX_MAP "MACROTEST=$srcdir" } */
++
++int
++main ()
++{
++  if (__builtin_strcmp (__FILE__, "MACROTEST/gcc.dg/cpp/build_path_prefix_map-1.c") != 0)
++    __builtin_abort ();
++  return 0;
++}
+Index: b/gcc/testsuite/gcc.dg/cpp/build_path_prefix_map-2.c
+===================================================================
+--- /dev/null
++++ b/gcc/testsuite/gcc.dg/cpp/build_path_prefix_map-2.c
+@@ -0,0 +1,12 @@
++/* __FILE__ should not be relative if BUILD_PATH_PREFIX_MAP is not set, and gcc is
++   asked to compile an absolute filename as is the case with this test.  */
++/* { dg-do run } */
++/* { dg-set-compiler-env-var BUILD_PATH_PREFIX_MAP } */
++
++int
++main ()
++{
++  if (__builtin_strcmp (__FILE__, "./gcc.dg/cpp/build_path_prefix_map-2.c") == 0)
++    __builtin_abort ();
++  return 0;
++}
+Subject: [PATCH 3/3] When remapping paths, only match whole path components
+
+Change the remapping algorithm so that each old_prefix only matches paths that
+have old_prefix as a whole path component prefix.  (A whole path component is a
+part of a path that begins and ends at a directory separator or at either end
+of the path string.)
+
+This remapping algorithm is more predictable than the old algorithm, because
+there is no chance of mappings for one directory interfering with mappings for
+other directories.  It contains less corner cases and is therefore nicer for
+clients to use.  For these reasons, in our BUILD_PATH_PREFIX_MAP specification
+we recommend this algorithm, and it would be good for GCC to follow suit.
+
+This does technically break backwards compatibility but I don't think anyone
+would be reasonably depending on the corner cases of the previous algorithm,
+which are surprising and counterintuitive.
+
+Acknowledgements
+----------------
+
+Discussions with Michael Woerister and other members of the Rust compiler team
+on Github, and discussions with Daniel Shahaf on the rb-general@ mailing list
+on lists.reproducible-builds.org.
+
+ChangeLogs
+----------
+
+gcc/ChangeLog:
+
+2017-03-27  Ximin Luo  <infinity0@pwned.gg>
+
+	* doc/invoke.texi (Environment Variables): Document form and behaviour
+	of BUILD_PATH_PREFIX_MAP.
+
+libiberty/ChangeLog:
+
+2017-03-27  Ximin Luo  <infinity0@pwned.gg>
+
+	* prefix-map.c: When remapping paths, only match whole path components.
+
+Index: b/libiberty/prefix-map.c
+===================================================================
+--- a/libiberty/prefix-map.c
++++ b/libiberty/prefix-map.c
+@@ -101,12 +101,22 @@ struct prefix_map *
+ prefix_map_find (struct prefix_map *map, const char *old_name,
+ 		 const char **suffix, size_t *suf_len)
+ {
++  size_t len;
++
+   for (; map; map = map->next)
+-    if (filename_ncmp (old_name, map->old_prefix, map->old_len) == 0)
+-      {
+-	*suf_len = strlen (*suffix = old_name + map->old_len);
+-	break;
+-      }
++    {
++      len = map->old_len;
++      /* Ignore trailing path separators at the end of old_prefix */
++      while (len > 0 && IS_DIR_SEPARATOR (map->old_prefix[len-1])) len--;
++      /* Check if old_name matches old_prefix at a path component boundary */
++      if (! filename_ncmp (old_name, map->old_prefix, len)
++	  && (IS_DIR_SEPARATOR (old_name[len])
++	      || old_name[len] == '\0'))
++	{
++	  *suf_len = strlen (*suffix = old_name + len);
++	  break;
++	}
++    }
+ 
+   return map;
+ }
-- 
Jan Nieuwenhuizen <janneke@gnu.org> | GNU LilyPond http://lilypond.org
Freelance IT http://JoyofSource.com | Avatar® http://AvatarAcademy.com


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: gcc-ddc.diff --]
[-- Type: text/x-patch, Size: 8281 bytes --]

$ ./pre-inst-env guix build gcc-ddc@4.7.4
process 11900 acquired build slot '/var/guix/offload/192.168.32.121/0'
load on machine '192.168.32.121' is 0.0 (normalized: 0.0)
process 11900 acquired build slot '/var/guix/offload/192.168.32.122/0'
load on machine '192.168.32.122' is 0.07 (normalized: 0.023333333333333334)
@ build-started /gnu/store/sb9drfd3n8pqc1ch0yffqccpgchc3jll-gcc-ddc-4.7.4.drv - x86_64-linux /var/log/guix/drvs/sb//9drfd3n8pqc1ch0yffqccpgchc3jll-gcc-ddc-4.7.4.drv.bz2
sending 0 store items to '192.168.32.121'...
offloading '/gnu/store/sb9drfd3n8pqc1ch0yffqccpgchc3jll-gcc-ddc-4.7.4.drv' to '192.168.32.121'...
@ build-remote /gnu/store/sb9drfd3n8pqc1ch0yffqccpgchc3jll-gcc-ddc-4.7.4.drv 192.168.32.121
substitute: updating list of substitutes from 'http://guix2.oban.verum.com:8181'... 100.0%
substitute: updating list of substitutes from 'https://mirror.guixsd.org'... 100.0%
@ build-started /gnu/store/sb9drfd3n8pqc1ch0yffqccpgchc3jll-gcc-ddc-4.7.4.drv - x86_64-linux /var/log/guix/drvs/sb//9drfd3n8pqc1ch0yffqccpgchc3jll-gcc-ddc-4.7.4.drv.bz2
--- /gnu/store/zw672zcmykdwzm4x7l098hb94c34ak85-repro-gcc-4.7.4/bin/gcc
+++ /gnu/store/jhcf91y94nfnr5hmmxj7jn3whq1gm009-repr2-gcc-4.7.4/bin/gcc
??? objdump --line-numbers --disassemble --demangle --section=.text {}
? @@ -363,31 +363,31 @@
?    402da3:	0f 84 50 0e 00 00    	je     403bf9 <main+0x1429>
?    402da9:	4c 8b 25 a0 51 28 00 	mov    0x2851a0(%rip),%r12        
?    402db0:	4c 89 e7             	mov    %r12,%rdi
?    402db3:	e8 08 f5 ff ff       	callq  4022c0 <strlen@plt>
?    402db8:	48 83 c0 68          	add    $0x68,%rax
?    402dbc:	49 b8 2f 67 6e 75 2f 	movabs $0x6f74732f756e672f,%r8
?    402dc3:	73 74 6f 
? -  402dc6:	49 b9 72 65 2f 7a 77 	movabs $0x323736777a2f6572,%r9
? -  402dcd:	36 37 32 
? +  402dc6:	49 b9 72 65 2f 6a 68 	movabs $0x396663686a2f6572,%r9
? +  402dcd:	63 66 39 
?    402dd0:	48 83 e0 f0          	and    $0xfffffffffffffff0,%rax
? -  402dd4:	48 bf 6b 38 35 2d 72 	movabs $0x727065722d35386b,%rdi
? +  402dd4:	48 bf 30 30 39 2d 72 	movabs $0x727065722d393030,%rdi
?    402ddb:	65 70 72 
? -  402dde:	48 ba 6d 34 78 37 6c 	movabs $0x3839306c3778346d,%rdx
? -  402de5:	30 39 38 
? +  402dde:	48 ba 35 68 6d 6d 78 	movabs $0x6a376a786d6d6835,%rdx
? +  402de5:	6a 37 6a 
?    402de8:	48 29 c4             	sub    %rax,%rsp
? -  402deb:	48 be 68 62 39 34 63 	movabs $0x6134336334396268,%rsi
? -  402df2:	33 34 61 
? -  402df5:	48 b8 7a 63 6d 79 6b 	movabs $0x7a77646b796d637a,%rax
? -  402dfc:	64 77 7a 
? +  402deb:	48 be 6e 33 77 68 71 	movabs $0x6d6731716877336e,%rsi
? +  402df2:	31 67 6d 
? +  402df5:	48 b8 31 79 39 34 6e 	movabs $0x726e666e34397931,%rax
? +  402dfc:	66 6e 72 
?    402dff:	48 8d 5c 24 0f       	lea    0xf(%rsp),%rbx
?    402e04:	48 83 e3 f0          	and    $0xfffffffffffffff0,%rbx
?    402e08:	4c 89 03             	mov    %r8,(%rbx)
?    402e0b:	4c 89 4b 08          	mov    %r9,0x8(%rbx)
? -  402e0f:	49 b8 6f 2d 67 63 63 	movabs $0x2e342d6363672d6f,%r8
? +  402e0f:	49 b8 32 2d 67 63 63 	movabs $0x2e342d6363672d32,%r8
?    402e16:	2d 34 2e 
?    402e19:	49 b9 37 2e 34 2f 6c 	movabs $0x2f62696c2f342e37,%r9
?    402e20:	69 62 2f 
?    402e23:	48 89 7b 28          	mov    %rdi,0x28(%rbx)
?    402e27:	48 8d 7b 44          	lea    0x44(%rbx),%rdi
?    402e2b:	48 89 53 18          	mov    %rdx,0x18(%rbx)
?    402e2f:	48 89 73 20          	mov    %rsi,0x20(%rbx)
??? readelf --wide --decompress --hex-dump=.rodata {}
? @@ -48,27 +48,27 @@
?    0x0043e990 653d2a3a 253e6d74 756e653d 6e617469 e=*:%>mtune=nati
?    0x0043e9a0 76652025 3a6c6f63 616c5f63 70755f64 ve %:local_cpu_d
?    0x0043e9b0 65746563 74287475 6e65297d 7d20257b etect(tune)}} %{
?    0x0043e9c0 6d74756e 653d6e61 74697665 3a253e6d mtune=native:%>m
?    0x0043e9d0 74756e65 3d6e6174 69766520 253a6c6f tune=native %:lo
?    0x0043e9e0 63616c5f 6370755f 64657465 63742874 cal_cpu_detect(t
?    0x0043e9f0 756e6529 7d000000 2f676e75 2f73746f 
? -  0x0043ea00 72652f7a 77363732 7a636d79 6b64777a 
? -  0x0043ea10 6d347837 6c303938 68623934 63333461 
? -  0x0043ea20 6b38352d 72657072 6f2d6763 632d342e 
? +  0x0043ea00 72652f6a 68636639 31793934 6e666e72 re/jhcf91y94nfnr
? +  0x0043ea10 35686d6d 786a376a 6e337768 7131676d 5hmmxj7jn3whq1gm
? +  0x0043ea20 3030392d 72657072 322d6763 632d342e 009-repr2-gcc-4.
?    0x0043ea30 372e342f 6c69622f 6763632f 00000000 7.4/lib/gcc/....
? -  0x0043ea40 2f676e75 2f73746f 72652f7a 77363732 /gnu/store/zw672
? -  0x0043ea50 7a636d79 6b64777a 6d347837 6c303938 zcmykdwzm4x7l098
? -  0x0043ea60 68623934 63333461 6b38352d 72657072 hb94c34ak85-repr
? -  0x0043ea70 6f2d6763 632d342e 372e342f 6c696265 o-gcc-4.7.4/libe
? +  0x0043ea40 2f676e75 2f73746f 72652f6a 68636639 /gnu/store/jhcf9
? +  0x0043ea50 31793934 6e666e72 35686d6d 786a376a 1y94nfnr5hmmxj7j
? +  0x0043ea60 6e337768 7131676d 3030392d 72657072 n3whq1gm009-repr
? +  0x0043ea70 322d6763 632d342e 372e342f 6c696265 2-gcc-4.7.4/libe
?    0x0043ea80 7865632f 6763632f 00000000 00000000 xec/gcc/........
? -  0x0043ea90 2f676e75 2f73746f 72652f7a 77363732 
? -  0x0043eaa0 7a636d79 6b64777a 6d347837 6c303938 
? -  0x0043eab0 68623934 63333461 6b38352d 72657072 
? -  0x0043eac0 6f2d6763 632d342e 372e342f 62696e2f 
? +  0x0043ea90 2f676e75 2f73746f 72652f6a 68636639 /gnu/store/jhcf9
? +  0x0043eaa0 31793934 6e666e72 35686d6d 786a376a 1y94nfnr5hmmxj7j
? +  0x0043eab0 6e337768 7131676d 3030392d 72657072 n3whq1gm009-repr
? +  0x0043eac0 322d6763 632d342e 372e342f 62696e2f 2-gcc-4.7.4/bin/
?    0x0043ead0 00000000 00000000 2d706970 65206967 ........-pipe ig
?    0x0043eae0 6e6f7265 64206265 63617573 65202d73 nored because -s
?    0x0043eaf0 6176652d 74656d70 73207370 65636966 ave-temps specif
?    0x0043eb00 69656400 00000000 253c2d78 20257325 ied.....%<-x %s%
?    0x0043eb10 3e206166 74657220 6c617374 20696e70 > after last inp
?    0x0043eb20 75742066 696c6520 68617320 6e6f2065 ut file has no e
?    0x0043eb30 66666563 74000000 25717320 69732061 ffect...%qs is a
? @@ -1553,18 +1553,18 @@
?    0x004447a0 bffc4000 00000000 f6fd4000 00000000 ..@.......@.....
?    0x004447b0 bffc4000 00000000 bffc4000 00000000 ..@.......@.....
?    0x004447c0 bffc4000 00000000 f6fd4000 00000000 ..@.......@.....
?    0x004447d0 00000000 00000000 00000000 00000000 ................
?    0x004447e0 01000000 02000000 03000000 0e000000 ................
?    0x004447f0 0e000000 0e000000 0e000000 0e000000 ................
?    0x00444800 0e000000 0e000000 0e000000 07000000 ................
? -  0x00444810 2f676e75 2f73746f 72652f7a 77363732 /gnu/store/zw672
? -  0x00444820 7a636d79 6b64777a 6d347837 6c303938 zcmykdwzm4x7l098
? -  0x00444830 68623934 63333461 6b38352d 72657072 hb94c34ak85-repr
? -  0x00444840 6f2d6763 632d342e 372e3400 5f524f4f o-gcc-4.7.4._ROO
? +  0x00444810 2f676e75 2f73746f 72652f6a 68636639 /gnu/store/jhcf9
? +  0x00444820 31793934 6e666e72 35686d6d 786a376a 1y94nfnr5hmmxj7j
? +  0x00444830 6e337768 7131676d 3030392d 72657072 n3whq1gm009-repr
? +  0x00444840 322d6763 632d342e 372e3400 5f524f4f 2-gcc-4.7.4._ROO
?    0x00444850 54002e2e 2f2e2e2f 6763632d 342e372e T.../../gcc-4.7.
?    0x00444860 342f6763 632f7061 72616d73 2e630069 4/gcc/params.c.i
?    0x00444870 6e76616c 69642070 6172616d 65746572 nvalid parameter
?    0x00444880 20257173 00707265 64696374 61626c65  %qs.predictable
?    0x00444890 2d627261 6e63682d 6f757463 6f6d6500 -branch-outcome.
?    0x004448a0 6d61782d 696e6c69 6e652d69 6e736e73 max-inline-insns
?    0x004448b0 2d73696e 676c6500 6d61782d 696e6c69 -single.max-inli
builder for `/gnu/store/sb9drfd3n8pqc1ch0yffqccpgchc3jll-gcc-ddc-4.7.4.drv' failed with exit code 1
@ build-failed /gnu/store/sb9drfd3n8pqc1ch0yffqccpgchc3jll-gcc-ddc-4.7.4.drv - 1 builder for `/gnu/store/sb9drfd3n8pqc1ch0yffqccpgchc3jll-gcc-ddc-4.7.4.drv' failed with exit code 1
derivation '/gnu/store/sb9drfd3n8pqc1ch0yffqccpgchc3jll-gcc-ddc-4.7.4.drv' offloaded to '192.168.32.121' failed: build of `/gnu/store/sb9drfd3n8pqc1ch0yffqccpgchc3jll-gcc-ddc-4.7.4.drv' failed
@ build-failed /gnu/store/sb9drfd3n8pqc1ch0yffqccpgchc3jll-gcc-ddc-4.7.4.drv - 1 builder for `/gnu/store/sb9drfd3n8pqc1ch0yffqccpgchc3jll-gcc-ddc-4.7.4.drv' failed with exit code 100
guix build: error: build failed: build of `/gnu/store/sb9drfd3n8pqc1ch0yffqccpgchc3jll-gcc-ddc-4.7.4.drv' failed

[-- Attachment #4: Type: text/plain, Size: 152 bytes --]


-- 
Jan Nieuwenhuizen <janneke@gnu.org> | GNU LilyPond http://lilypond.org
Freelance IT http://JoyofSource.com | Avatar® http://AvatarAcademy.com

  reply	other threads:[~2017-11-10 19:20 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-11-01 16:46 diverse double compilation: using $ORIGIN? Ricardo Wurmus
2017-11-02  8:41 ` Fwd: " Ricardo Wurmus
2017-11-02  8:46 ` [bootstrappable] " Jan Nieuwenhuizen
2017-11-05 16:09   ` Ludovic Courtès
2017-11-05 16:27     ` Jan Nieuwenhuizen
2017-11-10 19:19       ` Jan Nieuwenhuizen [this message]
2017-11-05 16:11 ` Ludovic Courtès
2017-11-10  4:53 ` Chris Marusich
2017-11-11 21:56   ` Ludovic Courtès

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://guix.gnu.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87efp6x7pm.fsf@gnu.org \
    --to=janneke@gnu.org \
    --cc=bootstrappable@freelists.org \
    --cc=guix-devel@gnu.org \
    --cc=ludo@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).