GNU/Linux >> Linux の 問題 >  >> Linux

ソースから独自の glibc C 標準ライブラリをコンパイルして使用するにはどうすればよいですか?

最後に glibc 開発バージョン 2.33.9000 を使用して Ubuntu 20.04 でテスト済み (glibc/version.h を参照) ) 2021 年 6 月 27 日。

glibc をダウンロードしてビルドし、そのベンチマークを実行する方法

glibc のソース コードは、https://www.gnu.org/software/libc/sources.html から手動で取得できます:

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

GitHub のサードパーティ ミラー:https://github.com/bminor/glibc/tree/master/benchtests

こちらもご覧ください:

<オール>
  • https://kazoo.ga/a-simple-tool-to-test-malloc-performance/
  • glibc とそのベンチテストを手動でビルドする場合は、次のようにします。

    # 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
    

    参考文献:

    <オール>
  • 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 :このメイクファイル ターゲットを研究することで、多くのことを学びました:
    $(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"
    
  • 独自の glibc C 標準ライブラリをソースからコンパイルして使用する方法
  • キーワード:glibc とそのベンチテストをビルドして実行する方法。ソースからのmallocベンチテスト。 Linux ubuntu でソースから glibc をビルド


    Makefile build-glibc に存在する予定です configure の場合はディレクトリ スクリプトが正常に終了しました。

    すべて思われる場合 configure の間に順調に進んだこと まだ Makefile はありません の場合は、特異性を見逃している可能性があります:

    configure を実行中 glibc の場合、通常は代わりの --prefix を提供することが期待されます 、デフォルトの場所 (/usr/local にインストールするため) ) システムが機能しなくなる可能性があります。提供しない場合は、--disable-sanity-checks をオンにする必要があります .

    そうでない場合は、config.log を探します。 ファイルを開き、その内容を読み取ります。


    セットアップ 1:専用 GCC を使用しない glibc

    このセットアップは、GCC ツールチェーン全体を再コンパイルするのではなく、glibc のみを再コンパイルするため、うまくいく可能性があり、迅速です。

    このセットアップに関する唯一の問題は、crt1.o などのランタイム オブジェクトを使用する適切な方法が見つからなかったことです。 、 crti.o 、および crtn.o 私たちの glibc によって提供されており、今のところホストのものを使用しています。これについては、https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location で言及されています。そして驚くほど微妙な方法。以下でこれを解決するための試みを参照してください。

    glibc をビルドしてローカルにインストール:

    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`
    

    セットアップ 1:ビルドを確認する

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

    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
    

    https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location から採用したコマンド

    プログラムは期待されるものを出力します:

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

    ldd 出力は ldd であることを確認します 構築したばかりのライブラリは、実際に期待どおりに使用されています:

    + 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 コンパイルのデバッグ出力は、私のホスト ランタイム オブジェクトが使用されたことを示しています。含まれています:

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

    セットアップ 1:glibc の変更

    それでは、glibc を次のように変更しましょう:

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

    次に、glibc を再コンパイルして再インストールし、プログラムを再コンパイルして再実行します。

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

    hacked が表示されます 予想通り数回印刷されました。

    これにより、ホストのものではなく、コンパイルした glibc を実際に使用したことがさらに確認されます。

    Ubuntu 20.10 でテスト済み。

    セットアップ 1:正しい crt* の使用を試みる オブジェクト

    https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location --sysroot を追加することをお勧めします gcc に コマンドですが:

    • ログによると、実際にオブジェクトを私たちのものに変更するわけではありません
    • そして /usr/bin/ld: cannot find libgcc_s.so.1 でコンパイルが失敗します おそらく sysroot この GCC 提供のオブジェクトに使用されますが、glibc のみを構築したため、その sysroot にはありません

    https://stackoverflow.com/a/66634184/895245 で、ZeZNiQ は以下を渡すことでおそらく正しい回避策を提供します:

    -nostartfiles
    

    その後にすべてのオブジェクトが続きます。 -nostartfiles を使用して完全なコマンドから正しいオブジェクトを抽出するだけです。 手動で渡します。

    たとえば、私の amd64 マシンでは、使用されるオブジェクトが彼の 32 ビット コマンドとは異なるため、これは少し面倒です。

    参考文献:

    • crti.o の GCC のデフォルト検索ディレクトリを変更するにはどうすればよいですか?
    • https://gcc.gnu.org/legacy-ml/gcc-help/2015-02/msg00016.html
    • https://gcc.gnu.org/legacy-ml/gcc-help/2001-11/msg00029.html

    セットアップ 2:crosstool-NG の元のセットアップ

    これはセットアップ 1 の代替であり、これまでに達成した中で最も正しいセットアップです。crt1.o などの C ランタイム オブジェクトを含め、私が観察できる限り、すべてが正しいです。 、 crti.o 、および crtn.o .

    このセットアップでは、必要な glibc を使用する完全な専用 GCC ツールチェーンをコンパイルします。

    この方法の唯一の欠点は、ビルドに時間がかかることです。しかし、それ以下のもので本番環境のセットアップを危険にさらすことはありません.

    crosstool-NG は、GCC、glibc、binutils など、ソースからすべてをダウンロードしてコンパイルする一連のスクリプトです。

    はい、GCC ビルド システムは非常に悪いので、別のプロジェクトが必要です。

    crosstool-NG は追加の -Wl なしで実行可能ファイルのビルドをサポートしていないため、このセットアップは完璧ではありません。 GCC 自体を構築したので、これは奇妙に感じます。しかし、すべてうまくいっているように見えるので、これはただの不便です.

    crosstool-NG を入手し、構成してビルドします。

    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`
    

    ビルドには約 30 分から 2 時間かかります。

    私が見ることができる唯一の必須の構成オプションは、正しいカーネルヘッダーを使用するためにホストカーネルのバージョンと一致させることです。ホスト カーネルのバージョンを確認するには:

    uname -a
    

    4.15.0-34-generic
    

    だから menuconfig 私は:

    • Operating System
      • Version of linux

    だから私は選択します:

    4.14.71
    

    これは、最初の同等または古いバージョンです。カーネルには下位互換性があるため、古いものである必要があります。

    セットアップ 2:オプションの構成

    .config ./ct-ng x86_64-unknown-linux-gnu で生成したもの 持っています:

    CT_GLIBC_V_2_27=y
    

    それを変更するには、menuconfig で する:

    • C-library
    • Version of glibc

    .config を保存します 、ビルドを続行します。

    または、独自の glibc ソースを使用する場合。最新の git から glibc を使用するには、次のように進めます:

    • Paths and misc options
      • Try features marked as EXPERIMENTAL :true に設定
    • C-library
      • Source of glibc
        • Custom location :そう言ってください
        • Custom location
          • Custom source location :glibc ソースを含むディレクトリを指定します

    glibc は次のように複製されました:

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

    セットアップ 2:テストしてみる

    必要なツールチェーンを構築したら、以下でテストします:

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

    正しいランタイム オブジェクトが使用されたことを除いて、すべてがセットアップ 1 と同じように機能しているように見えます:

    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
    

    セットアップ 2:効率的な glibc 再コンパイルの試みに失敗しました

    以下で説明するように、クロスツール NG では不可能のようです。

    再構築するだけなら;

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

    カスタム glibc ソースの場所への変更は考慮されますが、すべてをゼロから構築するため、反復的な開発には使用できません。

    その場合:

    ./ct-ng list-steps
    

    ビルド手順の概要が分かりやすくなっています:

    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.
    

    したがって、いくつかの GCC ステップと絡み合った glibc ステップがあることがわかります。最も顕著なのは libc_start_files です。 cc_core_pass_2 の前に来る 、これはおそらく cc_core_pass_1 とともに最も高価なステップです .

    1 つのステップだけをビルドするには、最初に .config で「中間ステップの保存」を設定する必要があります。 初期ビルドのオプション:

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

    そして、あなたは試すことができます:

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

    残念ながら、+ https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536 で述べられているように必要です

    <ブロック引用>

    ただし、中間ステップで再起動すると、インストール ディレクトリがそのステップ中の状態にリセットされることに注意してください。つまり、再構築された libc がありますが、この libc で構築された最終的なコンパイラはありません (したがって、libstdc++ のようなコンパイラ ライブラリもありません)。

    そして、基本的には再構築が遅すぎて開発に適していません.crosstool-NGにパッチを当てずにこれを克服する方法がわかりません.

    さらに、libc から ステップは Custom source location からソースを再度コピーしているようには見えませんでした 、さらにこのメソッドを使用できなくします。

    ボーナス:stdlibc++

    C++ 標準ライブラリにも興味がある場合のボーナス:GCC libstdc++ C++ 標準ライブラリ ソースを編集して再構築する方法は?


    Ciro の以前の回答/ソリューションへの追加 https://stackoverflow.com/a/52454710/4726668 :

    @CiroSantilli 回答を編集すると、「提案された編集キューがいっぱいです」が返されます。 test_glibc.sh で呼び出している ldd スクリプト スクリプトはホスト動的リンカーを指します:/home/ciro/glibc/build/install/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007fc12f1b3000) .これを修正するには、test_glibc.sh で 、変更 ldd ${glibc_install}/bin/ldd まで .これには、ビルドされた crt を追加する必要があります *.o ファイルもスクリプトに追加:

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

    私の GNU/Linux i386/i686 (32 ビット x86 アーキテクチャ) マシンでは、次のように動作します 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. CentOS / RHELのソースからFFmpegをコンパイルしてインストールする方法は?

    2. いつソースからコンパイルしてインストールする必要がありますか?

    3. Linux でソースから (および YUM を使用して) MongoDB をインストールする方法

    1. Ubuntu18.04LTSでソースからBrotliをコンパイルする方法

    2. Linux にソースから TBB をインストールして動作させる方法

    3. GLFW 3 をビルドしてインストールし、Linux プロジェクトで使用する方法

    1. CentOS7でソースからBrotliをコンパイルする方法

    2. CheckInstallを使用してソースからパッケージを構築する方法

    3. CentOSのソースからPython3.5とPython-pipをコンパイルしてインストールする方法