diff --git a/chapter05/glibc.xml b/chapter05/glibc.xml
index 7b31f11ca..d84a8f57f 100644
--- a/chapter05/glibc.xml
+++ b/chapter05/glibc.xml
@@ -94,7 +94,6 @@ cd build
--host=$LFS_TGT \
--build=$(../scripts/config.guess) \
--enable-kernel=&min-kernel; \
- --with-headers=$LFS/usr/include \
--disable-nscd \
libc_cv_slibdir=/usr/lib
@@ -119,16 +118,6 @@ cd build
-
- --with-headers=$LFS/usr/include
-
- This tells Glibc to compile itself against the headers
- recently installed to the $LFS/usr/include directory, so that
- it knows exactly what features the kernel has and can optimize
- itself accordingly.
-
-
-
libc_cv_slibdir=/usr/lib
@@ -192,7 +181,7 @@ cd build
class="directory">/) directory. Here we specify that
the package is installed in
$LFS, which will become the root directory in .
+ "ch-tools-chroot" role='.'/>
@@ -203,32 +192,101 @@ cd build
sed '/RTLDLIST=/s@/usr@@g' -i $LFS/usr/bin/ldd
-
- At this point, it is imperative to stop and ensure that the basic
- functions (compiling and linking) of the new toolchain are working as
- expected. To perform a sanity check, run the following commands:
+ Now that our cross toolchain is in place, it is important to ensure
+ that compiling and linking will work as expected. We do this by performing
+ some sanity checks:
-echo 'int main(){}' | $LFS_TGT-gcc -xc -
-readelf -l a.out | grep ld-linux
+echo 'int main(){}' | $LFS_TGT-gcc -x c - -v -Wl,--verbose &> dummy.log
+readelf -l a.out | grep ': /lib'
- If everything is working correctly, there should be no errors,
- and the output of the last command will be of the form:
+ There should be no errors,
+ and the output of the last command will be (allowing for
+ platform-specific differences in the dynamic linker name):
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
- Note that for 32-bit machines, the interpreter name will be
- /lib/ld-linux.so.2.
+ Note that for 32-bit machines, the interpreter name will be
+ /lib/ld-linux.so.2.
- If the output is not as shown above, or there is no output at all,
- then something is wrong. Investigate and retrace the steps to find out
- where the problem is and correct it. This issue must be resolved before
- continuing.
+ Note that this path should not contain
+ /mnt/lfs (or the value of
+ the LFS variable if you used a different one). The path is
+ resolved when the compiled program is executed, and that should only happen
+ after we enter the chroot environment where the kernel would consider
+ $LFS as the root directory
+ (/).
- Once all is well, clean up the test file:
+ Now make sure that we're set up to use the correct start files:
-rm -v a.out
+grep -E -o "$LFS/lib.*/S?crt[1in].*succeeded" dummy.log
-
+ The output of the last command should be:
+
+/mnt/lfs/lib/../lib/Scrt1.o succeeded
+/mnt/lfs/lib/../lib/crti.o succeeded
+/mnt/lfs/lib/../lib/crtn.o succeeded
+
+ Verify that the compiler is searching for the correct header
+ files:
+
+grep -B3 "^ $LFS/usr/include" dummy.log
+
+ This command should return the following output:
+
+#include <...> search starts here:
+ /mnt/lfs/tools/lib/gcc/x86_64-lfs-linux-gnu/&gcc-version;/include
+ /mnt/lfs/tools/lib/gcc/x86_64-lfs-linux-gnu/&gcc-version;/include-fixed
+ /mnt/lfs/usr/include
+
+ Again, the directory named after your target triplet may be
+ different than the above, depending on your system architecture.
+
+ Next, verify that the new linker is being used with the correct search paths:
+
+grep 'SEARCH.*/usr/lib' dummy.log |sed 's|; |\n|g'
+
+ References to paths that have components with '-linux-gnu' should
+ be ignored, but otherwise the output of the last command should be:
+
+SEARCH_DIR("=/mnt/lfs/tools/x86_64-lfs-linux-gnu/lib64")
+SEARCH_DIR("=/usr/local/lib64")
+SEARCH_DIR("=/lib64")
+SEARCH_DIR("=/usr/lib64")
+SEARCH_DIR("=/mnt/lfs/tools/x86_64-lfs-linux-gnu/lib")
+SEARCH_DIR("=/usr/local/lib")
+SEARCH_DIR("=/lib")
+SEARCH_DIR("=/usr/lib");
+
+ A 32-bit system may use a few other directories, but anyway
+ the important facet here is all the paths should begin with an equal sign
+ (=), which would be replaced with the sysroot
+ directory that we've configured for the linker.
+
+ Next make sure that we're using the correct libc:
+
+grep "/lib.*/libc.so.6 " dummy.log
+
+ The output of the last command should be:
+
+attempt to open /mnt/lfs/usr/lib/libc.so.6 succeeded
+
+ Make sure GCC is using the correct dynamic linker:
+
+grep found dummy.log
+
+ The output of the last command should be (allowing for
+ platform-specific differences in dynamic linker name):
+
+found ld-linux-x86-64.so.2 at /mnt/lfs/usr/lib/ld-linux-x86-64.so.2
+
+ If the output does not appear as shown above or is not received
+ at all, then something is seriously wrong. Investigate and retrace the
+ steps to find out where the problem is and correct it. Any
+ issues should be resolved before continuing with the process.
+
+ Once everything is working correctly, clean up the test files:
+
+rm -v a.out dummy.log
Building the packages in the next chapter will serve as an
additional check that the toolchain has been built properly. If some
diff --git a/chapter08/gcc.xml b/chapter08/gcc.xml
index e6278ebc2..161318c79 100644
--- a/chapter08/gcc.xml
+++ b/chapter08/gcc.xml
@@ -251,8 +251,7 @@ su tester -c "PATH=$PATH make -k check"
that compiling and linking will work as expected. We do this by performing
some sanity checks:
-echo 'int main(){}' > dummy.c
-cc dummy.c -v -Wl,--verbose &> dummy.log
+echo 'int main(){}' | cc dummy.c -x c - -v -Wl,--verbose &> dummy.log
readelf -l a.out | grep ': /lib'
There should be no errors,
@@ -348,7 +347,7 @@ SEARCH_DIR("/usr/lib");
Once everything is working correctly, clean up the test files:
-rm -v dummy.c a.out dummy.log
+rm -v a.out dummy.log
Finally, move a misplaced file:
diff --git a/part3intro/toolchaintechnotes.xml b/part3intro/toolchaintechnotes.xml
index 1dad94103..a9af3c542 100644
--- a/part3intro/toolchaintechnotes.xml
+++ b/part3intro/toolchaintechnotes.xml
@@ -3,6 +3,9 @@
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
%general-entities;
+
+ <the host triplet>">
]>
@@ -44,6 +47,14 @@
book for a cross-toolchain for some purpose other
than building LFS, unless you really understand what you are doing.
+
+
+ It's known installing GCC pass 2 will break the cross-toolchain.
+ We don't consider it a bug because GCC pass 2 is the last package
+ to be cross-compiled in the book, and we won't fix
+ it until we really need to cross-compile some package after GCC
+ pass 2 in the future.
+
Cross-compilation involves some concepts that deserve a section of
@@ -197,14 +208,105 @@
page.
- In order to fake a cross-compilation in LFS, the name of the host triplet
- is slightly adjusted by changing the "vendor" field in the
- LFS_TGT variable so it says "lfs". We also use the
- --with-sysroot option when building the cross-linker and
- cross-compiler, to tell them where to find the needed host files. This
- ensures that none of the other programs built in can link to libraries on the build
- machine. Only two stages are mandatory, plus one more for tests.
+
+ There are two key points for a cross-compilation:
+
+
+
+
+
+ When producing and processing the machine code supposed to be
+ executed on the host,
the cross-toolchain must be
+ used. Note that the native toolchain from the build
+ may be still invoked to generate machine code supposed to be
+ executed on the build.
For example, the build system
+ may compile a generator with the native toolchain, then generate
+ a C source file with the generator, and finally compile the C
+ source file with the cross-toolchain so the generated code will
+ be able to run on the host.
+
+
+ With an autoconf-based build system, this requirement is ensured
+ by using the --host switch to specify
+ the host
triplet. With this switch the build
+ system will use the toolchain components prefixed
+ with &host-triplet;
+ for generating and processing the machine code for
+ the host
; e.g. the compiler will be
+ &host-triplet;-gcc and the
+ readelf tool will be
+ &host-triplet;-readelf.
+
+
+
+
+ The build system should not attempt to run any generated machine
+ code supposed to be executed on the host.
For
+ example, when building an utility natively, its man page can be
+ generated by running the utility with the
+ --help switch and processing the output,
+ but generally it's not possible to do so for a cross-compilation
+ as the utility may fail
+ to run on the build
: it's obviously impossible to
+ run ARM64 machine code on a x86 CPU (without an emulator).
+
+
+ With an autoconf-based build system, this requirement is
+ satisfied in the cross-compilation mode
where
+ the optional features requiring to run machine code for
+ the host
during the build time are disabled. When the
+ host
triplet is explicitly specified, the
+ cross-compilation mode
is enabled if and only if either
+ the configure script fails to run a dummy
+ program compiled into the host
machine code, or
+ the build
triplet is explicitly specified via the
+ --build switch and it's different from
+ the host
triplet.
+
+
+
+
+ In order to cross-compile a package for the LFS temporary system,
+ the name of the system triplet is slightly adjusted by changing the
+ "vendor" field in the LFS_TGT variable so it
+ says "lfs" and LFS_TGT is then specified as
+ the host
triplet via --host, so
+ the cross-toolchain will be used for generating and processing the
+ machine code running as a part of the LFS temporary system. And, we
+ also need to enable the cross-compilation mode
: despite
+ the host
machine code, i.e. the machine code for the LFS
+ temporary system, is able to execute on the current CPU, it may refer
+ to a library not available on the the build
(the host
+ distro), or some code or data non-exist or defined differently in the
+ library even if it happens to be available. When cross-compiling a
+ package for the LFS temporary system, we cannot rely on the
+ configure script to detect this issue with the
+ dummy program: the dummy only uses a few components in
+ libc that the host distro
+ libc likely provides (unless,
+ maybe the host distro uses a different
+ libc implementaion like Musl),
+ so it won't fail like how the really useful programs would likely.
+ Thus we must explicitly specify the build
triplet to
+ enable the cross-compilation mode.
The value we use is
+ just the default, i.e. the original system triplet from
+ config.guess output, but the cross-compilation
+ mode
depends on an explicit specification as we've
+ discussed.
+
+ We use the --with-sysroot option when
+ building the cross-linker and cross-compiler, to tell them where to find
+ the needed files for the host.
This nearly ensures that
+ none of the other programs built in
+ can link to libraries on
+ the build.
The word nearly
is used because
+ libtool, a compatibility
wrapper of
+ the compiler and the linker for autoconf-based build systems,
+ can try to be too clever and mistakenly pass options allowing the linker
+ to find libraries of the build.
+ To prevent this fallout, we need to delete the libtool archive
+ (.la) files and fix up an
+ outdated libtool copy shipped with the Binutils code.
@@ -228,7 +330,7 @@
3lfslfslfs
- Rebuild and test cc-lfs using cc-lfs on lfs.
+ Rebuild (and maybe test) cc-lfs using cc-lfs on lfs.
@@ -256,30 +358,11 @@
The upshot of the preceding paragraph is that cc1 is unable to
build a fully functional libstdc++ with the degraded libgcc, but cc1
is the only compiler available for building the C/C++ libraries
- during stage 2. There are two reasons we don't immediately use the
- compiler built in stage 2, cc-lfs, to build those libraries.
-
-
-
-
- Generally speaking, cc-lfs cannot run on pc (the host system). Even though the
- triplets for pc and lfs are compatible with each other, an executable
- for lfs must depend on glibc-&glibc-version;; the host distro
- may utilize either a different implementation of libc (for example, musl), or
- a previous release of glibc (for example, glibc-2.13).
-
-
-
-
- Even if cc-lfs can run on pc, using it on pc would create
- a risk of linking to the pc libraries, since cc-lfs is a native
- compiler.
-
-
-
-
- So when we build gcc stage 2, we instruct the building system to
- rebuild libgcc and libstdc++ with cc1, but we link libstdc++ to the newly
+ during stage 2. As we've discussed, we cannot run cc-lfs on pc (the
+ host distro) because it may require some library, code, or data not
+ available on the build
(the host distro).
+ So when we build gcc stage 2, we override the library
+ search path to link libstdc++ against the newly
rebuilt libgcc instead of the old, degraded build. This makes the rebuilt
libstdc++ fully functional.
@@ -290,12 +373,11 @@
package on a completed LFS system, the reinstalled content of the package
should be the same as the content of the same package when first installed in
&ch-final;. The temporary packages installed in &ch-tmp-cross; or
- &ch-tmp-chroot; cannot satisfy this requirement, because some of them
- are built without optional dependencies, and autoconf cannot
- perform some feature checks in &ch-tmp-cross; because of cross-compilation,
- causing the temporary packages to lack optional features,
- or use suboptimal code routines. Additionally, a minor reason for
- rebuilding the packages is to run the test suites.
+ &ch-tmp-chroot; cannot satisfy this requirement, because some optional
+ features of them are disabled because of either the missing
+ dependencies or the cross-compilation mode.
+ Additionally, a minor reason for rebuilding the packages is to run the
+ test suites.
@@ -357,39 +439,25 @@ checking what linker to use... /mnt/lfs/tools/i686-lfs-linux-gnu/bin/ld
- Next comes glibc. The most important
- considerations for building glibc are the compiler, binary tools, and
- kernel headers. The compiler and binary tools are generally not an issue
- since glibc will always use those relating to the --host
- parameter passed to its configure script; e.g., in our case, the compiler
- will be $LFS_TGT-gcc and the readelf
- tool will be $LFS_TGT-readelf. The kernel headers can
- be a bit more complicated. Therefore, we take no risks and use
- the available configure switch to enforce the correct selection. After
- the run of configure, check the contents of the
- config.make file in the build directory for all important details.
- These items highlight an important aspect of the glibc
- package—it is very self-sufficient in terms of its build machinery,
- and generally does not rely on toolchain defaults.
+ Next comes glibc. This is the first package that we cross-compile.
+ We use the --host=$LFS_TGT option to make
+ the build system to use those tools prefixed with
+ $LFS_TGT-, and the
+ --build=$(../scripts/config.guess) option to
+ enable the cross-compilation mode
as we've discussed.
+ The DESTDIR variable is used to force installation into
+ the LFS file system.
As mentioned above, the standard C++ library is compiled next, followed in
by other programs that must
be cross-compiled to break circular dependencies at build time.
- The install step of all those packages uses the
- DESTDIR variable to force installation
- in the LFS filesystem.
+ The steps for those packages are similar to the steps for glibc.
At the end of the native
LFS compiler is installed. First binutils-pass2 is built,
in the same DESTDIR directory as the other programs,
then the second pass of gcc is constructed, omitting some
- non-critical libraries. Due to some weird logic in gcc's
- configure script, CC_FOR_TARGET ends up as
- cc when the host is the same as the target, but
- different from the build system. This is why
- CC_FOR_TARGET=$LFS_TGT-gcc is declared explicitly
- as one of the configuration options.
+ non-critical libraries.
Upon entering the chroot environment in ,