guix build: Add '--rounds'.

* guix/scripts/build.scm (show-build-options-help)
(%standard-build-options): Add --rounds.
(set-build-options-from-command-line): Honor it.
* doc/guix.texi (Invoking guix build): Document it.
* doc/contributing.texi (Submitting Patches): Mention it.
This commit is contained in:
Ludovic Courtès 2015-12-08 23:27:53 +01:00
parent 2fba87ac7c
commit 5b74fe065b
3 changed files with 44 additions and 5 deletions

View file

@ -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}). @var{package}} will help you do that (@pxref{Invoking guix refresh}).
@item @item
@cindex determinism, of build processes
@cindex reproducible builds, checking
Check whether the package's build process is deterministic. This Check whether the package's build process is deterministic. This
typically means checking whether an independent build of the package typically means checking whether an independent build of the package
yields the exact same result that you obtained, bit for bit. yields the exact same result that you obtained, bit for bit.
A simple way to do that is with @command{guix challenge} A simple way to do that is by building the same package several times in
(@pxref{Invoking guix challenge}). You may run it once the package has a row on your machine (@pxref{Invoking guix build}):
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 @example
that can build it and run @command{guix publish}. 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 @end enumerate

View file

@ -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 locally instead of allowing downloads of pre-built binaries
(@pxref{Substitutes}). (@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 @item --no-build-hook
Do not attempt to offload builds @i{via} the daemon's ``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 (@pxref{Daemon Offload Setup}). That is, always build things locally

View file

@ -170,6 +170,8 @@ (define (show-build-options-help)
--timeout=SECONDS mark the build as failed after SECONDS of activity")) --timeout=SECONDS mark the build as failed after SECONDS of activity"))
(display (_ " (display (_ "
--verbosity=LEVEL use the given verbosity LEVEL")) --verbosity=LEVEL use the given verbosity LEVEL"))
(display (_ "
--rounds=N build N times in a row to detect non-determinism"))
(display (_ " (display (_ "
-c, --cores=N allow the use of up to N CPU cores for the build")) -c, --cores=N allow the use of up to N CPU cores for the build"))
(display (_ " (display (_ "
@ -181,6 +183,7 @@ (define (set-build-options-from-command-line store opts)
;; TODO: Add more options. ;; TODO: Add more options.
(set-build-options store (set-build-options store
#:keep-failed? (assoc-ref opts 'keep-failed?) #:keep-failed? (assoc-ref opts 'keep-failed?)
#:rounds (assoc-ref opts 'rounds)
#:build-cores (or (assoc-ref opts 'cores) 0) #:build-cores (or (assoc-ref opts 'cores) 0)
#:max-build-jobs (or (assoc-ref opts 'max-jobs) 1) #:max-build-jobs (or (assoc-ref opts 'max-jobs) 1)
#:fallback? (assoc-ref opts 'fallback?) #:fallback? (assoc-ref opts 'fallback?)
@ -210,6 +213,12 @@ (define %standard-build-options
(apply values (apply values
(alist-cons 'keep-failed? #t result) (alist-cons 'keep-failed? #t result)
rest))) 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 (option '("fallback") #f #f
(lambda (opt name arg result . rest) (lambda (opt name arg result . rest)
(apply values (apply values