unofficial mirror of guix-devel@gnu.org 
 help / color / mirror / code / Atom feed
* diverse double compilation: using $ORIGIN?
@ 2017-11-01 16:46 Ricardo Wurmus
  2017-11-02  8:41 ` Fwd: " Ricardo Wurmus
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Ricardo Wurmus @ 2017-11-01 16:46 UTC (permalink / raw)
  To: guix-devel; +Cc: bootstrappable

Hi Guix,
hi bootstrappers!

When building packages, Guix embeds the absolute file name of the output
directory in the resulting binary.  That’s usually fine and what we
want.

Now let’s assume that we’d like to build the GCC sources with diverse
double compilation: we’d have a “gcc” package that’s built with
“gcc-core”; we’d also have a “gcc-from-clang” package that uses Clang as
its input.  Since the GCC build procedure is performed at least two
times (once with the bootstrap compiler, and then again with the GCC
variant this produces), the resulting GCC binaries should be identical.

Except that they are not.  One of the reasons is that the binaries that
Guix produces embed the target output directories.  This means that the
two compiler binaries that result from diverse double compilation will
*always* differ in at least the embedded paths, such as paths to itself
(e.g. to binaries in the libexec directory) and paths to.

I wonder if we can use $ORIGIN in the compiler binaries, so that we can
avoid (most) references to the output directories, thereby making the
equality check between the diversely built compiler binaries simpler.

Is this at all possible?  Or do we need to accept that the equality
check for diverse double compilation for binaries built with Guix must
be aware of /gnu/store references and ignore those?

Alternatively, could we move all of these store references into a
wrapper script that would tell the binary about them via environment
variables?  The equality check would only need to exclude the wrapper
script then and compare the two sets of compiler binaries naively.

Does this make any sense?

--
Ricardo

GPG: BCA6 89B6 3655 3801 C3C6  2150 197A 5888 235F ACAC
https://elephly.net

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Fwd: diverse double compilation: using $ORIGIN?
  2017-11-01 16:46 diverse double compilation: using $ORIGIN? Ricardo Wurmus
@ 2017-11-02  8:41 ` Ricardo Wurmus
  2017-11-02  8:46 ` [bootstrappable] " Jan Nieuwenhuizen
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 9+ messages in thread
From: Ricardo Wurmus @ 2017-11-02  8:41 UTC (permalink / raw)
  To: guix-devel

[resending to guix-devel@gnu.org because of mail problems / delays]

Hi Guix,
hi bootstrappers!

When building packages, Guix embeds the absolute file name of the output
directory in the resulting binary.  That’s usually fine and what we
want.

Now let’s assume that we’d like to build the GCC sources with diverse
double compilation: we’d have a “gcc” package that’s built with
“gcc-core”; we’d also have a “gcc-from-clang” package that uses Clang as
its input.  Since the GCC build procedure is performed at least two
times (once with the bootstrap compiler, and then again with the GCC
variant this produces), the resulting GCC binaries should be identical.

Except that they are not.  One of the reasons is that the binaries that
Guix produces embed the target output directories.  This means that the
two compiler binaries that result from diverse double compilation will
*always* differ in at least the embedded paths, such as paths to itself
(e.g. to binaries in the libexec directory) and paths to.

I wonder if we can use $ORIGIN in the compiler binaries, so that we can
avoid (most) references to the output directories, thereby making the
equality check between the diversely built compiler binaries simpler.

Is this at all possible?  Or do we need to accept that the equality
check for diverse double compilation for binaries built with Guix must
be aware of /gnu/store references and ignore those?

Alternatively, could we move all of these store references into a
wrapper script that would tell the binary about them via environment
variables?  The equality check would only need to exclude the wrapper
script then and compare the two sets of compiler binaries naively.

Does this make any sense?

-- 
Ricardo

GPG: BCA6 89B6 3655 3801 C3C6  2150 197A 5888 235F ACAC
https://elephly.net

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [bootstrappable] diverse double compilation: using $ORIGIN?
  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 ` Jan Nieuwenhuizen
  2017-11-05 16:09   ` Ludovic Courtès
  2017-11-05 16:11 ` Ludovic Courtès
  2017-11-10  4:53 ` Chris Marusich
  3 siblings, 1 reply; 9+ messages in thread
From: Jan Nieuwenhuizen @ 2017-11-02  8:46 UTC (permalink / raw)
  To: Ricardo Wurmus; +Cc: guix-devel, bootstrappable

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

Ricardo Wurmus writes:

> When building packages, Guix embeds the absolute file name of the output
> directory in the resulting binary.  That’s usually fine and what we
> want.
>
> Now let’s assume that we’d like to build the GCC sources with diverse
> double compilation: we’d have a “gcc” package that’s built with
> “gcc-core”; we’d also have a “gcc-from-clang” package that uses Clang as
> its input.  Since the GCC build procedure is performed at least two
> times (once with the bootstrap compiler, and then again with the GCC
> variant this produces), the resulting GCC binaries should be identical.
>
> Except that they are not.  One of the reasons is that the binaries that
> Guix produces embed the target output directories.  This means that the
> two compiler binaries that result from diverse double compilation will
> *always* differ in at least the embedded paths, such as paths to itself
> (e.g. to binaries in the libexec directory) and paths to.
>
> I wonder if we can use $ORIGIN in the compiler binaries, so that we can
> avoid (most) references to the output directories, thereby making the
> equality check between the diversely built compiler binaries simpler.
>
> Is this at all possible?  Or do we need to accept that the equality
> check for diverse double compilation for binaries built with Guix must
> be aware of /gnu/store references and ignore those?
>
> Alternatively, could we move all of these store references into a
> wrapper script that would tell the binary about them via environment
> variables?  The equality check would only need to exclude the wrapper
> script then and compare the two sets of compiler binaries naively.
>
> Does this make any sense?

Attached is a patch prototyping this diverse double compilation test.

janneke


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

From c91609e847066c384826d726033146e08d8185ed 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 gcc-5.4.0 and on
clang-gcc-5.4.0 (the same GCC built with clang).  The builder
checks if both gcc's are bit-for-bit identical and fails if
they differ.

* gnu/packages/bootstrappable.scm: New file.
* gnu/local.mk (GNU_SYSTEM_MODULES): Add it.
---
 gnu/local.mk                    |  1 +
 gnu/packages/bootstrappable.scm | 98 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 99 insertions(+)
 create mode 100644 gnu/packages/bootstrappable.scm

diff --git a/gnu/local.mk b/gnu/local.mk
index 90dc7aec1..379b2c7b9 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -78,6 +78,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				\
diff --git a/gnu/packages/bootstrappable.scm b/gnu/packages/bootstrappable.scm
new file mode 100644
index 000000000..4ccde7a6d
--- /dev/null
+++ b/gnu/packages/bootstrappable.scm
@@ -0,0 +1,98 @@
+;;; 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 base) ; diffutils
+  #:use-module (gnu packages gcc)
+  #:use-module (gnu packages llvm)
+  #:use-module (gnu packages package-management) ; diffosscope
+  #:use-module (guix packages)
+
+  #:use-module (guix build-system trivial)
+
+  ;; for clang-gcc
+  #:use-module (guix build-system gnu)
+  #:use-module (guix utils)
+  #:use-module (gnu packages bootstrap)
+  #:use-module (gnu packages compression)
+  #:use-module (gnu packages elf)
+  #:use-module (gnu packages multiprecision)
+  #:use-module (gnu packages texinfo)
+
+  #:use-module (srfi srfi-1))
+
+(define gcc-configure-flags-for-triplet (@@ (gnu packages gcc) gcc-configure-flags-for-triplet))
+
+(define-public clang-gcc
+  (package
+    (inherit gcc-5)
+    ;;(name "clang-gcc")
+    (name "cgc")                        ; let's see if length matters here
+    (version "5.4.0")
+    (native-inputs `(("clang" ,clang)
+                     ,@(alist-delete "gcc" (package-native-inputs gcc-5)))) ; FIXME: %final-inputs?
+    (arguments
+     (substitute-keyword-arguments (package-arguments gcc-5)
+       ((#: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 "5.4.0")
+    (source #f)
+    (native-inputs `(("diffoscope" ,diffoscope)
+                     ("diffutils" ,diffutils)
+                     ("gcc" ,gcc-5)
+                     ("clang-gcc" ,clang-gcc)))
+    (build-system trivial-build-system)
+    (arguments
+     `(#:modules ((guix build utils))
+       #:builder
+       (begin
+         (use-modules (guix build utils))
+         (let* ((diffoscope (assoc-ref %build-inputs "diffoscope"))
+                (diffutils (assoc-ref %build-inputs "diffutils"))
+                (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")))
+           ;; FIXME: diffoscope.exc.RequiredToolNotFound: cmp
+           (setenv "PATH" (string-append diffoscope "/bin:"
+                                         diffutils "/bin:"))
+           ;; diffoscope.presenters.formats: Console is unable to print Unicode characters. Set e.g. PYTHONIOENCODING=utf-8
+           (setenv "PYTHONIOENCODING" "utf-8")
+           ;; cmp should suffice but gives little insight if it fails
+           ;; (zero? (system* "cmp" gcc/bin/gcc clang-gcc/bin/gcc))
+           ;; for starters, only check the gcc binary
+           (zero? (system* "diffoscope" gcc/bin/gcc clang-gcc/bin/gcc))
+           ))))
+    (synopsis "test gcc+clang DDC property for gcc-5.4.0")
+    (description "gcc-dcc is a meta-package that depends on gcc-5.4.0 and on
+clang-gcc-5.4.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+)))
-- 
Jan Nieuwenhuizen <janneke@gnu.org> | GNU LilyPond http://lilypond.org
Freelance IT http://JoyofSource.com | Avatar® http://AvatarAcademy.com


[-- Attachment #3: 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

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [bootstrappable] diverse double compilation: using $ORIGIN?
  2017-11-02  8:46 ` [bootstrappable] " Jan Nieuwenhuizen
@ 2017-11-05 16:09   ` Ludovic Courtès
  2017-11-05 16:27     ` Jan Nieuwenhuizen
  0 siblings, 1 reply; 9+ messages in thread
From: Ludovic Courtès @ 2017-11-05 16:09 UTC (permalink / raw)
  To: Jan Nieuwenhuizen; +Cc: guix-devel, bootstrappable

Jan Nieuwenhuizen <janneke@gnu.org> skribis:

> From c91609e847066c384826d726033146e08d8185ed 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 gcc-5.4.0 and on
> clang-gcc-5.4.0 (the same GCC built with clang).  The builder
> checks if both gcc's are bit-for-bit identical and fails if
> they differ.
>
> * 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.”  :-)

Ludo’.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [bootstrappable] diverse double compilation: using $ORIGIN?
  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:11 ` Ludovic Courtès
  2017-11-10  4:53 ` Chris Marusich
  3 siblings, 0 replies; 9+ messages in thread
From: Ludovic Courtès @ 2017-11-05 16:11 UTC (permalink / raw)
  To: Ricardo Wurmus; +Cc: guix-devel, bootstrappable

Hello!

Ricardo Wurmus <rekado@elephly.net> skribis:

> When building packages, Guix embeds the absolute file name of the output
> directory in the resulting binary.  That’s usually fine and what we
> want.
>
> Now let’s assume that we’d like to build the GCC sources with diverse
> double compilation: we’d have a “gcc” package that’s built with
> “gcc-core”; we’d also have a “gcc-from-clang” package that uses Clang as
> its input.  Since the GCC build procedure is performed at least two
> times (once with the bootstrap compiler, and then again with the GCC
> variant this produces), the resulting GCC binaries should be identical.
>
> Except that they are not.  One of the reasons is that the binaries that
> Guix produces embed the target output directories.  This means that the
> two compiler binaries that result from diverse double compilation will
> *always* differ in at least the embedded paths, such as paths to itself
> (e.g. to binaries in the libexec directory) and paths to.
>
> I wonder if we can use $ORIGIN in the compiler binaries, so that we can
> avoid (most) references to the output directories, thereby making the
> equality check between the diversely built compiler binaries simpler.

Assuming we can add a phase to replace absolute file names in RUNPATH &
co. with $ORIGIN references where applicable (should be doable), we
still have a problem with multiple-output derivations: we’d still have
the hash of the other outputs.

I’m not sure how to avoid that.

When the goal is just to compare things, we could build static
binaries.  Or we could have a comparison tool that compares modulo file
names or something…

Thoughts?

Ludo’.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [bootstrappable] diverse double compilation: using $ORIGIN?
  2017-11-05 16:09   ` Ludovic Courtès
@ 2017-11-05 16:27     ` Jan Nieuwenhuizen
  2017-11-10 19:19       ` Jan Nieuwenhuizen
  0 siblings, 1 reply; 9+ messages in thread
From: Jan Nieuwenhuizen @ 2017-11-05 16:27 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guix-devel, bootstrappable

Ludovic Courtès 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.

Of course, Guix has the additional problem of the install-prefix that
debian and others do not have.

I'll be sending updated patches soon.

janneke.

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

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: diverse double compilation: using $ORIGIN?
  2017-11-01 16:46 diverse double compilation: using $ORIGIN? Ricardo Wurmus
                   ` (2 preceding siblings ...)
  2017-11-05 16:11 ` Ludovic Courtès
@ 2017-11-10  4:53 ` Chris Marusich
  2017-11-11 21:56   ` Ludovic Courtès
  3 siblings, 1 reply; 9+ messages in thread
From: Chris Marusich @ 2017-11-10  4:53 UTC (permalink / raw)
  To: Ricardo Wurmus; +Cc: guix-devel, bootstrappable

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

Ricardo Wurmus <rekado@elephly.net> writes:

> Since the GCC build procedure is performed at least two
> times (once with the bootstrap compiler, and then again with the GCC
> variant this produces), the resulting GCC binaries should be identical.
>
> Except that they are not.  One of the reasons is that the binaries
> that Guix produces embed the target output directories.  This means
> that the two compiler binaries that result from diverse double
> compilation will *always* differ in at least the embedded paths, such
> as paths to itself (e.g. to binaries in the libexec directory) and
> paths to.

What ever happened to the intensional model (i.e., a content-addressed
store)?  If derivation outputs were content-addressed, this would not be
a problem, right?

Dolstra's thesis presented some ideas for how to rewrite self-references
in derivation outputs under the intensional model.  I've casually looked
into what happened with the intensional model since his thesis was
written, but I don't really know why it hasn't been implemented.  All I
know is that Dolstra and the Nix devs seem to have moved away from that
idea; I never really learned the reason(s) why.

-- 
Chris

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [bootstrappable] diverse double compilation: using $ORIGIN?
  2017-11-05 16:27     ` Jan Nieuwenhuizen
@ 2017-11-10 19:19       ` Jan Nieuwenhuizen
  0 siblings, 0 replies; 9+ messages in thread
From: Jan Nieuwenhuizen @ 2017-11-10 19:19 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guix-devel, bootstrappable

[-- 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

^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: diverse double compilation: using $ORIGIN?
  2017-11-10  4:53 ` Chris Marusich
@ 2017-11-11 21:56   ` Ludovic Courtès
  0 siblings, 0 replies; 9+ messages in thread
From: Ludovic Courtès @ 2017-11-11 21:56 UTC (permalink / raw)
  To: Chris Marusich; +Cc: guix-devel, bootstrappable

Chris Marusich <cmmarusich@gmail.com> skribis:

> Ricardo Wurmus <rekado@elephly.net> writes:
>
>> Since the GCC build procedure is performed at least two
>> times (once with the bootstrap compiler, and then again with the GCC
>> variant this produces), the resulting GCC binaries should be identical.
>>
>> Except that they are not.  One of the reasons is that the binaries
>> that Guix produces embed the target output directories.  This means
>> that the two compiler binaries that result from diverse double
>> compilation will *always* differ in at least the embedded paths, such
>> as paths to itself (e.g. to binaries in the libexec directory) and
>> paths to.
>
> What ever happened to the intensional model (i.e., a content-addressed
> store)?  If derivation outputs were content-addressed, this would not be
> a problem, right?

Indeed.

> Dolstra's thesis presented some ideas for how to rewrite self-references
> in derivation outputs under the intensional model.  I've casually looked
> into what happened with the intensional model since his thesis was
> written, but I don't really know why it hasn't been implemented.  All I
> know is that Dolstra and the Nix devs seem to have moved away from that
> idea; I never really learned the reason(s) why.

One problem is that it requires 100% reproducible builds; if something
doesn’t build reproducibly, you cannot get substitutes.

Another problem is… migration.  :-)

Now, fixed-output derivations are one way to retrofit bits of the
intensional model in the extensional model.  Perhaps we could do more in
that direction?

Ludo’.

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2017-11-11 21:56 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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
2017-11-05 16:11 ` Ludovic Courtès
2017-11-10  4:53 ` Chris Marusich
2017-11-11 21:56   ` Ludovic Courtès

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).