Linux From Scratch IV: Empezamos a compilar

Sigo con mi serie de posts dedicados a instalar Linux From Scratch. En mi anterior artículo deje todo listo para empezar a compilar ahora. En este, compilaré los primeros paquetes del sistema temporal. Algunos de ellos hay que compilarlos en dos pasos. El primero de todos es binutils. Pero antes de empezar a compilar voy a hacer un último ajuste. Como mi equipo tiene 4 CPUs (virtualmente, en realidad son dos cores hyper-threading) voy a hacer que los aproveche. Para esto, tengo que añadir la variable MAKEFLAGS al .bashrc para que el comando make la use. En esta variable pondré los parámetros que quiero que make utilice al compilar. El parámetro -j me permite indicar el número de hilos que quiero que lance. Lo ideal es poner una unidad más que el número de CPUs que tengo. En mi caso sería así:

[lfs@corellia ~]$ echo 'export MAKEFLAGS=-j5' >> ~/.bashrc
[lfs@corellia ~]$ source ~/.bashrc

Compilando binutils (paso 1)

Con esta linea en el .bashrc, este usuario hará todas las compilaciones con 5 hilos. Ahora ya puedo descomprimir el código fuente de binutils, que me descargué hace dos artículos y aplicar los parches correspondientes.

[lfs@corellia ~]$ cd $LFS/sources
[lfs@corellia sources]$ tar xvjf binutils-2.22.tar.bz2 
binutils-2.22/bfd/.gitignore
binutils-2.22/bfd/acinclude.m4
binutils-2.22/bfd/aclocal.m4
binutils-2.22/bfd/aix386-core.c
binutils-2.22/bfd/aix5ppc-core.c
binutils-2.22/bfd/aout-adobe.c

...

binutils-2.22/README-maintainer-mode
binutils-2.22/setup.com
binutils-2.22/src-release
binutils-2.22/symlink-tree
binutils-2.22/texinfo/texinfo.tex
binutils-2.22/ylwrap
[lfs@corellia sources]$ cd binutils-2.22
[lfs@corellia binutils-2.22]$ patch -Np1 -i ../binutils-2.22-build_fix-1.patch
patching file opcodes/ChangeLog
patching file opcodes/i386-dis.c

Por lo visto, la documentación de binutils recomienda compilar en un directorio aparte del árbol de código fuente, así que creo un directorio binutils-build tal como recomienda el libro y me meto en él.

[lfs@corellia binutils-2.22]$ mkdir -v ../binutils-build
mkdir: created directory '../binutils-build'
[lfs@corellia binutils-2.22]$ cd ../binutils-build
[lfs@corellia binutils-build]$

En un sistema de 64 bits como el que estoy compilando, necesito que las librerías sean accesibles tanto a través del directorio lib como de lib64, así que hay que crear un enlace de uno a otro. Esto va a ser así en el sistema temporal. Cuando ya esté todo funcionando definitivamente, cada directorio tendrá las librerías del bitness que le corresponda, pero de momento, creamos el directorio y el correspondiente enlace.

[lfs@corellia binutils-build]$ mkdir -v /tools/lib && ln -sv lib /tools/lib64
mkdir: created directory '/tools/lib'
'/tools/lib64' -> 'lib'

Y por fin podemos compilar. Como es la primera compilación de binutils, lanzo todo el proceso de compilación con time para ver cuánto tarda. El valor que me dé aquí será el SBU del que os hablé en el artículo anterior, que me servirá para estimar lo que van a tardar el resto de las compilaciones.

[lfs@corellia binutils-build]$ time {
> ../binutils-2.22/configure     \
>     --prefix=/tools            \
>     --with-sysroot=$LFS        \
>     --with-lib-path=/tools/lib \
>     --target=$LFS_TGT          \
>     --disable-nls              \
>     --disable-werror &&
> make &&
> make install
> }
checking for C compiler default output file name... a.out
checking whether the C compiler works... yes
checking whether we are cross compiling... no
checking for suffix of executables... 
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
...

