guix build: Add '--with-debug-info'.

* guix/scripts/build.scm (transform-package-with-debug-info): New
procedure.
(%transformations): Add 'with-debug-info'.
(%transformation-options, show-transformation-options-help): Add
'--with-debug-info'.
* tests/scripts-build.scm ("options->transformation, with-debug-info"):
New test.
* doc/guix.texi (Package Transformation Options): Document
'--with-debug-info'.
(Installing Debugging Files): Introduce sections.  Remove bit about
eventual "opt-out" since this is not happening.  Document
'--with-debug-info' under "Rebuilding with Debugging Info".
This commit is contained in:
Ludovic Courtès 2020-10-09 18:17:41 +02:00
parent ccf3dcba3d
commit 6aeda81602
No known key found for this signature in database
GPG key ID: 090B11993D9AEBB5
3 changed files with 173 additions and 5 deletions

View file

@ -352,6 +352,11 @@ Defining Services
* Service Reference:: API reference. * Service Reference:: API reference.
* Shepherd Services:: A particular type of service. * Shepherd Services:: A particular type of service.
Installing Debugging Files
* Separate Debug Info:: Installing 'debug' outputs.
* Rebuilding Debug Info:: Building missing debug info.
Bootstrapping Bootstrapping
* Reduced Binary Seed Bootstrap:: A Bootstrap worthy of GNU. * Reduced Binary Seed Bootstrap:: A Bootstrap worthy of GNU.
@ -9884,6 +9889,37 @@ must be compatible. If @var{replacement} is somehow incompatible with
@var{package}, then the resulting package may be unusable. Use with @var{package}, then the resulting package may be unusable. Use with
care! care!
@cindex debugging info, rebuilding
@item --with-debug-info=@var{package}
Build @var{package} in a way that preserves its debugging info and graft
it onto packages that depend on it. This is useful if @var{package}
does not already provide debugging info as a @code{debug} output
(@pxref{Installing Debugging Files}).
For example, suppose you're experiencing a crash in Inkscape and would
like to see what's up in GLib, a library deep down in Inkscape's
dependency graph. GLib lacks a @code{debug} output, so debugging is
tough. Fortunately, you rebuild GLib with debugging info and tack it on
Inkscape:
@example
guix install inkscape --with-debug-info=glib
@end example
Only GLib needs to be recompiled so this takes a reasonable amount of
time. @xref{Installing Debugging Files}, for more info.
@quotation Note
Under the hood, this option works by passing the @samp{#:strip-binaries?
#f} to the build system of the package of interest (@pxref{Build
Systems}). Most build systems support that option but some do not. In
that case, an error is raised.
Likewise, if a C/C++ package is built without @code{-g} (which is rarely
the case), debugging info will remain unavailable even when
@code{#:strip-binaries?} is false.
@end quotation
@cindex tool chain, changing the build tool chain of a package @cindex tool chain, changing the build tool chain of a package
@item --with-c-toolchain=@var{package}=@var{toolchain} @item --with-c-toolchain=@var{package}=@var{toolchain}
This option changes the compilation of @var{package} and everything that This option changes the compilation of @var{package} and everything that
@ -31688,6 +31724,18 @@ typically written in the ELF format, with a section containing
debugger, GDB, to map binary code to source code; it is required to debugger, GDB, to map binary code to source code; it is required to
debug a compiled program in good conditions. debug a compiled program in good conditions.
This chapter explains how to use separate debug info when packages
provide it, and how to rebuild packages with debug info when it's
missing.
@menu
* Separate Debug Info:: Installing 'debug' outputs.
* Rebuilding Debug Info:: Building missing debug info.
@end menu
@node Separate Debug Info
@section Separate Debug Info
The problem with debugging information is that is takes up a fair amount The problem with debugging information is that is takes up a fair amount
of disk space. For example, debugging information for the GNU C Library of disk space. For example, debugging information for the GNU C Library
weighs in at more than 60 MiB. Thus, as a user, keeping all the weighs in at more than 60 MiB. Thus, as a user, keeping all the
@ -31737,12 +31785,75 @@ directory using the @code{directory} command (@pxref{Source Path,
@c XXX: keep me up-to-date @c XXX: keep me up-to-date
The @code{debug} output mechanism in Guix is implemented by the The @code{debug} output mechanism in Guix is implemented by the
@code{gnu-build-system} (@pxref{Build Systems}). Currently, it is @code{gnu-build-system} (@pxref{Build Systems}). Currently, it is
opt-in---debugging information is available only for the packages opt-in---debugging information is available only for the packages with
with definitions explicitly declaring a @code{debug} output. This may be definitions explicitly declaring a @code{debug} output. To check
changed to opt-out in the future if our build farm servers can handle whether a package has a @code{debug} output, use @command{guix package
the load. To check whether a package has a @code{debug} output, use --list-available} (@pxref{Invoking guix package}).
@command{guix package --list-available} (@pxref{Invoking guix package}).
Read on for how to deal with packages lacking a @code{debug} output.
@node Rebuilding Debug Info
@section Rebuilding Debug Info
@cindex debugging info, rebuilding
As we saw above, some packages, but not all, provide debugging info in a
@code{debug} output. What can you do when debugging info is missing?
The @option{--with-debug-info} option provides a solution to that: it
allows you to rebuild the package(s) for which debugging info is
missing---and only those---and to graft those onto the application
you're debugging. Thus, while it's not as fast as installing a
@code{debug} output, it is relatively inexpensive.
Let's illustrate that. Suppose you're experiencing a bug in Inkscape
and would like to see what's going on in GLib, a library that's deep
down in its dependency graph. As it turns out, GLib does not have a
@code{debug} output and the backtrace GDB shows is all sadness:
@example
(gdb) bt
#0 0x00007ffff5f92190 in g_getenv ()
from /gnu/store/@dots{}-glib-2.62.6/lib/libglib-2.0.so.0
#1 0x00007ffff608a7d6 in gobject_init_ctor ()
from /gnu/store/@dots{}-glib-2.62.6/lib/libgobject-2.0.so.0
#2 0x00007ffff7fe275a in call_init (l=<optimized out>, argc=argc@@entry=1, argv=argv@@entry=0x7fffffffcfd8,
env=env@@entry=0x7fffffffcfe8) at dl-init.c:72
#3 0x00007ffff7fe2866 in call_init (env=0x7fffffffcfe8, argv=0x7fffffffcfd8, argc=1, l=<optimized out>)
at dl-init.c:118
@end example
To address that, you install Inkscape linked against a variant GLib that
contains debug info:
@example
guix install inkscape --with-debug-info=glib
@end example
This time, debugging will be a whole lot nicer:
@example
$ gdb --args sh -c 'exec inkscape'
@dots{}
(gdb) b g_getenv
Function "g_getenv" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (g_getenv) pending.
(gdb) r
Starting program: /gnu/store/@dots{}-profile/bin/sh -c exec\ inkscape
@dots{}
(gdb) bt
#0 g_getenv (variable=variable@@entry=0x7ffff60c7a2e "GOBJECT_DEBUG") at ../glib-2.62.6/glib/genviron.c:252
#1 0x00007ffff608a7d6 in gobject_init () at ../glib-2.62.6/gobject/gtype.c:4380
#2 gobject_init_ctor () at ../glib-2.62.6/gobject/gtype.c:4493
#3 0x00007ffff7fe275a in call_init (l=<optimized out>, argc=argc@@entry=3, argv=argv@@entry=0x7fffffffd088,
env=env@@entry=0x7fffffffd0a8) at dl-init.c:72
@dots{}
@end example
Much better!
Note that there can be packages for which @option{--with-debug-info}
will not have the desired effect. @xref{Package Transformation Options,
@option{--with-debug-info}}, for more information.
@node Security Updates @node Security Updates
@chapter Security Updates @chapter Security Updates

View file

@ -474,6 +474,40 @@ (define replacements
obj) obj)
obj))) obj)))
(define (transform-package-with-debug-info specs)
"Return a procedure that, when passed a package, set its 'replacement' field
to the same package but with #:strip-binaries? #f in its 'arguments' field."
(define (non-stripped p)
(package
(inherit p)
(arguments
(substitute-keyword-arguments (package-arguments p)
((#:strip-binaries? _ #f) #f)))))
(define (package-with-debug-info p)
(if (member "debug" (package-outputs p))
p
(let loop ((p p))
(match (package-replacement p)
(#f
(package
(inherit p)
(replacement (non-stripped p))))
(next
(package
(inherit p)
(replacement (loop next))))))))
(define rewrite
(package-input-rewriting/spec (map (lambda (spec)
(cons spec package-with-debug-info))
specs)))
(lambda (store obj)
(if (package? obj)
(rewrite obj)
obj)))
(define (transform-package-tests specs) (define (transform-package-tests specs)
"Return a procedure that, when passed a package, sets #:tests? #f in its "Return a procedure that, when passed a package, sets #:tests? #f in its
'arguments' field." 'arguments' field."
@ -505,6 +539,7 @@ (define %transformations
(with-commit . ,transform-package-source-commit) (with-commit . ,transform-package-source-commit)
(with-git-url . ,transform-package-source-git-url) (with-git-url . ,transform-package-source-git-url)
(with-c-toolchain . ,transform-package-toolchain) (with-c-toolchain . ,transform-package-toolchain)
(with-debug-info . ,transform-package-with-debug-info)
(without-tests . ,transform-package-tests))) (without-tests . ,transform-package-tests)))
(define (transformation-procedure key) (define (transformation-procedure key)
@ -536,6 +571,8 @@ (define %transformation-options
(parser 'with-git-url)) (parser 'with-git-url))
(option '("with-c-toolchain") #t #f (option '("with-c-toolchain") #t #f
(parser 'with-c-toolchain)) (parser 'with-c-toolchain))
(option '("with-debug-info") #t #f
(parser 'with-debug-info))
(option '("without-tests") #t #f (option '("without-tests") #t #f
(parser 'without-tests))))) (parser 'without-tests)))))
@ -561,6 +598,9 @@ (define (show-transformation-options-help)
(display (G_ " (display (G_ "
--with-c-toolchain=PACKAGE=TOOLCHAIN --with-c-toolchain=PACKAGE=TOOLCHAIN
build PACKAGE and its dependents with TOOLCHAIN")) build PACKAGE and its dependents with TOOLCHAIN"))
(display (G_ "
--with-debug-info=PACKAGE
build PACKAGE and preserve its debug info"))
(display (G_ " (display (G_ "
--without-tests=PACKAGE --without-tests=PACKAGE
build PACKAGE without running its tests"))) build PACKAGE without running its tests")))

View file

@ -348,6 +348,23 @@ (define (package-name* obj)
(with-store store (with-store store
(eq? (t store p) p)))) (eq? (t store p) p))))
(test-equal "options->transformation, with-debug-info"
'(#:strip-binaries? #f)
(let* ((dep (dummy-package "chbouib"))
(p (dummy-package "thingie"
(build-system gnu-build-system)
(inputs `(("foo" ,dep)
("bar" ,grep)))))
(t (options->transformation
'((with-debug-info . "chbouib")))))
(with-store store
(let ((new (t store p)))
(match (package-inputs new)
((("foo" dep0) ("bar" dep1))
(and (string=? (package-full-name dep1)
(package-full-name grep))
(package-arguments (package-replacement dep0)))))))))
(test-assert "options->transformation, without-tests" (test-assert "options->transformation, without-tests"
(let* ((dep (dummy-package "dep")) (let* ((dep (dummy-package "dep"))
(p (dummy-package "foo" (p (dummy-package "foo"