Zuletzt getestet auf Ubuntu 20.04 mit glibc-Entwicklungsversion 2.33.9000 (siehe glibc/version.h
) am 27. Juni 2021.
Wie man glibc herunterlädt und baut und seine Benchmarks ausführt
Sie können den Glibc-Quellcode hier manuell abrufen:https://www.gnu.org/software/libc/sources.html:
git clone https://sourceware.org/git/glibc.git
cd glibc
git checkout master
Drittanbieter-Mirror auf GitHub:https://github.com/bminor/glibc/tree/master/benchtests
Siehe auch:
- https://kazoo.ga/a-simple-tool-to-test-malloc-performance/
Wenn Sie jemals glibc und seine Benchtests manuell erstellen möchten, tun Sie dies wie folgt:
# IMPORTANT: begin AT THE SAME DIRECTORY LEVEL as the `glibc` source code
# directory, NOT inside the `glibc` source code dir! In other words, if
# you are in the correct dir, running `ls` will show the `glibc` source
# code dir (that you just cloned) inside the dir you are in.
mkdir -p glibc-build
mkdir -p glibc-install
cd glibc-build
../glibc/configure --prefix="$(realpath "../glibc-install")"
time make -j8 # build with 8 threads (jobs); on a fast laptop this takes ~3 min.
time make install # (optional: install to the `glibc-install` dir you created)
# Build the benchtests (everything inside the `glibc/benchtests` dir) too;
# see the makefile 'glibc/benchtests/Makefile' for more build commands.
time make bench-build -j8
# Now you have this executable file you can use for malloc speed tests, for instance!:
# ../glibc-build/benchtests/bench-malloc-thread
# To build **and run** all glibc benchtests, do:
time make bench
Referenzen:
- https://www.gnu.org/software/libc/manual/html_node/Configuring-and-compiling.html
- https://kazoo.ga/a-simple-tool-to-test-malloc-performance/
- https://github.com/f18m/malloc-benchmarks/blob/master/Makefile#L122-L129 :Ich habe viel davon gelernt, indem ich dieses Makefile-Ziel studiert habe:
$(glibc_install_dir)/lib/libc.so.6: @echo "Building GNU libc... go get a cup of coffee... this will take time!" mkdir -p $(glibc_build_dir) cd $(glibc_build_dir) && \ ../glibc/configure --prefix=$(glibc_install_dir) && \ make $(parallel_flags) && \ make install [ -x $(glibc_build_dir)/benchtests/bench-malloc-thread ] && echo "GNU libc benchmarking utility is ready!" || echo "Cannot find GNU libc benchmarking utility! Cannot collect benchmark results"
- Wie kompiliere ich meine eigene Glibc-C-Standardbibliothek aus dem Quellcode und verwende sie?
Schlüsselwörter:wie man glibc und seine Benchtests erstellt und ausführt, inkl. Malloc-Benchtests, aus der Quelle; Erstellen Sie glibc aus dem Quellcode unter Linux Ubuntu
Die Makefile
wird in Ihrem build-glibc
existieren Verzeichnis, wenn der configure
Skript erfolgreich beendet.
Wenn alles scheint während configure
reibungslos verlaufen zu sein und immer noch kein Makefile
, dann haben Sie wahrscheinlich eine Eigenart übersehen:
Beim Ausführen einer configure
für glibc wird erwartet, dass Sie normalerweise einen alternativen --prefix
angeben , da die Installation am Standardspeicherort (/usr/local
) kann das System möglicherweise lahmlegen. Wenn Sie keine angeben, müssen Sie --disable-sanity-checks
einschalten .
Ist dies auch nicht der Fall, suchen Sie nach einem config.log
Datei und lesen Sie ihren Inhalt.
Setup 1:glibc ohne dedizierten GCC
Dieses Setup könnte funktionieren und ist schnell, da es nicht die gesamte GCC-Toolchain neu kompiliert, sondern nur glibc.
Das einzige Problem, das ich mit diesem Setup habe, ist, dass ich keinen netten Weg gefunden habe, Laufzeitobjekte wie crt1.o
zu verwenden , crti.o
, und crtn.o
bereitgestellt von unserer glibc, und ich verwende vorerst die Host-Dateien. Dies wird unter:https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location erwähnt und unglaublich subtile Wege. Siehe Lösungsversuche weiter unten.
Glibc erstellen und lokal installieren:
git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.32
mkdir build
cd build
export glibc_install="$(pwd)/install"
../configure --prefix "$glibc_install"
make -j `nproc`
make install -j `nproc`
Setup 1:Überprüfen Sie den Build
test_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);
}
Mit test_glibc.sh
kompilieren und ausführen :
#!/usr/bin/env bash
set -eux
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" \
-std=c11 \
-o test_glibc.out \
-v \
test_glibc.c \
-pthread \
;
ldd ./test_glibc.out
./test_glibc.out
Befehl angepasst von https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location
Das Programm gibt das Erwartete aus:
gnu_get_libc_version() = 2.32
The atomic counter is 10000
The non-atomic counter is 8674
ldd
Ausgabe bestätigt, dass der ldd
und Bibliotheken, die wir gerade erstellt haben, werden tatsächlich wie erwartet verwendet:
+ 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)
Die gcc
Die Debug-Ausgabe der Kompilierung zeigt, dass meine Host-Laufzeitobjekte verwendet wurden, was wie bereits erwähnt schlecht ist, aber ich weiß nicht, wie ich es umgehen soll, z. es enthält:
COLLECT_GCC_OPTIONS=/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crt1.o
Setup 1:glibc ändern
Jetzt modifizieren wir glibc mit:
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)");
Dann kompilieren und installieren Sie glibc neu und kompilieren Sie unser Programm neu und führen Sie es erneut aus:
cd glibc/build
make -j `nproc`
make -j `nproc` install
./test_glibc.sh
und wir sehen hacked
wie erwartet einige Male gedruckt.
Dies bestätigt weiter, dass wir tatsächlich die glibc verwendet haben, die wir kompiliert haben, und nicht die des Hosts.
Getestet auf Ubuntu 20.10.
Setup 1:Versuche, den richtigen crt*
zu verwenden Objekte
https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location schlägt vor, --sysroot
hinzuzufügen an die gcc
Befehl aber:
- Es ändert die Objekte laut Protokollen nicht wirklich auf unsere
- und es lässt die Kompilierung mit
/usr/bin/ld: cannot find libgcc_s.so.1
fehlschlagen vermutlich weil diesysroot
wird für dieses von GCC bereitgestellte Objekt verwendet, das wir in diesem Sysroot nicht haben, weil wir nur glibc gebaut haben
Unter https://stackoverflow.com/a/66634184/895245 bietet ZeZNiQ eine wahrscheinlich korrekte Problemumgehung, indem es Folgendes übergibt:
-nostartfiles
gefolgt von allen Objekten. Sie müssen nur die richtigen Objekte aus dem vollständigen Befehl mit -nostartfiles
extrahieren und übergeben Sie sie manuell.
Zum Beispiel waren die verwendeten Objekte auf meinem amd64-Rechner anders als sein 32-Bit-Befehl, also ist das ein bisschen fummelig.
Literatur:
- Wie ändere ich das Standardsuchverzeichnis von GCC für crti.o?
- https://gcc.gnu.org/legacy-ml/gcc-help/2015-02/msg00016.html
- https://gcc.gnu.org/legacy-ml/gcc-help/2001-11/msg00029.html
Setup 2:makelloses Crosstool-NG-Setup
Dies ist eine Alternative zu Setup 1, und es ist das korrekteste Setup, das ich bisher erreicht habe:Soweit ich das beobachten kann, ist alles korrekt, einschließlich der C-Laufzeitobjekte wie crt1.o
, crti.o
, und crtn.o
.
In diesem Setup werden wir eine vollständig dedizierte GCC-Toolchain kompilieren, die die von uns gewünschte glibc verwendet.
Der einzige Nachteil dieser Methode ist, dass der Build länger dauert. Aber mit weniger würde ich kein Produktions-Setup riskieren.
crosstool-NG ist eine Reihe von Skripten, die alles für uns aus dem Quellcode herunterladen und kompilieren, einschließlich GCC, glibc und binutils.
Ja, das GCC-Build-System ist so schlecht, dass wir dafür ein separates Projekt brauchen.
Dieses Setup ist nur deshalb nicht perfekt, weil crosstool-NG das Erstellen der ausführbaren Dateien ohne zusätzlichen -Wl
nicht unterstützt Flags, was sich komisch anfühlt, da wir GCC selbst gebaut haben. Aber alles scheint zu funktionieren, also ist das nur eine Unannehmlichkeit.
Holen Sie sich crosstool-NG, konfigurieren und bauen Sie es:
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
env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`
Der Build dauert etwa dreißig Minuten bis zwei Stunden.
Die einzige obligatorische Konfigurationsoption, die ich sehen kann, besteht darin, sie an Ihre Host-Kernel-Version anzupassen, um die richtigen Kernel-Header zu verwenden. Finden Sie Ihre Host-Kernel-Version mit:
uname -a
was mir zeigt:
4.15.0-34-generic
also in menuconfig
Ich mache:
Operating System
Version of linux
also wähle ich:
4.14.71
das ist die erste gleiche oder ältere Version. Es muss älter sein, da der Kernel abwärtskompatibel ist.
Setup 2:optionale Konfigurationen
Die .config
die wir mit ./ct-ng x86_64-unknown-linux-gnu
generiert haben hat:
CT_GLIBC_V_2_27=y
Um das zu ändern, in menuconfig
tun:
C-library
Version of glibc
Speichern Sie den .config
, und fahren Sie mit dem Build fort.
Oder wenn Sie Ihre eigene Glibc-Quelle verwenden möchten, z. um glibc vom neusten git zu verwenden, gehen sie wie folgt vor:
Paths and misc options
Try features marked as EXPERIMENTAL
:auf wahr setzen
C-library
Source of glibc
Custom location
:Ja sagenCustom location
Custom source location
:Zeigen Sie auf ein Verzeichnis, das Ihre Glibc-Quelle enthält
wobei glibc geklont wurde als:
git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.28
Setup 2:Testen Sie es aus
Nachdem Sie die gewünschte Toolchain erstellt haben, testen Sie sie mit:
#!/usr/bin/env bash
set -eux
install_dir="${CT_PREFIX}/x86_64-unknown-linux-gnu"
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" \
-v \
-o test_glibc.out \
test_glibc.c \
-pthread \
;
ldd test_glibc.out
./test_glibc.out
Alles scheint wie in Setup 1 zu funktionieren, außer dass jetzt die richtigen Laufzeitobjekte verwendet wurden:
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
Setup 2:Effizienter Glibc-Neukompilierungsversuch fehlgeschlagen
Mit crosstool-NG scheint dies nicht möglich zu sein, wie unten erklärt.
Wenn Sie nur neu erstellen;
env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`
dann werden Ihre Änderungen am benutzerdefinierten glibc-Quellspeicherort berücksichtigt, aber es wird alles von Grund auf neu erstellt, was es für die iterative Entwicklung unbrauchbar macht.
Wenn ja:
./ct-ng list-steps
es gibt einen schönen Überblick über die Build-Schritte:
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.
Daher sehen wir, dass glibc-Schritte mit mehreren GCC-Schritten verflochten sind, insbesondere libc_start_files
kommt vor cc_core_pass_2
, was zusammen mit cc_core_pass_1
wahrscheinlich der teuerste Schritt ist .
Um nur einen Schritt zu bauen, müssen Sie zuerst in .config
das "Zwischenschritte speichern" setzen Option für den anfänglichen Build:
Paths and misc options
Debug crosstool-NG
Save intermediate steps
und dann können Sie versuchen:
env -u LD_LIBRARY_PATH time ./ct-ng libc+ -j`nproc`
aber leider die +
erforderlich, wie unter:https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536
Beachten Sie jedoch, dass ein Neustart bei einem Zwischenschritt das Installationsverzeichnis auf den Zustand zurücksetzt, den es während dieses Schritts hatte. Das heißt, Sie haben eine neu erstellte libc - aber keinen endgültigen Compiler, der mit dieser libc erstellt wurde (und daher auch keine Compiler-Bibliotheken wie libstdc++).
und im Grunde macht die Neuerstellung immer noch zu langsam, um für die Entwicklung machbar zu sein, und ich sehe nicht, wie ich dies überwinden kann, ohne crosstool-NG zu patchen.
Außerdem ab dem libc
step schien die Quelle nicht erneut von Custom source location
zu kopieren , was diese Methode weiter unbrauchbar macht.
Bonus:stdlibc++
Ein Bonus, wenn Sie auch an der C++-Standardbibliothek interessiert sind:How to edit and rebuild the GCC libstdc++ C++ standard library source?
Hinzufügen zu Ciros früherer Antwort/Lösung https://stackoverflow.com/a/52454710/4726668 :
@CiroSantilli Beim Bearbeiten Ihrer Antwort wird "Vorgeschlagene Bearbeitungswarteschlange ist voll" zurückgegeben. Das ldd-Skript, das Sie aufrufen, ist test_glibc.sh
Das Skript verweist auf den dynamischen Linker des Hosts:/home/ciro/glibc/build/install/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007fc12f1b3000)
. Um dies zu beheben, in test_glibc.sh
, ändern Sie ldd
bis ${glibc_install}/bin/ldd
. Dazu müssen Sie den eingebauten crt
hinzufügen *.o-Dateien ebenfalls zum Skript:
-nostartfiles \
${glibc_install}/lib/crti.o \
${glibc_install}/lib/crtn.o \
${glibc_install}/lib/crt1.o \
Auf meinem GNU/Linux i386/i686 (32-Bit x86 Arch)-Rechner folgt mein funktionierender test_glibc.sh
:
#!/usr/bin/env bash
set -eux
gcc \
-L "${glibc_install}/lib" \
-I "${glibc_install}/include" \
-Wl,--rpath="${glibc_install}/lib" \
-Wl,--dynamic-linker="${glibc_install}/lib/ld-linux.so.2" \
-std=c11 \
-nostartfiles \
${glibc_install}/lib/crti.o \
${glibc_install}/lib/crtn.o \
${glibc_install}/lib/crt1.o \
-o test_glibc.out \
-v \
test_glibc.c \
-pthread \
;
${glibc_install}/bin/ldd ./test_glibc.out
./test_glibc.out