done
make[5]: Leaving directory `/mnt/lfs/sources/binutils-build/binutils'
make[4]: Leaving directory `/mnt/lfs/sources/binutils-build/binutils'
make[3]: Leaving directory `/mnt/lfs/sources/binutils-build/binutils'
make[2]: Leaving directory `/mnt/lfs/sources/binutils-build/binutils'
make[1]: Leaving directory `/mnt/lfs/sources/binutils-build'

real    1m35.573s
user    1m53.353s
sys     0m13.936s

De todas las opciones que le he pasado a configure, es destacable --prefix=/tools, que sirve para que los ficheros queden instalados en /tools, que es lo que queríamos cuando creamos ese directorio. También son destacables --with-sysroot=$LFS, que indica cuál es el directorio raíz a partir del cual se van a buscar las librerías en tiempo de compilación y --with-lib-path=/tools/lib que le indica al linkador en qué directorio buscar las librerías al ejecutar los programas compilados.

Otra opción importante es --target=$LFS_TGT. que sirve para dar un nombre para el sistema que estamos generando. Al fin y al cabo, lo que estamos haciendo con este sistema temporal es generar un compilador cruzado que sea capaz de compilar los paquetes independientemente de lo que haya en la máquina. La opción –target coloca un prefijo en los nombres de todos los binarios para que sea posible instalar en la misma máquina compiladores para varias arquitecturas. Así funciona la compilación cruzada.

Viendo el tiempo que ha tardado en compilar, el SBU para mi sistema es, aproximadamente, 1 minuto 35 segundos. De todos modos, como esto no es muy fiable, he repetido la prueba 9 veces y he hecho la media de los resultados. El valor que me da es 1 minuto 19 segundos. Utilizaré este valor para calcular los tiempos.

Ahora habría que borrar todo el código fuente descomprimido e ir a por el siguiente paquete, pero como hay que volver a compilar binutils en un segundo paso, lo voy a dejar descomprimido para tenerlo ya. Me limito a borrar el contenido de binutils-build, que sí que no necesito conservarlo.

[lfs@corellia binutils-build]$ rm -rf *
[lfs@corellia binutils-build]$ cd ..
[lfs@corellia sources]$

Todo listo para compilar el siguiente paquete, que es nada menos que el gcc.

Compilando gcc (paso 1)

Lo primero de todo es descomprimir el paquete y entrar en el directorio que genera. También hay que descomprimir gmp, mpfr y mpc en el directorio del código fuente de gcc para que los utilice al compilar en lugar de los que están instalados en el sistema. Esto es, como todo este entorno temporal, para evitar que la configuración del sistema afecte a la compilación. Estos tres paquetes son librerías para cálculos de precisión multiple en coma flotante y con números complejos. No sé por qué gcc necesita esto. 🙂

[lfs@corellia sources]$ tar xvjf gcc-4.7.1.tar.bz2

...

gcc-4.7.1/gcc/target-hooks-macros.h
gcc-4.7.1/gcc/tree-ssa-phiprop.c
gcc-4.7.1/gcc/gsstruct.def
gcc-4.7.1/gcc/combine.c
gcc-4.7.1/gcc/input.h
gcc-4.7.1/ltsugar.m4
[lfs@corellia sources]$ cd gcc-4.7.1
[lfs@corellia gcc-4.7.1]$ tar -Jxf ../mpfr-3.1.1.tar.xz
[lfs@corellia gcc-4.7.1]$ mv -v mpfr-3.1.1 mpfr
'mpfr-3.1.1' -> 'mpfr'
[lfs@corellia gcc-4.7.1]$ tar -Jxf ../gmp-5.0.5.tar.xz
[lfs@corellia gcc-4.7.1]$ mv -v gmp-5.0.5 gmp
'gmp-5.0.5' -> 'gmp'
[lfs@corellia gcc-4.7.1]$ tar -zxf ../mpc-1.0.tar.gz
[lfs@corellia gcc-4.7.1]$ mv -v mpc-1.0 mpc
'mpc-1.0' -> 'mpc'
[lfs@corellia gcc-4.7.1]$

El siguiente paso que da el libro es modificar el código fuente del gcc para que busque las librerías en /tools. Se ve que no tiene una opción para esto. Lo bonito es que lo hace con un comando.

[lfs@corellia gcc-4.7.1]$ for file in \
>  $(find gcc/config -name linux64.h -o -name linux.h -o -name sysv4.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
'gcc/config/rs6000/linux64.h' -> 'gcc/config/rs6000/linux64.h.orig'
'gcc/config/rs6000/linux.h' -> 'gcc/config/rs6000/linux.h.orig'
'gcc/config/rs6000/sysv4.h' -> 'gcc/config/rs6000/sysv4.h.orig'
'gcc/config/m68k/linux.h' -> 'gcc/config/m68k/linux.h.orig'
'gcc/config/mips/linux64.h' -> 'gcc/config/mips/linux64.h.orig'
'gcc/config/mips/linux.h' -> 'gcc/config/mips/linux.h.orig'
'gcc/config/alpha/linux.h' -> 'gcc/config/alpha/linux.h.orig'
'gcc/config/frv/linux.h' -> 'gcc/config/frv/linux.h.orig'
'gcc/config/tilepro/linux.h' -> 'gcc/config/tilepro/linux.h.orig'
'gcc/config/mn10300/linux.h' -> 'gcc/config/mn10300/linux.h.orig'
'gcc/config/i386/linux64.h' -> 'gcc/config/i386/linux64.h.orig'
'gcc/config/i386/linux.h' -> 'gcc/config/i386/linux.h.orig'
'gcc/config/i386/sysv4.h' -> 'gcc/config/i386/sysv4.h.orig'
'gcc/config/linux.h' -> 'gcc/config/linux.h.orig'
'gcc/config/microblaze/linux.h' -> 'gcc/config/microblaze/linux.h.orig'
'gcc/config/sh/linux.h' -> 'gcc/config/sh/linux.h.orig'
'gcc/config/tilegx/linux.h' -> 'gcc/config/tilegx/linux.h.orig'
'gcc/config/m32r/linux.h' -> 'gcc/config/m32r/linux.h.orig'
'gcc/config/ia64/linux.h' -> 'gcc/config/ia64/linux.h.orig'
'gcc/config/ia64/sysv4.h' -> 'gcc/config/ia64/sysv4.h.orig'
'gcc/config/cris/linux.h' -> 'gcc/config/cris/linux.h.orig'
'gcc/config/xtensa/linux.h' -> 'gcc/config/xtensa/linux.h.orig'
'gcc/config/s390/linux.h' -> 'gcc/config/s390/linux.h.orig'
'gcc/config/bfin/linux.h' -> 'gcc/config/bfin/linux.h.orig'
'gcc/config/sparc/linux64.h' -> 'gcc/config/sparc/linux64.h.orig'
'gcc/config/sparc/linux.h' -> 'gcc/config/sparc/linux.h.orig'
'gcc/config/sparc/sysv4.h' -> 'gcc/config/sparc/sysv4.h.orig'
'gcc/config/vax/linux.h' -> 'gcc/config/vax/linux.h.orig'
[lfs@corellia gcc-4.7.1]$

El comando modifica los ficheros necesarios para todas las arquitecturas buscándolos recursivamente con find, reemplazando las rutas con sed y, luego, les añade algunas directivas de preprocesador simplemente con echo.

Otra corrección que aplica el libro es un pequeño parche para que no dé problemas al compilar glibc.

[lfs@corellia gcc-4.7.1]$ sed -i '/k prot/agcc_cv_libc_provides_ssp=yes' gcc/configure
[lfs@corellia gcc-4.7.1]$

Después de esto ya podemos crear un directorio para hacer la compilación y compilar gcc.

[lfs@corellia gcc-4.7.1]$ mkdir -v ../gcc-build
mkdir: created directory '../gcc-build'
[lfs@corellia gcc-4.7.1]$ cd ../gcc-build
[lfs@corellia gcc-build]$ ../gcc-4.7.1/configure         \
>     --target=$LFS_TGT          \
>     --prefix=/tools            \
>     --with-sysroot=$LFS        \
>     --with-newlib              \
>     --without-headers          \
>     --with-local-prefix=/tools \
>     --with-native-system-header-dir=/tools/include \
>     --disable-nls              \
>     --disable-shared           \
>     --disable-multilib         \
>     --disable-decimal-float    \
>     --disable-threads          \
>     --disable-libmudflap       \
>     --disable-libssp           \
>     --disable-libgomp          \
>     --disable-libquadmath      \
>     --enable-languages=c       \
>     --with-mpfr-include=$(pwd)/../gcc-4.7.1/mpfr/src \
>     --with-mpfr-lib=$(pwd)/mpfr/src/.libs
checking build system type... x86_64-unknown-linux-gnu
checking host system type... x86_64-unknown-linux-gnu
checking target system type... x86_64-lfs-linux-gnu
checking for a BSD-compatible install... /usr/bin/install -c
checking whether ln works... yes

...

[lfs@corellia gcc-build]$ make

...
    *.a)                        \
      /tools/x86_64-lfs-linux-gnu/bin/ranlib ../.././gcc/$file ;;    \
  esac;                            \
done
make[3]: Leaving directory `/mnt/lfs/sources/gcc-build/x86_64-lfs-linux-gnu/libgcc'
make[2]: Leaving directory `/mnt/lfs/sources/gcc-build/x86_64-lfs-linux-gnu/libgcc'
make[1]: Leaving directory `/mnt/lfs/sources/gcc-build'
[lfs@corellia gcc-build]$ make install
...

