# Linux Kernel Dev Blog 8 - Linux From Scratch (LFS) Compiling ## 4/7/2020 ## determine target triplet and dynamic linker > Before continuing, be aware of the name of the working platform, often referred to as the target triplet. Unpack the bin utils and run the `config.guess` script ```shell $ tar -xf binutils-2.34.tar.xz $ bash binutils-2.34/config.guess x86_64-pc-linux-gnu ``` `x86_64-pc-linux-gnu` is target triplet (which is different than our LFS_TGT which is `x86_64-lfs-linux-gnu` for some reason?) We also need to determine the Dynamic Linker used by host Glibc that finds and loads shared libraries of a program > A sure-fire way to determine the name of the dynamic linker is to inspect a random binary from the host system by running: readelf -l | grep interpreter and noting the output ELF - format of Executable and Linking Format (ELF) files > An executable file using the ELF file format consists of an ELF header, followed by a program header table or a section header table, or both. With `readelf` we can look at a compiled library to determine the dynamic linker used ```shell $ readelf -a /usr/bin/x86_64-linux-gnu-cpp-7 | grep interpreter [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] ``` Looks like the dynamic linker is `/lib64/ld-linux-x86-64.so.2` ? ## cross compiling The act of compiling code on one host for another target architecture We will adjust the source of gcc to cross compile to our target architecture (which is the same as our current architecture?) Double checking requirements: - lfs is the user - source is in /mnt/lfs/source - bash is the shell in use - /bin/sh points to bash - /usr/bin/awk is a symbolic link to gawk - /usr/bin/yacc is a symbolic link to bison For each package: - Using the tar program, extract the package to be built. In Chapter 5, ensure you are the lfs user when extracting the package. - Change to the directory created when the package was extracted. - Follow the book's instructions for building the package. - Change back to the sources directory. - Delete the extracted source directory unless instructed otherwise. ### Installation of Cross Binutils ```shell $ tar -xf binutils-2.34.tar.xz $ cd binutils-2.34 $ mkdir build $ cd build $ ../configure --prefix=/tools \ --with-sysroot=$LFS \ --with-lib-path=/tools/lib \ --target=$LFS_TGT \ --disable-nls \ --disable-werror $ time { make -j2; } # this will create our SBU to estimate build times ``` It took `2m26.212s` to build the binutils > If building on x86_64, create a symlink to ensure the sanity of the toolchain ```shell $ mkdir -v /tools/lib && ln -sv lib /tools/lib64 $ make -j2 install # took 3 seconds $ ls -l /tools/ total 16 drwxr-xr-x 2 lfs lfs 4096 Apr 7 18:52 bin drwxr-xr-x 2 lfs lfs 4096 Apr 7 18:52 lib lrwxrwxrwx 1 lfs lfs 3 Apr 7 18:52 lib64 -> lib drwxr-xr-x 4 lfs lfs 4096 Apr 7 18:52 share drwxr-xr-x 4 lfs lfs 4096 Apr 7 18:52 x86_64-lfs-linux-gnu ``` ### Installation of Cross GCC ```shell $ tar -xf gcc-9.2.0.tar.xz $ cd gcc-9.2.0 ``` GCC requires three other packages we downloaded: GMP, MPFR and MPC ```shell $ tar -xf ../mpfr-4.0.2.tar.xz; mv -v mpfr-4.0.2 mpfr $ tar -xf ../gmp-6.2.0.tar.xz; mv -v gmp-6.2.0 gmp $ tar -xf ../mpc-1.1.0.tar.gz; mv -v mpc-1.1.0 mpc ``` This command will change GCC's default linker to use the one we installed in /tools (/mnt/lfs/tools) and removes /usr/include from GCCs search path ```shell for file in gcc/config/{linux,i386/linux{,64}}.h do cp -uv $file{,.orig} sed -e 's@/lib\(64\)\?\(32\)\?/ld@/tools&@g' \ -e 's@/usr@/tools@g' $file.orig > $file echo ' #undef STANDARD_STARTFILE_PREFIX_1 #undef STANDARD_STARTFILE_PREFIX_2 #define STANDARD_STARTFILE_PREFIX_1 "/tools/lib/" #define STANDARD_STARTFILE_PREFIX_2 ""' >> $file touch $file.orig done ``` output ``` 'gcc/config/linux.h' -> 'gcc/config/linux.h.orig' 'gcc/config/i386/linux.h' -> 'gcc/config/i386/linux.h.orig' 'gcc/config/i386/linux64.h' -> 'gcc/config/i386/linux64.h.orig' ``` For x86_64 we need to change the 64 bit libs to "lib" ```shell case $(uname -m) in x86_64) sed -e '/m64=/s/lib64/lib/' \ -i.orig gcc/config/i386/t-linux64 ;; esac ``` HOLD ON TO YOUR BUTTS ```shell $ mkdir -v build $ cd build $ ../configure \ --target=$LFS_TGT \ --prefix=/tools \ --with-glibc-version=2.11 \ --with-sysroot=$LFS \ --with-newlib \ --without-headers \ --with-local-prefix=/tools \ --with-native-system-header-dir=/tools/include \ --disable-nls \ # make sure we dont link to host libs --disable-shared \ --disable-multilib \ # most of this stuff wont cross compile and we dont need it --disable-decimal-float \ --disable-threads \ --disable-libatomic \ --disable-libgomp \ --disable-libquadmath \ --disable-libssp \ --disable-libvtv \ --disable-libstdcxx \ --enable-languages=c,c++ $ make -j2 # eta 20-30 minutes $ make install ``` ### linux-5.5.3 To expose Application Programming Interface (API) for the system's C library for the Linux Kernel ```shell $ make mrproper $ make headers $ cp -rv usr/include/* /tools/include ``` ### Glibc-2.31 The Glibc package contains the main C library for allocating memory, searching directories, opening and closing files, reading and writing files, string handling, pattern matching, arithmetic, and so on ```shell $ mkdir build; cd build $ ../configure \ --prefix=/tools \ --host=$LFS_TGT \ --build=$(../scripts/config.guess) \ --enable-kernel=3.2 \ # make sure it uses our headers we just brought in from the linux API headers for GCC before --with-headers=/tools/include $ make -j2 $ make install ``` Test our compiler and linker ```shell $ echo 'int main(){}' > dummy.c $ $LFS_TGT-gcc dummy.c $ readelf -l a.out | grep ': /tools' [Requesting program interpreter: /tools/lib64/ld-linux-x86-64.so.2] ``` In good working order... ### Libstdc++ from GCC-9.2.0 Its in GCC but has not been compiled yet, apparently part of GCC is written in C++ ```shell $ cd /mnt/lfs/sources/gcc-9.2.0/ $ mkdir build; cd build # alread existed from previous build $ ../libstdc++-v3/configure \ --host=$LFS_TGT \ --prefix=/tools \ --disable-multilib \ --disable-nls \ --disable-libstdcxx-threads \ --disable-libstdcxx-pch \ --with-gxx-include-dir=/tools/$LFS_TGT/include/c++/9.2.0 $ make -j2 $ make install ``` ?? I think make recognizes that now C++ is now included and configured so it builds it into the compiler too? !! This I think was a problem, revisiting the technical notes I was supposed to delete the entire source directory after each build so on round 2 for this I should have compiled it differently I started over and killed and rebuilt this ### Binutils-2.34 - Pass 2 ```shell mkdir -v build cd build CC=$LFS_TGT-gcc \ AR=$LFS_TGT-ar \ RANLIB=$LFS_TGT-ranlib \ ../configure \ --prefix=/tools \ --disable-nls \ --disable-werror \ --with-lib-path=/tools/lib \ --with-sysroot make -j2 make install make -C ld clean make -C ld LIB_PATH=/usr/lib:/lib cp -v ld/ld-new /tools/bin ``` ### GCC-9.2.0 - Pass 2 in `/mnt/lfs/sources/gcc-9.2.0` ```shell cat gcc/limitx.h gcc/glimits.h gcc/limity.h > \ `dirname $($LFS_TGT-gcc -print-libgcc-file-name)`/include-fixed/limits.h for file in gcc/config/{linux,i386/linux{,64}}.h do cp -uv $file{,.orig} sed -e 's@/lib\(64\)\?\(32\)\?/ld@/tools&@g' \ -e 's@/usr@/tools@g' $file.orig > $file echo ' #undef STANDARD_STARTFILE_PREFIX_1 #undef STANDARD_STARTFILE_PREFIX_2 #define STANDARD_STARTFILE_PREFIX_1 "/tools/lib/" #define STANDARD_STARTFILE_PREFIX_2 ""' >> $file touch $file.orig done case $(uname -m) in x86_64) sed -e '/m64=/s/lib64/lib/' \ -i.orig gcc/config/i386/t-linux64 ;; esac tar -xf ../mpfr-4.0.2.tar.xz mv -v mpfr-4.0.2 mpfr tar -xf ../gmp-6.2.0.tar.xz mv -v gmp-6.2.0 gmp tar -xf ../mpc-1.1.0.tar.gz mv -v mpc-1.1.0 mpc sed -e '1161 s|^|//|' \ -i libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc mkdir -v build cd build CC=$LFS_TGT-gcc \ CXX=$LFS_TGT-g++ \ AR=$LFS_TGT-ar \ RANLIB=$LFS_TGT-ranlib \ ../configure \ --prefix=/tools \ --with-local-prefix=/tools \ --with-native-system-header-dir=/tools/include \ --enable-languages=c,c++ \ --disable-libstdcxx-pch \ --disable-multilib \ --disable-bootstrap \ --disable-libgomp make -j2 make install ln -sv gcc /tools/bin/cc # test echo 'int main(){}' > dummy.c cc dummy.c readelf -l a.out | grep ': /tools' # /tools/lib64/ld-linux-x86-64.so.2 rm -v dummy.c a.out ```