summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/contributing.texi26
-rw-r--r--doc/guix.texi14
-rw-r--r--guix/scripts/build.scm9
3 files changed, 44 insertions, 5 deletions
diff --git a/doc/contributing.texi b/doc/contributing.texi
index a66f5374b9..b61f6a534c 100644
--- a/doc/contributing.texi
+++ b/doc/contributing.texi
@@ -279,15 +279,31 @@ not affected by the change; @code{guix refresh --list-dependent
 @var{package}} will help you do that (@pxref{Invoking guix refresh}).
 
 @item
+@cindex determinism, of build processes
+@cindex reproducible builds, checking
 Check whether the package's build process is deterministic.  This
 typically means checking whether an independent build of the package
 yields the exact same result that you obtained, bit for bit.
 
-A simple way to do that is with @command{guix challenge}
-(@pxref{Invoking guix challenge}).  You may run it once the package has
-been committed and built by @code{hydra.gnu.org} to check whether it
-obtains the same result as you did.  Better yet: Find another machine
-that can build it and run @command{guix publish}.
+A simple way to do that is by building the same package several times in
+a row on your machine (@pxref{Invoking guix build}):
+
+@example
+guix build --rounds=2 my-package
+@end example
+
+This is enough to catch a class of common non-determinism issues, such
+as timestamps or randomly-generated output in the build result.
+
+Another option is to use @command{guix challenge} (@pxref{Invoking guix
+challenge}).  You may run it once the package has been committed and
+built by @code{hydra.gnu.org} to check whether it obtains the same
+result as you did.  Better yet: Find another machine that can build it
+and run @command{guix publish}.  Since the remote build machine is
+likely different from yours, this can catch non-determinism issues
+related to the hardware---e.g., use of different instruction set
+extensions---or to the operating system kernel---e.g., reliance on
+@code{uname} or @file{/proc} files.
 
 @end enumerate
 
diff --git a/doc/guix.texi b/doc/guix.texi
index 309548be88..390e7949c0 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -3876,6 +3876,20 @@ Do not use substitutes for build products.  That is, always build things
 locally instead of allowing downloads of pre-built binaries
 (@pxref{Substitutes}).
 
+@item --rounds=@var{n}
+Build each derivation @var{n} times in a row, and raise an error if
+consecutive build results are not bit-for-bit identical.
+
+This is a useful way to detect non-deterministic builds processes.
+Non-deterministic build processes are a problem because they make it
+practically impossible for users to @emph{verify} whether third-party
+binaries are genuine.  @xref{Invoking guix challenge}, for more.
+
+Note that, currently, the differing build results are not kept around,
+so you will have to manually investigate in case of an error---e.g., by
+stashing one of the build results with @code{guix archive --export},
+then rebuilding, and finally comparing the two results.
+
 @item --no-build-hook
 Do not attempt to offload builds @i{via} the daemon's ``build hook''
 (@pxref{Daemon Offload Setup}).  That is, always build things locally
diff --git a/guix/scripts/build.scm b/guix/scripts/build.scm
index 192ed5cd45..072840b953 100644
--- a/guix/scripts/build.scm
+++ b/guix/scripts/build.scm
@@ -171,6 +171,8 @@ options handled by 'set-build-options-from-command-line', and listed in
   (display (_ "
       --verbosity=LEVEL  use the given verbosity LEVEL"))
   (display (_ "
+      --rounds=N         build N times in a row to detect non-determinism"))
+  (display (_ "
   -c, --cores=N          allow the use of up to N CPU cores for the build"))
   (display (_ "
   -M, --max-jobs=N       allow at most N build jobs")))
@@ -181,6 +183,7 @@ options handled by 'set-build-options-from-command-line', and listed in
   ;; TODO: Add more options.
   (set-build-options store
                      #:keep-failed? (assoc-ref opts 'keep-failed?)
+                     #:rounds (assoc-ref opts 'rounds)
                      #:build-cores (or (assoc-ref opts 'cores) 0)
                      #:max-build-jobs (or (assoc-ref opts 'max-jobs) 1)
                      #:fallback? (assoc-ref opts 'fallback?)
@@ -210,6 +213,12 @@ options handled by 'set-build-options-from-command-line', and listed in
                   (apply values
                          (alist-cons 'keep-failed? #t result)
                          rest)))
+        (option '("rounds") #t #f
+                (lambda (opt name arg result . rest)
+                  (apply values
+                         (alist-cons 'rounds (string->number* arg)
+                                     result)
+                         rest)))
         (option '("fallback") #f #f
                 (lambda (opt name arg result . rest)
                   (apply values