/usr/bin/install -c -m 644 ../../gcc-4.7.1/gcc/vecir.h /tools/lib/gcc/x86_64-lfs-linux-gnu/4.7.1/plugin/include/vecir.h
/usr/bin/install -c -m 644 ../../gcc-4.7.1/gcc/vecprim.h /tools/lib/gcc/x86_64-lfs-linux-gnu/4.7.1/plugin/include/vecprim.h
/usr/bin/install -c -m 644 ../../gcc-4.7.1/gcc/version.h /tools/lib/gcc/x86_64-lfs-linux-gnu/4.7.1/plugin/include/version.h
/usr/bin/install -c -m 644 b-header-vars /tools/lib/gcc/x86_64-lfs-linux-gnu/4.7.1/plugin/include/b-header-vars
make[2]: Leaving directory `/mnt/lfs/sources/gcc-build/gcc'
make[1]: Leaving directory `/mnt/lfs/sources/gcc-build'
[lfs@corellia gcc-build]$

Aunque no lo he puesto en los comandos, he medido los tiempos y ha tardado en total 7 minutos 14 segundos. Según el libro esta compilación tarda 5.5 SBU, o sea unos 7 minutos 18 segundos. Parece que la precisión del cálculo no está mal para hacerse una idea. Y los tiempos son aceptables. No parece que me vaya a eternizar compilando.

