GNU/Linux >> Znalost Linux >  >> Linux

Jak zkompilovat vlastní standardní knihovnu glibc C ze zdroje a použít ji?

Naposledy testováno na Ubuntu 20.04 s vývojovou verzí glibc 2.33.9000 (viz glibc/version.h ) dne 27. června 2021.

Jak stáhnout a sestavit glibc a spustit jeho benchmarky

Zdrojový kód glibc můžete ručně získat zde:https://www.gnu.org/software/libc/sources.html:

git clone https://sourceware.org/git/glibc.git
cd glibc
git checkout master

Zrcadlo třetí strany na GitHubu:https://github.com/bminor/glibc/tree/master/benchtests

Viz také:

  1. https://kazoo.ga/a-simple-tool-to-test-malloc-performance/

Pokud si někdy budete přát ručně sestavit glibc a jeho benchtesty, udělejte to následovně:

# 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

Odkazy:

  1. https://www.gnu.org/software/libc/manual/html_node/Configuring-and-compiling.html
  2. https://kazoo.ga/a-simple-tool-to-test-malloc-performance/
  3. https://github.com/f18m/malloc-benchmarks/blob/master/Makefile#L122-L129 :Hodně jsem se toho naučil při studiu tohoto cíle makefile:
    $(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"
    
  4. Jak zkompilovat vlastní standardní knihovnu glibc C ze zdroje a použít ji?

Klíčová slova:jak sestavit a spustit glibc a jeho benchtesty, vč. benchtesty malloc, ze zdroje; sestavte glibc ze zdroje na linux ubuntu


Makefile bude existovat ve vašem build-glibc pokud je configure skript úspěšně skončí.

Pokud se vše zdá během configure proběhly hladce a stále žádné Makefile , pak vám pravděpodobně unikla výstřednost:

Při provádění configure pro glibc se očekává, že normálně poskytnete alternativní --prefix , protože instalace do výchozího umístění (/usr/local ) může potenciálně ochromit systém. Pokud žádný nezadáte, musíte zapnout --disable-sanity-checks .

Pokud ani toto není tento případ, vyhledejte config.log a přečtěte si jeho obsah.


Nastavení 1:glibc bez vyhrazeného GCC

Toto nastavení může fungovat a je rychlé, protože nepřekompiluje celý nástroj GCC, pouze glibc.

Jediný problém, který mám s tímto nastavením, je ten, že jsem nenašel pěkný způsob, jak používat runtime objekty, jako je crt1.o , crti.o a crtn.o poskytuje náš glibc a já zatím používám hostitelské. Toto je zmíněno na:https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location Tyto objekty provádějí brzké nastavení, na které se glibc spoléhá, ​​takže bych nebyl překvapen, kdyby se věci zhroutily v úžasném a úžasně rafinovanými způsoby. Viz pokusy o vyřešení níže.

Sestavte glibc a nainstalujte lokálně:

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`

Nastavení 1:ověřte sestavení

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);
}

Kompilace a spuštění s 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-x86-64.so.2" \
  -std=c11 \
  -o test_glibc.out \
  -v \
  test_glibc.c \
  -pthread \
;
ldd ./test_glibc.out
./test_glibc.out

Příkaz upraven z https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location

Výstupem programu je očekávané:

gnu_get_libc_version() = 2.32
The atomic counter is 10000
The non-atomic counter is 8674

ldd výstup potvrzuje, že ldd a knihovny, které jsme právě vytvořili, se skutečně používají podle očekávání:

+ 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)

gcc výstup ladění kompilace ukazuje, že byly použity moje hostitelské runtime objekty, což je špatné, jak bylo zmíněno dříve, ale nevím, jak to obejít, např. obsahuje:

COLLECT_GCC_OPTIONS=/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crt1.o

Nastavení 1:úprava glibc

Nyní upravíme glibc pomocí:

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)");

Poté znovu zkompilujte a znovu nainstalujte glibc a znovu zkompilujte a znovu spusťte náš program:

cd glibc/build
make -j `nproc`
make -j `nproc` install
./test_glibc.sh

a vidíme hacked vytištěno několikrát podle očekávání.

To dále potvrzuje, že jsme skutečně použili glibc, který jsme zkompilovali, a ne hostitelský.

Testováno na Ubuntu 20.10.

Nastavení 1:pokusí se použít správný crt* objekty

https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location navrhuje přidat --sysroot na gcc příkaz ale:

  • ve skutečnosti nemění objekty na naše podle protokolů
  • a způsobí to selhání kompilace s /usr/bin/ld: cannot find libgcc_s.so.1 pravděpodobně proto, že sysroot se používá pro tento objekt poskytovaný GCC, který v tomto kořenovém adresáři sysroot nemáme, protože jsme vytvořili pouze glibc

Na https://stackoverflow.com/a/66634184/895245 ZeZNiQ poskytuje řešení, které je pravděpodobně správné, tím, že předá:

-nostartfiles

následují všechny předměty. Stačí extrahovat správné objekty z úplného příkazu s -nostartfiles a předejte je ručně.

Například na mém počítači amd64 se použité objekty lišily od jeho 32bitového příkazu, takže je to trochu nešikovné.

Bibliografie:

  • Jak změním výchozí vyhledávací adresář GCC pro 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

Nastavení 2:Dokonalé nastavení crosstool-NG

Toto je alternativa k nastavení 1 a je to nejsprávnější nastavení, kterého jsem dosud dosáhl:vše je v pořádku, pokud mohu pozorovat, včetně objektů C runtime, jako je crt1.o , crti.o a crtn.o .

V tomto nastavení zkompilujeme úplný vyhrazený toolchain GCC, který používá glibc, který chceme.

Jedinou nevýhodou této metody je, že sestavení bude trvat déle. Ale neriskoval bych produkční nastavení s ničím menším.

crosstool-NG je sada skriptů, která pro nás stahuje a kompiluje vše ze zdroje, včetně GCC, glibc a binutils.

Ano, sestavovací systém GCC je tak špatný, že na to potřebujeme samostatný projekt.

Toto nastavení není dokonalé, protože crosstool-NG nepodporuje vytváření spustitelných souborů bez extra -Wl flags, což je divný pocit, protože jsme vytvořili samotné GCC. Ale zdá se, že vše funguje, takže je to jen nepříjemnost.

Získejte crosstool-NG, nakonfigurujte jej a sestavte:

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`

Sestavení trvá asi třicet minut až dvě hodiny.

Jedinou povinnou možností konfigurace, kterou vidím, je zajistit, aby odpovídala verzi vašeho hostitelského jádra, aby používala správné hlavičky jádra. Najděte verzi hostitelského jádra pomocí:

uname -a

což mi ukazuje:

4.15.0-34-generic

tedy v menuconfig Já ano:

  • Operating System
    • Version of linux

takže vybírám:

4.14.71

což je první stejná nebo starší verze. Musí být starší, protože jádro je zpětně kompatibilní.

Nastavení 2:volitelné konfigurace

.config které jsme vygenerovali pomocí ./ct-ng x86_64-unknown-linux-gnu má:

CT_GLIBC_V_2_27=y

Chcete-li to změnit, v menuconfig udělat:

  • C-library
  • Version of glibc

uložte .config a pokračujte v sestavení.

Nebo, pokud chcete použít svůj vlastní zdroj glibc, např. pro použití glibc z nejnovějšího git postupujte takto:

  • Paths and misc options
    • Try features marked as EXPERIMENTAL :nastaveno na hodnotu true
  • C-library
    • Source of glibc
      • Custom location :řekni ano
      • Custom location
        • Custom source location :přejděte na adresář obsahující váš zdroj glibc

kde glibc byl klonován jako:

git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.28

Nastavení 2:vyzkoušejte to

Jakmile vytvoříte požadovaný nástrojový řetězec, vyzkoušejte jej pomocí:

#!/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

Zdá se, že vše funguje jako v Nastavení 1, až na to, že nyní byly použity správné runtime objekty:

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

Nastavení 2:neúspěšný pokus o efektivní rekompilaci glibc

Zdá se, že s crosstool-NG to není možné, jak je vysvětleno níže.

Pokud jste právě přestavěli;

env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`

pak se vezmou v úvahu vaše změny ve vlastním umístění zdroje glibc, ale vše vytváří od začátku, takže je pro iterativní vývoj nepoužitelný.

Pokud to uděláme:

./ct-ng list-steps

poskytuje pěkný přehled kroků sestavení:

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.

proto vidíme, že existují kroky glibc propojené s několika kroky GCC, zejména libc_start_files je před cc_core_pass_2 , což je pravděpodobně nejdražší krok spolu s cc_core_pass_1 .

Chcete-li sestavit pouze jeden krok, musíte nejprve nastavit "Uložit mezikroky" v .config možnost pro počáteční sestavení:

  • Paths and misc options
    • Debug crosstool-NG
      • Save intermediate steps

a pak můžete zkusit:

env -u LD_LIBRARY_PATH time ./ct-ng libc+ -j`nproc`

ale bohužel + vyžadováno, jak je uvedeno na:https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536

Všimněte si však, že restartování v mezikroku resetuje instalační adresář do stavu, v jakém byl během tohoto kroku. To znamená, že budete mít přestavěnou knihovnu libc – ale žádný konečný kompilátor vytvořený s touto knihovnou libc (a tudíž ani žádné knihovny kompilátorů jako libstdc++).

a v zásadě je přestavba stále příliš pomalá na to, aby byla proveditelná pro vývoj, a nevím, jak to překonat bez záplatování crosstool-NG.

Navíc počínaje libc nezdálo se, že by step znovu zkopíroval zdroj z Custom source location , což dále činí tuto metodu nepoužitelnou.

Bonus:stdlibc++

Bonus, pokud vás také zajímá standardní knihovna C++:Jak upravit a znovu sestavit zdrojový kód standardní knihovny GCC libstdc++ C++?


Přidání k dřívější odpovědi/řešení Ciro https://stackoverflow.com/a/52454710/4726668 :

@CiroSantilli Úprava vaší odpovědi vrátí „Fronta navrhovaných úprav je plná“. Skript ldd, který voláte, v test_glibc.sh skript ukazuje na hostitelský dynamický linker:/home/ciro/glibc/build/install/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007fc12f1b3000) . Chcete-li to opravit, v test_glibc.sh , změňte ldd na ${glibc_install}/bin/ldd . To bude vyžadovat, abyste přidali vestavěný crt *.o soubory také do skriptu:

-nostartfiles \
${glibc_install}/lib/crti.o \
${glibc_install}/lib/crtn.o \
${glibc_install}/lib/crt1.o \

Na mém počítači GNU/Linux i386/i686 (32bitový x86 arch) je můj pracovní 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

Linux
  1. Jak zkompilovat a nainstalovat FFmpeg ze zdroje v CentOS/RHEL?

  2. Kdy byste měli kompilovat a instalovat ze zdroje?

  3. Jak nainstalovat MongoDB ze zdroje (a pomocí YUM) na Linuxu

  1. Jak zkompilovat Brotli ze zdroje na Ubuntu 18.04 LTS

  2. Jak používat sched_getaffinity a sched_setaffinity v Linuxu z C?

  3. Jak nainstalovat TBB ze zdroje na Linux a zprovoznit jej

  1. Jak zkompilovat Brotli ze zdroje na CentOS 7

  2. Jak sestavit balíčky ze zdroje pomocí CheckInstall

  3. Jak zkompilovat a nainstalovat Python3.5 a Python-pip ze zdroje na CentOS