Configuración 1: compile su propia glibc sin GCC dedicado y utilícela
Sin estática también trabajando en: Múltiples bibliotecas glibc en un solo host
Esta configuración podría funcionar y es rápida, ya que no vuelve a compilar toda la cadena de herramientas de GCC, solo glibc.
Pero no es confiable ya que utiliza objetos de tiempo de ejecución del host C como crt1.o
, crti.o
y crtn.o
proporcionado por glibc. Esto se menciona en: https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_ubicación Esos objetos realizan una configuración temprana en la que se basa glibc, por lo que no me sorprendería si las cosas colapsaran de maneras maravillosas y asombrosamente sutiles.
Para una configuración más confiable, consulte la Configuración 2 a continuación.
Compile glibc e instálelo localmente:
export glibc_install="$(pwd)/glibc/build/install"
git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.28
mkdir build
cd build
../configure --prefix "$glibc_install"
make -j `nproc`
make install -j `nproc`
Configuración 1: verificar la compilación
prueba_glibc.c
#define _GNU_SOURCE
#include <assert.h>
#include <gnu/libc-version.h>
#include <stdatomic.h>
#include <stdio.h>
#include <threads.h>
atomic_int acnt;
int cnt;
int f(void* thr_data) {
for(int n = 0; n < 1000; ++n) {
++cnt;
++acnt;
}
return 0;
}
int main(int argc, char **argv) {
/* Basic library version check. */
printf("gnu_get_libc_version() = %s\n", gnu_get_libc_version());
/* Exercise thrd_create from -pthread,
* which is not present in glibc 2.27 in Ubuntu 18.04.
* https://stackoverflow.com/questions/56810/how-do-i-start-threads-in-plain-c/52453291#52453291 */
thrd_t thr[10];
for(int n = 0; n < 10; ++n)
thrd_create(&thr[n], f, NULL);
for(int n = 0; n < 10; ++n)
thrd_join(thr[n], NULL);
printf("The atomic counter is %u\n", acnt);
printf("The non-atomic counter is %u\n", cnt);
}
Compilar y ejecutar con test_glibc.sh
:
#!/usr/bin/env bash
set -eux
rm -rf tmp
mkdir tmp
gcc \
-L "${glibc_install}/lib" \
-I "${glibc_install}/include" \
-Wl,--rpath="${glibc_install}/lib" \
-Wl,--dynamic-linker="${glibc_install}/lib/ld-linux-x86-64.so.2" \
-static \
-std=c11 \
-o tmp/test_glibc.out \
-v \
test_glibc.c \
-pthread \
;
sudo chroot tmp /test_glibc.out
El programa genera lo esperado:
gnu_get_libc_version() = 2.28
The atomic counter is 10000
The non-atomic counter is 8674
a pesar de que lo ejecutamos en un chroot limpio, por lo que el -static
debe haber trabajado
Comando adaptado de https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_ubicación pero --sysroot
lo hizo fallar con:
cannot find /home/ciro/glibc/build/install/lib/libc.so.6 inside /home/ciro/glibc/build/install
así que lo eliminé.
ldd
salida confirma que el ldd
y las bibliotecas que acabamos de crear se están usando como se esperaba:
+ ldd test_glibc.out
linux-vdso.so.1 (0x00007ffe4bfd3000)
libpthread.so.0 => /home/ciro/glibc/build/install/lib/libpthread.so.0 (0x00007fc12ed92000)
libc.so.6 => /home/ciro/glibc/build/install/lib/libc.so.6 (0x00007fc12e9dc000)
/home/ciro/glibc/build/install/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007fc12f1b3000)
los gcc
La salida de depuración de compilación muestra que se usaron los objetos de tiempo de ejecución de mi host, lo cual es malo como se mencionó anteriormente, pero no sé cómo solucionarlo, por ejemplo, contiene:
COLLECT_GCC_OPTIONS=/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crt1.o
Configuración 1: modificar glibc
Ahora vamos a modificar glibc con:
diff --git a/nptl/thrd_create.c b/nptl/thrd_create.c
index 113ba0d93e..b00f088abb 100644
--- a/nptl/thrd_create.c
+++ b/nptl/thrd_create.c
@@ -16,11 +16,14 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#include <stdio.h>
+
#include "thrd_priv.h"
int
thrd_create (thrd_t *thr, thrd_start_t func, void *arg)
{
+ puts("hacked");
_Static_assert (sizeof (thr) == sizeof (pthread_t),
"sizeof (thr) != sizeof (pthread_t)");
Luego vuelva a compilar y reinstalar glibc, y vuelva a compilar y vuelva a ejecutar nuestro programa:
cd glibc/build
make -j `nproc`
make -j `nproc` install
./test_glibc.sh
y vemos hacked
impreso un par de veces como se esperaba.
Esto confirma aún más que en realidad usamos la glibc que compilamos y no la del host.
Probado en Ubuntu 18.04.
Configuración 2: configuración impecable crosstool-NG
Esta es una alternativa a la configuración 1, y es la configuración más correcta que he logrado hasta ahora: todo es correcto por lo que puedo observar, incluidos los objetos de tiempo de ejecución de C como crt1.o
, crti.o
y crtn.o
.
En esta configuración, compilaremos una cadena de herramientas GCC completa y dedicada que usa la glibc que queremos.
El único inconveniente de este método es que la compilación llevará más tiempo. Pero no arriesgaría una configuración de producción con nada menos.
crosstool-NG es un conjunto de scripts que descarga y compila todo desde la fuente para nosotros, incluidos GCC, glibc y binutils.
Sí, el sistema de construcción de GCC es tan malo que necesitamos un proyecto separado para eso.
Esta configuración solo no es perfecta porque crosstool-NG no admite la creación de ejecutables sin extra -Wl
banderas, lo cual se siente extraño ya que hemos creado GCC. Pero todo parece funcionar, por lo que esto es solo un inconveniente.
Obtenga crosstool-NG y configúrelo:
git clone https://github.com/crosstool-ng/crosstool-ng
cd crosstool-ng
git checkout a6580b8e8b55345a5a342b5bd96e42c83e640ac5
export CT_PREFIX="$(pwd)/.build/install"
export PATH="/usr/lib/ccache:${PATH}"
./bootstrap
./configure --enable-local
make -j `nproc`
./ct-ng x86_64-unknown-linux-gnu
./ct-ng menuconfig
La única opción obligatoria que puedo ver es hacer que coincida con la versión del kernel de su host para usar los encabezados del kernel correctos. Encuentre la versión del kernel de su host con:
uname -a
que me muestra:
4.15.0-34-generic
así que en menuconfig
Hago:
así que selecciono:
4.14.71
que es la primera versión igual o anterior. Tiene que ser más antiguo ya que el núcleo es compatible con versiones anteriores.
Ahora puedes construir con:
env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`
y ahora espere entre treinta minutos y dos horas para la compilación.
Configuración 2: configuraciones opcionales
los .config
que generamos con ./ct-ng x86_64-unknown-linux-gnu
posee:
CT_GLIBC_V_2_27=y
Para cambiar eso, en menuconfig
hacer:
C-library
Version of glibc
salva el .config
y continuar con la compilación.
O, si desea usar su propia fuente de glibc, por ejemplo, para usar glibc de la última versión de git, proceda Me gusta esto:
Paths and misc options
Try features marked as EXPERIMENTAL
: establecido en verdadero
C-library
Source of glibc
Custom location
: decir que sí
Custom location
Custom source location
: apunta a un directorio que contiene su fuente glibc
donde glibc fue clonado como:
git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.28
Configuración 2: pruébalo
Una vez que haya creado la cadena de herramientas que desea, pruébela con:
#!/usr/bin/env bash
set -eux
install_dir="${CT_PREFIX}/x86_64-unknown-linux-gnu"
rm -rf tmp
mkdir tmp
PATH="${PATH}:${install_dir}/bin" \
x86_64-unknown-linux-gnu-gcc \
-Wl,--dynamic-linker="${install_dir}/x86_64-unknown-linux-gnu/sysroot/lib/ld-linux-x86-64.so.2" \
-Wl,--rpath="${install_dir}/x86_64-unknown-linux-gnu/sysroot/lib" \
-static \
-v \
-o tmp/test_glibc.out \
test_glibc.c \
-pthread \
;
sudo chroot tmp /test_glibc.out
Todo parece funcionar como en la Configuración 1, excepto que ahora se usaron los objetos de tiempo de ejecución correctos:
COLLECT_GCC_OPTIONS=/home/ciro/crosstool-ng/.build/install/x86_64-unknown-linux-gnu/bin/../x86_64-unknown-linux-gnu/sysroot/usr/lib/../lib64/crt1.o
Configuración 2: intento fallido de recompilación eficiente de glibc
No parece posible con crosstool-NG, como se explica a continuación.
Si solo reconstruyes;
env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`
luego se tienen en cuenta los cambios en la ubicación de origen de la glibc personalizada, pero construye todo desde cero, lo que lo hace inutilizable para el desarrollo iterativo.
Si hacemos:
./ct-ng list-steps
da una buena visión general de los pasos de compilación:
Available build steps, in order:
- companion_tools_for_build
- companion_libs_for_build
- binutils_for_build
- companion_tools_for_host
- companion_libs_for_host
- binutils_for_host
- cc_core_pass_1
- kernel_headers
- libc_start_files
- cc_core_pass_2
- libc
- cc_for_build
- cc_for_host
- libc_post_cc
- companion_libs_for_target
- binutils_for_target
- debug
- test_suite
- finish
Use "<step>" as action to execute only that step.
Use "+<step>" as action to execute up to that step.
Use "<step>+" as action to execute from that step onward.
por lo tanto, vemos que hay pasos glibc entrelazados con varios pasos GCC, más notablemente libc_start_files
viene antes cc_core_pass_2
que es probablemente el paso más caro junto con cc_core_pass_1
.
Para construir solo un paso, primero debe configurar “Guardar pasos intermedios” en .config
opción para la compilación inicial:
y luego puedes probar:
env -u LD_LIBRARY_PATH time ./ct-ng libc+ -j`nproc`
pero desafortunadamente, el +
requerido como se menciona en: https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536
Sin embargo, tenga en cuenta que reiniciar en un paso intermedio restablece el directorio de instalación al estado que tenía durante ese paso. Es decir, tendrá una libc reconstruida, pero no un compilador final creado con esta libc (y, por lo tanto, tampoco bibliotecas de compilación como libstdc++).
y básicamente todavía hace que la reconstrucción sea demasiado lenta para que sea factible para el desarrollo, y no veo cómo superar esto sin parchear crosstool-NG.
Además, a partir de la libc
paso no parecía copiar la fuente de nuevo desde Custom source location
lo que hace que este método quede inutilizable.
Bono: stdlibc++
Una ventaja adicional si también está interesado en la biblioteca estándar de C ++: ¿Cómo editar y reconstruir la fuente de la biblioteca estándar GCC libstdc ++ C ++?
GCC depende en gran medida de las funciones internas que tiene Glibc. Tendrá que reconstruir una versión anterior de GCC para no esperar estas funciones internas. Esto no va a ser pan comido…
– usuario529758
26 de mayo de 2012 a las 3:40
No entiendo por qué necesitaría una versión anterior de GCC. La glibc que construí es la penúltima versión más reciente, 2.14. (Tuve problemas de compilación con 2.15 en mi sistema Ubuntu debido a problemas conocidos que no pude resolver con las soluciones alternativas recomendadas).
– Amittai Aviram
26 mayo 2012 a las 20:16
La versión de GCC no debe estar relacionada. Se supone que los símbolos que GCC no puede encontrar están definidos en
libc.a
así que si faltan, tal vezlibc.a
fue mal compilado ..?– R.. GitHub DEJA DE AYUDAR A ICE
27 de mayo de 2012 a las 0:21
Las versiones de GCC no tienen nada que ver con este problema. Consulte mi solución publicada a continuación (segunda respuesta).
– Amittai Aviram
27 de mayo de 2012 a las 6:18