En cuanto a las opciones usadas en el configure, muchas son similares a las de binutils. De las demás, --with-local-prefix=/tools sirve para que el compilador busque los ficheros include instalados localmente en /tools en vez de en /usr/local. La opción --with-native-system-header-dir=/tools/include sirve para que busque los ficheros include del sistema en /tools/include, ya que es ahí donde los vamos a dejar más adelante. Las demás opciones son para desactivar características del compilador que no vamos a necesitar en el sistema temporal. Por ejemplo, para generar el compilador sin usar la glibc ni los headers, para que el compilador que estamos generando no use aritmética de punto flotante, multitarea, multilib y para que el único lenguaje que genere sea C, ya que de momento sólo vamos a necesitar ese.

El último paso para terminar esta compilación del gcc es crear un enlace a la librería libgcc.a para que la use en lugar de libgcc_eh.a, ya que con la opción --disable-shared los símbolos que deberían estar en libgcc_eh.a, se colocan en libgcc.a.

[lfs@corellia gcc-build]$ ln -vs libgcc.a `$LFS_TGT-gcc -print-libgcc-file-name | sed 's/libgcc/&_eh/'`
'/mnt/lfs/tools/bin/../lib/gcc/x86_64-lfs-linux-gnu/4.7.1/libgcc_eh.a' -> 'libgcc.a'

Como todavía hay que hacer un segundo paso de compilación, voy a dejar el código fuente descomprimido igual que hice con binutils. Borraré solamente el contenido del directorio gcc-build, que sólo son ficheros temporales que se generan durante la compilación y ya no son necesarios para nada.

[lfs@corellia gcc-build]$ rm -rf *
[lfs@corellia gcc-build]$

Bueno, ya he compilado el compilador. 🙂 Con esto termino por hoy. En el siguiente post seguiré compilando más paquetes. Faltan todavía unos cuantos sólo para tener el sistema temporal listo.

EOF

Anuncios

8 pensamientos en “Linux From Scratch IV: Empezamos a compilar

  1. Damian Rivera

    Impresionante compilar el compilador solo usando la sintaxis de la shell y $PS2 para escribir bucles y varias lineas O_O

    Que bueno que no se haya eternizado la compilación ya que yo estoy traumado con eso, como comentaba, y fue en FreeBSD no Gentoo(me confundí),en gentoo ya trae nano creo(no recuerdo uso ee).

    Muy buena entrada 😀

    1. hexborg Autor de la entrada

      La shell de linux es todopoderosa. Se puede hacer cualquier cosa con ella. 🙂

      La verdad es que no tengo mucho miedo de lo que pueda tardar la compilación. Es cuestión de dejarlo funcionando hasta que termine, Tengo paciencia. 🙂

      Gracias por tu comentario.

  2. Damian Rivera

    Listo 😀

    Compile binutils en :

    real 10m21.490s
    user 7m8.702s
    sys 0m51.457s

    Mi maquina es lenta,pero lo hice desde un usb y voy a ver si consigo una mas potente,o haber hasta donde llego con esta 😀

    Saludos

    1. hexborg Autor de la entrada

      La verdad es que 10 minutos es bastante. De todos modos, es cuestión de tener paciencia y dejarlo compilando. Ánimo con ello. 🙂

    1. hexborg Autor de la entrada

      Es el gcc, pero en el segundo paso. Tarda 7.1 SBU, o sea que creo que te tardará alrededor de una hora y cuarto. Después de ese, los demás paquetes no tardan nada.

Los comentarios están cerrados.