diff mbox series

[bug#55321] Document building for foreign architectures

Message ID 87k0avdi8p.fsf@gnu.org
State New
Headers show
Series [bug#55321] Document building for foreign architectures | expand

Checks

Context Check Description
cbaines/comparison success View comparision
cbaines/git branch success View Git branch
cbaines/applying patch fail View Laminar job
cbaines/issue success View issue

Commit Message

Mathieu Othacehe May 8, 2022, 5:52 p.m. UTC
Hello,

This is a follow-up of https://issues.guix.gnu.org/55220 that is still
in discussion.

If we were to create a top 10 of the most asked questions on #guix,
"What is --target, what's the difference with --system?", and "Why
--system=aarch64-linux isn't working on my machine?" would be in good
position I guess.

This patch builds upon the proposed introduction of
--list-systems/--list-targets options as well as --system/--target
argument checking to document how to build for foreign architectures.

I hope that this will shed some light on the matter.

Thanks,

Mathieu

Comments

Maxim Cournoyer May 22, 2022, 2:42 a.m. UTC | #1
Hi again,

Mathieu Othacehe <othacehe@gnu.org> writes:

> Hello,
>
> This is a follow-up of https://issues.guix.gnu.org/55220 that is still
> in discussion.
>
> If we were to create a top 10 of the most asked questions on #guix,
> "What is --target, what's the difference with --system?", and "Why
> --system=aarch64-linux isn't working on my machine?" would be in good
> position I guess.
>
> This patch builds upon the proposed introduction of
> --list-systems/--list-targets options as well as --system/--target
> argument checking to document how to build for foreign architectures.
>
> I hope that this will shed some light on the matter.
>
> Thanks,
>
> Mathieu
>
>>From e1fde962a334c6a5c0f855aaf3e11fa9ea73b2d0 Mon Sep 17 00:00:00 2001
> From: Mathieu Othacehe <othacehe@gnu.org>
> Date: Sun, 8 May 2022 18:52:33 +0200
> Subject: [PATCH 1/2] scripts: build: Highlight the current system with
>  --list-systems.
>
> * guix/scripts/build.scm (list-systems): Highlight it.
> ---
>  guix/scripts/build.scm | 12 ++++++++++--
>  1 file changed, 10 insertions(+), 2 deletions(-)
>
> diff --git a/guix/scripts/build.scm b/guix/scripts/build.scm
> index a09c54451f..4383a399a0 100644
> --- a/guix/scripts/build.scm
> +++ b/guix/scripts/build.scm
> @@ -21,6 +21,7 @@
>  
>  (define-module (guix scripts build)
>    #:use-module (guix ui)
> +  #:use-module (guix colors)
>    #:use-module (guix scripts)
>    #:autoload   (guix import json) (json->scheme-file)
>    #:use-module (guix store)
> @@ -342,8 +343,15 @@ (define (list-systems)
>    "Print the available systems."
>    (display (G_ "The available systems are:\n"))
>    (newline)
> -  (format #t "~{   - ~a ~%~}"
> -          (sort (systems) string<?)))
> +  (let ((systems*
> +         (map (lambda (system)
> +                (if (string=? system (%current-system))
> +                    (highlight
> +                     (string-append system " [current]"))
> +                    system))
> +              (systems))))
> +    (format #t "~{   - ~a ~%~}"
> +            (sort systems* string<?))))
>  
>  (define (list-targets)
>    "Print the available targets."
> -- 
> 2.36.0
>
>>From 3d70b0f67a0bcbe16d6f5eaea47410a3f526af05 Mon Sep 17 00:00:00 2001
> From: Mathieu Othacehe <othacehe@gnu.org>
> Date: Sun, 8 May 2022 19:43:47 +0200
> Subject: [PATCH 2/2] doc: Add a 'Foreign architectures' chapter.
>
> * doc/guix.texi ("Foreign architectures"): New chapter.
> ---
>  doc/guix.texi | 173 +++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 172 insertions(+), 1 deletion(-)
>
> diff --git a/doc/guix.texi b/doc/guix.texi
> index 1dc1474ec7..55c0049411 100644
> --- a/doc/guix.texi
> +++ b/doc/guix.texi
> @@ -41,7 +41,7 @@ Copyright @copyright{} 2016, 2017, 2018, 2019, 2020, 2021 Julien Lepiller@*
>  Copyright @copyright{} 2016 Alex ter Weele@*
>  Copyright @copyright{} 2016, 2017, 2018, 2019, 2020, 2021 Christopher Baines@*
>  Copyright @copyright{} 2017, 2018, 2019 Clément Lassieur@*
> -Copyright @copyright{} 2017, 2018, 2020, 2021 Mathieu Othacehe@*
> +Copyright @copyright{} 2017, 2018, 2020, 2021, 2022 Mathieu Othacehe@*
>  Copyright @copyright{} 2017 Federico Beffa@*
>  Copyright @copyright{} 2017, 2018 Carlo Zancanaro@*
>  Copyright @copyright{} 2017 Thomas Danckaert@*
> @@ -173,6 +173,7 @@ Weblate} (@pxref{Translating Guix}).
>  * Development::                 Guix-aided software development.
>  * Programming Interface::       Using Guix in Scheme.
>  * Utilities::                   Package management commands.
> +* Foreign architectures::       Build for foreign architectures.
>  * System Configuration::        Configuring the operating system.
>  * Home Configuration::          Configuring the home environment.
>  * Documentation::               Browsing software user manuals.
> @@ -320,6 +321,10 @@ Invoking @command{guix build}
>  * Additional Build Options::    Options specific to 'guix build'.
>  * Debugging Build Failures::    Real life packaging experience.
>  
> +Foreign architectures
> +* Using cross-compilation::  Build for foreign architecture using cross-compilation.
> +* Using native building::    Build for foreign architectures natively.
> +
>  System Configuration
>  
>  * Using the Configuration System::  Customizing your GNU system.
> @@ -14814,6 +14819,172 @@ Session_PID: 4278
>  @end table
>  @end table
>  
> +@node Foreign architectures
> +@chapter Foreign architectures
> +
> +You might need to use GNU Guix to produce packages (@pxref{Invoking guix
> +package}), packs (@pxref{Invoking guix pack}) or even full systems
> +(@pxref{Invoking guix system}) targeting computers with different CPU
> +architectures than the one of your current CPU.

Nitpick, but I'd perhaps invert this long sentence to something like
"GNU Guix can target computers of different CPU architectures when
producing packages, packs or full systems".

> +
> +GNU Guix supports two distinct mechanisms to target foreign
> +architectures:
> +
> +@enumerate
> +@item
> +The first one is the traditional
> +@uref{https://en.wikipedia.org/wiki/Cross_compiler,cross-compilation}
> +mechanism.
> +@item
> +The second one, called native building, consists in building using the
> +CPU instruction set of the foreign system you are targeting.  It often
> +requires emulation, using the QEMU program for instance.
> +@end enumerate

Since you are already enumerating the entries, I'd forego with "The
first one," and "The second one,", which seems redundant to me.

> +@menu
> +* Using cross-compilation::  Build for foreign architecture using cross-compilation.
> +* Using native building::    Build for foreign architectures natively.
> +@end menu
> +
> +@node Using cross-compilation
> +@section Using cross-compilation
> +
> +@cindex foreign architectures
> +The GNU Guix commands supporting cross-compilation are proposing the
> +@option{--list-targets} and @option{--target} options.
> +
> +The @option{--list-targets} option lists all the supported targets that
> +can be passed as an argument to @option{--target}.
> +
> +@example
> +$ guix build --list-targets
> +The available targets are:
> +
> +   - aarch64-linux-gnu
> +   - arm-linux-gnueabihf
> +   - i586-pc-gnu
> +   - i686-linux-gnu
> +   - i686-w64-mingw32
> +   - mips64el-linux-gnu
> +   - powerpc-linux-gnu
> +   - powerpc64le-linux-gnu
> +   - riscv64-linux-gnu
> +   - s390x-linux-gnu
> +   - x86_64-linux-gnu
> +   - x86_64-w64-mingw32
> +@end example
> +
> +The targets are specified as GNU triplets (@pxref{Specifying Target
> +Triplets, GNU configuration triplets,, autoconf, Autoconf}).
> +
> +Those triplets are passed to GCC and the other underlying compilers
> +possibly involved when building a package, a system image or any other
> +GNU Guix output.
> +
> +@example
> +$ guix build --target=aarch64-linux-gnu hello
> +/gnu/store/9926by9qrxa91ijkhw9ndgwp4bn24g9h-hello-2.12
> +
> +$ file /gnu/store/9926by9qrxa91ijkhw9ndgwp4bn24g9h-hello-2.12/bin/hello
> +/gnu/store/9926by9qrxa91ijkhw9ndgwp4bn24g9h-hello-2.12/bin/hello: ELF
> +64-bit LSB executable, ARM aarch64 @dots{}
> +@end example
> +
> +The major benefit of cross-compilation is that there are no performance
> +penalties compared to emulation using QEMU.  There are however higher

nitpick: perhaps use singular "no performance penalty".

> +risks that some packages are failing to cross-compile because few GNU
                            ^ fail [to cross-compile ...]
> +Guix users are using this mecanism extensively.
> +
> +@node Using native building
> +@section Using native building
> +
> +The GNU Guix commands supporting to impersonate a specific system are
                         ^ "that support impersonating", perhaps?
                         
> +proposing the @option{--list-systems} and @option{--system} options.

Perhaps s/are proposing/have/.

> +The @option{--list-systems} option lists all the supported systems that
> +can be passed as an argument to @option{--system}.
> +
> +@example
> +$ guix build --list-systems
> +The available systems are:
> +
> +   - x86_64-linux [current]
> +   - aarch64-linux
> +   - armhf-linux
> +   - i586-gnu
> +   - i686-linux
> +   - mips64el-linux
> +   - powerpc-linux
> +   - powerpc64le-linux
> +   - riscv64-linux
> +   - s390x-linux
> +
> +$ guix build --system=i686-linux hello
> +/gnu/store/cc0km35s8x2z4pmwkrqqjx46i8b1i3gm-hello-2.12
> +
> +$ file /gnu/store/cc0km35s8x2z4pmwkrqqjx46i8b1i3gm-hello-2.12/bin/hello
> +/gnu/store/cc0km35s8x2z4pmwkrqqjx46i8b1i3gm-hello-2.12/bin/hello: ELF
> +32-bit LSB executable, Intel 80386 @dots{}
> +@end example
> +
> +In the above example, the GNU Guix current system is @var{x86_64-linux}.
> +The @var{hello} package is however built for the @var{i686-linux}
> +system.
> +
> +This is possible because the @var{i686} CPU instruction set is a subset
> +of the @var{x86_64}, hence @var{i686} targeting binaries can be run on
> +@var{x86_64}.
> +
> +Still in the context of the previous example, if picking the
> +@var{aarch64-linux} system and the @command{guix build
> +--system=aarch64-linux hello} has to build some derivations, an extra
> +step might be needed.
> +
> +The @var{aarch64-linux} targeting binaries cannot directly be run on a
> +@var{x86_64-linux} system.  An emulation layer is requested.  The GNU
                                                     ^ needed.
> +Guix daemon can take advantage of the Linux kernel
> +@uref{https://en.wikipedia.org/wiki/Binfmt_misc,binfmt_misc} mechanism
> +for that.  In short, the Linux kernel can defer the execution of a
> +binary targeting a foreign platform, here @var{aarch64-linux}, to a
> +userspace program, usually an emulator.
> +
> +There is a GNU Guix service that registers QEMU as a backend for the
> +@code{binfmt_misc} mechanism (@pxref{Virtualization Services,
> +@code{qemu-binfmt-service-type}}).  On Debian based foreign
                                          ^Debian-based
> +distributions, the alternative would be the @code{qemu-user-static}
> +package.
> +
> +If the @code{binfmt_misc} mechanism is not setup correctly, the building
> +will fail this way:
> +
> +@example
> +$ guix build --system=armhf-linux hello --check
> +@dots{}
> +@ unsupported-platform /gnu/store/jjn969pijv7hff62025yxpfmc8zy0aq0-hello-2.12.drv aarch64-linux
> +while setting up the build environment: a `aarch64-linux' is required to
> +build `/gnu/store/jjn969pijv7hff62025yxpfmc8zy0aq0-hello-2.12.drv', but
> +I am a `x86_64-linux'@dots{}
> +@end example
> +
> +whereas, with the @code{binfmt_misc} mechanism correctly linked with
> +QEMU, one can expect to see:
> +
> +@example
> +$ guix build --system=armhf-linux hello --check
> +
> +@end example
> +
> +The main advantage of native building compared to cross-compiling, is
> +that more packages are likely to build correctly.  However it comes at a
> +price: compilation backed by QEMU is @emph{way slower} than
> +cross-compilation, because every instruction needs to be emulated.
> +
> +The availability of substitutes for the architecture targeted by the
> +@code{--system} option can mitigate this problem.  An other way to work
> +around it is to install GNU Guix on a machine which CPU is supporting
> +the targeted instruction set, an set it up as an offload machine
> +(@pxref{Daemon Offload Setup}).
> +
>  @node System Configuration
>  @chapter System Configuration

This is very detailed and will cover many use cases that people would
have had to figure themselves before.

Thank you!  LGTM with my small comments above.

Maxim
Mathieu Othacehe May 22, 2022, 1:14 p.m. UTC | #2
Hey,

> This is very detailed and will cover many use cases that people would
> have had to figure themselves before.
>
> Thank you!  LGTM with my small comments above.

I'm glad that you like it and fixed your remarks before pushed the whole
series. Thanks Ludo, Maxime and Maxim for having a look to it ;).

Mathieu
Ludovic Courtès May 22, 2022, 8:47 p.m. UTC | #3
Hi!

I’m late to the party but I’d like to contribute this: 👍

Some nitpicking though:

> +Foreign architectures
> +* Using cross-compilation::  Build for foreign architecture using cross-compilation.
> +* Using native building::    Build for foreign architectures natively.

Please use “title case” for node and section names, as in:

  Foreign Architectures

> +You might need to use GNU Guix to produce packages (@pxref{Invoking guix
> +package}), packs (@pxref{Invoking guix pack}) or even full systems
> +(@pxref{Invoking guix system}) targeting computers with different CPU
> +architectures than the one of your current CPU.
> +
> +GNU Guix supports two distinct mechanisms to target foreign

As a rule of thumb, I think it’s good to avoid repeating “GNU Guix”
because the reader most likely knows that it’s the manual they’re
reading :-) and because we can often be more precise or less verbose.
In this case, we could write:

  You can build packages, packs, or even full systems targeting
  computers with a different CPU architecture than the CPU you are
  using, or running a different operating system.

> +@item
> +The second one, called native building, consists in building using the
> +CPU instruction set of the foreign system you are targeting.  It often
> +requires emulation, using the QEMU program for instance.

> +The targets are specified as GNU triplets (@pxref{Specifying Target

s/The targets/Targets/  (or “Cross-compilation targets”?)

> +@node Using native building
> +@section Using native building

Or: “Native Builds”?  (“Using […] building” sounds weird to me.)

That’s all, thank you!  :-)

Ludo’.
Mathieu Othacehe May 25, 2022, 7:49 a.m. UTC | #4
Hey Ludo,

> Or: “Native Builds”?  (“Using […] building” sounds weird to me.)
>
> That’s all, thank you!  :-)

Thanks for having a look :) I fixed your remarks in
436afdfe46f6aac173ae161eb52367b7fdc30944.

Mathieu
Ludovic Courtès May 25, 2022, 1:28 p.m. UTC | #5
Hi,

Mathieu Othacehe <othacehe@gnu.org> skribis:

>> Or: “Native Builds”?  (“Using […] building” sounds weird to me.)
>>
>> That’s all, thank you!  :-)
>
> Thanks for having a look :) I fixed your remarks in
> 436afdfe46f6aac173ae161eb52367b7fdc30944.

Neat; there are still non-title-case node/section names though.

My preference would be to change along these lines:

  Using cross-compilation -> Cross-Compilation
  Using native builds -> Emulated Native Builds

(It’s better to agree on these before they’re translated and before
there are people linking to them out there.)

Thanks,
Ludo’.
diff mbox series

Patch

From 3d70b0f67a0bcbe16d6f5eaea47410a3f526af05 Mon Sep 17 00:00:00 2001
From: Mathieu Othacehe <othacehe@gnu.org>
Date: Sun, 8 May 2022 19:43:47 +0200
Subject: [PATCH 2/2] doc: Add a 'Foreign architectures' chapter.

* doc/guix.texi ("Foreign architectures"): New chapter.
---
 doc/guix.texi | 173 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 172 insertions(+), 1 deletion(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 1dc1474ec7..55c0049411 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -41,7 +41,7 @@  Copyright @copyright{} 2016, 2017, 2018, 2019, 2020, 2021 Julien Lepiller@*
 Copyright @copyright{} 2016 Alex ter Weele@*
 Copyright @copyright{} 2016, 2017, 2018, 2019, 2020, 2021 Christopher Baines@*
 Copyright @copyright{} 2017, 2018, 2019 Clément Lassieur@*
-Copyright @copyright{} 2017, 2018, 2020, 2021 Mathieu Othacehe@*
+Copyright @copyright{} 2017, 2018, 2020, 2021, 2022 Mathieu Othacehe@*
 Copyright @copyright{} 2017 Federico Beffa@*
 Copyright @copyright{} 2017, 2018 Carlo Zancanaro@*
 Copyright @copyright{} 2017 Thomas Danckaert@*
@@ -173,6 +173,7 @@  Weblate} (@pxref{Translating Guix}).
 * Development::                 Guix-aided software development.
 * Programming Interface::       Using Guix in Scheme.
 * Utilities::                   Package management commands.
+* Foreign architectures::       Build for foreign architectures.
 * System Configuration::        Configuring the operating system.
 * Home Configuration::          Configuring the home environment.
 * Documentation::               Browsing software user manuals.
@@ -320,6 +321,10 @@  Invoking @command{guix build}
 * Additional Build Options::    Options specific to 'guix build'.
 * Debugging Build Failures::    Real life packaging experience.
 
+Foreign architectures
+* Using cross-compilation::  Build for foreign architecture using cross-compilation.
+* Using native building::    Build for foreign architectures natively.
+
 System Configuration
 
 * Using the Configuration System::  Customizing your GNU system.
@@ -14814,6 +14819,172 @@  Session_PID: 4278
 @end table
 @end table
 
+@node Foreign architectures
+@chapter Foreign architectures
+
+You might need to use GNU Guix to produce packages (@pxref{Invoking guix
+package}), packs (@pxref{Invoking guix pack}) or even full systems
+(@pxref{Invoking guix system}) targeting computers with different CPU
+architectures than the one of your current CPU.
+
+GNU Guix supports two distinct mechanisms to target foreign
+architectures:
+
+@enumerate
+@item
+The first one is the traditional
+@uref{https://en.wikipedia.org/wiki/Cross_compiler,cross-compilation}
+mechanism.
+@item
+The second one, called native building, consists in building using the
+CPU instruction set of the foreign system you are targeting.  It often
+requires emulation, using the QEMU program for instance.
+@end enumerate
+
+@menu
+* Using cross-compilation::  Build for foreign architecture using cross-compilation.
+* Using native building::    Build for foreign architectures natively.
+@end menu
+
+@node Using cross-compilation
+@section Using cross-compilation
+
+@cindex foreign architectures
+The GNU Guix commands supporting cross-compilation are proposing the
+@option{--list-targets} and @option{--target} options.
+
+The @option{--list-targets} option lists all the supported targets that
+can be passed as an argument to @option{--target}.
+
+@example
+$ guix build --list-targets
+The available targets are:
+
+   - aarch64-linux-gnu
+   - arm-linux-gnueabihf
+   - i586-pc-gnu
+   - i686-linux-gnu
+   - i686-w64-mingw32
+   - mips64el-linux-gnu
+   - powerpc-linux-gnu
+   - powerpc64le-linux-gnu
+   - riscv64-linux-gnu
+   - s390x-linux-gnu
+   - x86_64-linux-gnu
+   - x86_64-w64-mingw32
+@end example
+
+The targets are specified as GNU triplets (@pxref{Specifying Target
+Triplets, GNU configuration triplets,, autoconf, Autoconf}).
+
+Those triplets are passed to GCC and the other underlying compilers
+possibly involved when building a package, a system image or any other
+GNU Guix output.
+
+@example
+$ guix build --target=aarch64-linux-gnu hello
+/gnu/store/9926by9qrxa91ijkhw9ndgwp4bn24g9h-hello-2.12
+
+$ file /gnu/store/9926by9qrxa91ijkhw9ndgwp4bn24g9h-hello-2.12/bin/hello
+/gnu/store/9926by9qrxa91ijkhw9ndgwp4bn24g9h-hello-2.12/bin/hello: ELF
+64-bit LSB executable, ARM aarch64 @dots{}
+@end example
+
+The major benefit of cross-compilation is that there are no performance
+penalties compared to emulation using QEMU.  There are however higher
+risks that some packages are failing to cross-compile because few GNU
+Guix users are using this mecanism extensively.
+
+@node Using native building
+@section Using native building
+
+The GNU Guix commands supporting to impersonate a specific system are
+proposing the @option{--list-systems} and @option{--system} options.
+
+The @option{--list-systems} option lists all the supported systems that
+can be passed as an argument to @option{--system}.
+
+@example
+$ guix build --list-systems
+The available systems are:
+
+   - x86_64-linux [current]
+   - aarch64-linux
+   - armhf-linux
+   - i586-gnu
+   - i686-linux
+   - mips64el-linux
+   - powerpc-linux
+   - powerpc64le-linux
+   - riscv64-linux
+   - s390x-linux
+
+$ guix build --system=i686-linux hello
+/gnu/store/cc0km35s8x2z4pmwkrqqjx46i8b1i3gm-hello-2.12
+
+$ file /gnu/store/cc0km35s8x2z4pmwkrqqjx46i8b1i3gm-hello-2.12/bin/hello
+/gnu/store/cc0km35s8x2z4pmwkrqqjx46i8b1i3gm-hello-2.12/bin/hello: ELF
+32-bit LSB executable, Intel 80386 @dots{}
+@end example
+
+In the above example, the GNU Guix current system is @var{x86_64-linux}.
+The @var{hello} package is however built for the @var{i686-linux}
+system.
+
+This is possible because the @var{i686} CPU instruction set is a subset
+of the @var{x86_64}, hence @var{i686} targeting binaries can be run on
+@var{x86_64}.
+
+Still in the context of the previous example, if picking the
+@var{aarch64-linux} system and the @command{guix build
+--system=aarch64-linux hello} has to build some derivations, an extra
+step might be needed.
+
+The @var{aarch64-linux} targeting binaries cannot directly be run on a
+@var{x86_64-linux} system.  An emulation layer is requested.  The GNU
+Guix daemon can take advantage of the Linux kernel
+@uref{https://en.wikipedia.org/wiki/Binfmt_misc,binfmt_misc} mechanism
+for that.  In short, the Linux kernel can defer the execution of a
+binary targeting a foreign platform, here @var{aarch64-linux}, to a
+userspace program, usually an emulator.
+
+There is a GNU Guix service that registers QEMU as a backend for the
+@code{binfmt_misc} mechanism (@pxref{Virtualization Services,
+@code{qemu-binfmt-service-type}}).  On Debian based foreign
+distributions, the alternative would be the @code{qemu-user-static}
+package.
+
+If the @code{binfmt_misc} mechanism is not setup correctly, the building
+will fail this way:
+
+@example
+$ guix build --system=armhf-linux hello --check
+@dots{}
+@ unsupported-platform /gnu/store/jjn969pijv7hff62025yxpfmc8zy0aq0-hello-2.12.drv aarch64-linux
+while setting up the build environment: a `aarch64-linux' is required to
+build `/gnu/store/jjn969pijv7hff62025yxpfmc8zy0aq0-hello-2.12.drv', but
+I am a `x86_64-linux'@dots{}
+@end example
+
+whereas, with the @code{binfmt_misc} mechanism correctly linked with
+QEMU, one can expect to see:
+
+@example
+$ guix build --system=armhf-linux hello --check
+
+@end example
+
+The main advantage of native building compared to cross-compiling, is
+that more packages are likely to build correctly.  However it comes at a
+price: compilation backed by QEMU is @emph{way slower} than
+cross-compilation, because every instruction needs to be emulated.
+
+The availability of substitutes for the architecture targeted by the
+@code{--system} option can mitigate this problem.  An other way to work
+around it is to install GNU Guix on a machine which CPU is supporting
+the targeted instruction set, an set it up as an offload machine
+(@pxref{Daemon Offload Setup}).
+
 @node System Configuration
 @chapter System Configuration
 
-- 
2.36.0