Nhiều thư viện glibc trên một máy chủ


171

Nhiều thư viện glibc trên một máy chủ

Máy chủ linux (SLES-8) của tôi hiện có glibc-2.2.5-235, nhưng tôi có một chương trình không hoạt động trên phiên bản này và yêu cầu glibc-2.3.3.

Có thể có nhiều glibcs ​​được cài đặt trên cùng một máy chủ không?

Đây là lỗi tôi gặp phải khi chạy chương trình của mình trên glibc cũ:

./myapp: /lib/i686/libc.so.6: version `GLIBC_2.3' not found (required by ./myapp)
./myapp: /lib/i686/libpthread.so.0: version `GLIBC_2.3.2' not found (required by ./myapp)
./myapp: /lib/i686/libc.so.6: version `GLIBC_2.3' not found (required by ./libxerces-c.so.27)
./myapp: /lib/ld-linux.so.2: version `GLIBC_2.3' not found (required by ./libstdc++.so.6)
./myapp: /lib/i686/libc.so.6: version `GLIBC_2.3' not found (required by ./libstdc++.so.6)

Vì vậy, tôi đã tạo một thư mục mới gọi là newglibc và sao chép các tệp sau vào:

libpthread.so.0
libm.so.6
libc.so.6
ld-2.3.3.so
ld-linux.so.2 -> ld-2.3.3.so

export LD_LIBRARY_PATH=newglibc:$LD_LIBRARY_PATH

Nhưng tôi gặp một lỗi:

./myapp: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by ./newglibc/libpthread.so.0)
./myapp: /lib/ld-linux.so.2: version `GLIBC_2.3' not found (required by libstdc++.so.6)
./myapp: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by ./newglibc/libm.so.6)
./myapp: /lib/ld-linux.so.2: version `GLIBC_2.3' not found (required by ./newglibc/libc.so.6)
./myapp: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by ./newglibc/libc.so.6)

Vì vậy, có vẻ như họ vẫn đang liên kết đến / lib và không nhận từ nơi tôi đặt chúng?

Cảm ơn


1
vấn đề tương tự với máy chủ SLES-11. Không thể cập nhật và cần những thứ gần đây. oh của tôi ...
UmNyobe

FWIW, export LD_LIBRARY_PATH=newglibc:$LD_LIBRARY_PATH đã giải quyết vấn đề cho tôi! Nó chắc chắn sẽ không hoạt động cho tất cả mọi người, nhưng nó là một sửa chữa dễ dàng nếu nó hoạt động! Cảm ơn! :)
rinogo

Câu trả lời:


229

Rất có thể có nhiều phiên bản glibc trên cùng một hệ thống (chúng tôi làm điều đó mỗi ngày).

Tuy nhiên, bạn cần biết rằng glibc bao gồm nhiều phần (hơn 200 thư viện chia sẻ) mà tất cả phải phù hợp. Một trong những phần là ld-linux.so.2 và nó phải phù hợp với libc.so.6, hoặc bạn sẽ thấy các lỗi bạn đang thấy.

Đường dẫn tuyệt đối đến ld-linux.so.2 được mã hóa cứng vào tệp thực thi tại thời điểm liên kết và không thể dễ dàng thay đổi sau khi liên kết được thực hiện.

Để xây dựng một tệp thực thi sẽ hoạt động với glibc mới, hãy làm điều này:

g++ main.o -o myapp ... \
   -Wl,--rpath=/path/to/newglibc \
   -Wl,--dynamic-linker=/path/to/newglibc/ld-linux.so.2

Các -rpathtùy chọn mối liên kết sẽ làm cho việc tìm kiếm bộ nạp thời gian chạy cho các thư viện trong /path/to/newglibc(do đó bạn sẽ không cần phải thiết lập LD_LIBRARY_PATHtrước khi chạy nó), và các -dynamic-linkertùy chọn sẽ "nướng" đường dẫn đến đúng ld-linux.so.2vào ứng dụng.

Nếu bạn không thể tải lại myappứng dụng (ví dụ vì đây là tệp nhị phân của bên thứ ba), không phải tất cả đều bị mất, nhưng nó trở nên khó khăn hơn. Một giải pháp là thiết lập một chrootmôi trường thích hợp cho nó. Một khả năng khác là sử dụng rtlditrình soạn thảo nhị phân .


3
Lưu ý rằng -Wl,--dynamic-linker=file(mất hai '-') chỉ hoạt động khi biên dịch cho các tệp thực thi ELF. Kiểm tra/sbin/ldconfig -p | grep ld
Tom

49
Bây giờ bạn có thể sử dụng một tiện ích thuận tiện patchelf( nixos.org/patchelf.html ), cho phép bạn sửa đổi rpath và trình thông dịch của ELF đã được biên dịch.
Michael Pankov

10
Điều đáng nói là việc chỉ định đường dẫn đến glibc mới sử dụng -Wl,--rpaththay vì LD_LIBRARY_PATHcó thể quan trọng vì những lý do không phải là thuận tiện: nếu chương trình khởi chạy các tiến trình con, giá trị LD_LIBRARY_PATHthường sẽ được kế thừa bởi chúng, nhưng nếu chúng không được biên dịch để sử dụng glibc mới hơn (ví dụ: nếu chúng là nhị phân chứng khoán bash), chúng sẽ không khởi chạy.
HighCommander4

13
Một tùy chọn khác đang chạy trực tiếp ld.so mới, truyền cho nó chương trình nhị phân của bạn dưới dạng tham số; điều này sẽ thay thế hiệu quả ld.so được sử dụng với nhu cầu biên dịch lại chương trình:/path/to/newglibc/ld-linux.so.2 --library-path /path/tonewglibc/lib64:/path/to/newglibc/usr/lib64 /path/to/myapp
maximk


67

Câu hỏi này là cũ, câu trả lời khác là cũ. Câu trả lời của "Người Nga làm việc" rất hay và nhiều thông tin, nhưng nó chỉ hoạt động nếu bạn có mã nguồn. Nếu bạn không, các lựa chọn thay thế sau đó rất khó khăn. May mắn là ngày nay chúng ta có một giải pháp đơn giản cho vấn đề này (như đã nhận xét trong một trong những câu trả lời của anh ấy), bằng cách sử dụng patchelf . Tât cả nhưng điêu bạn phải lam la:

$ ./patchelf --set-interpreter /path/to/newglibc/ld-linux.so.2 --set-rpath /path/to/newglibc/ myapp

Và sau đó, bạn có thể thực hiện tệp của mình:

$ ./myapp

Không cần chroothoặc chỉnh sửa thủ công nhị phân, rất may. Nhưng hãy nhớ sao lưu nhị phân của bạn trước khi vá nó, nếu bạn không chắc chắn mình đang làm gì, vì nó sửa đổi tệp nhị phân của bạn. Sau khi bạn vá nó, bạn không thể khôi phục đường dẫn cũ đến trình thông dịch / rpath. Nếu nó không hoạt động, bạn sẽ phải tiếp tục vá nó cho đến khi bạn tìm thấy đường dẫn thực sự hoạt động ... Chà, đó không phải là một quá trình thử và sai. Ví dụ, trong ví dụ của OP, anh ta cần GLIBC_2.3, vì vậy bạn có thể dễ dàng tìm thấy lib nào cung cấp phiên bản đó bằng cách sử dụng strings:

$ strings /lib/i686/libc.so.6 | grep GLIBC_2.3
$ strings /path/to/newglib/libc.so.6 | grep GLIBC_2.3

Về lý thuyết, grep đầu tiên sẽ trống vì libc hệ thống không có phiên bản anh ta muốn và phiên bản thứ hai sẽ xuất GLIBC_2.3 vì nó có phiên bản myappđang sử dụng, vì vậy chúng tôi biết chúng tôi có thểpatchelf sử dụng đường dẫn nhị phân đó.

Khi bạn cố chạy một tệp nhị phân trong linux, tệp nhị phân sẽ cố gắng tải trình liên kết, sau đó là các thư viện và tất cả chúng phải nằm trong đường dẫn và / hoặc ở đúng vị trí. Nếu vấn đề của bạn là với trình liên kết và bạn muốn tìm ra đường dẫn nào mà nhị phân của bạn đang tìm kiếm, bạn có thể tìm hiểu bằng lệnh này:

$ readelf -l myapp | grep interpreter
  [Requesting program interpreter: /lib/ld-linux.so.2]                                                                                                                                                                                   

Nếu vấn đề của bạn là với các lib, các lệnh sẽ cung cấp cho bạn các lib đang được sử dụng là:

$ readelf -d myapp | grep Shared
$ ldd myapp 

Điều này sẽ liệt kê các lib mà nhu cầu nhị phân của bạn cần, nhưng có lẽ bạn đã biết những vấn đề rắc rối, vì chúng đã gây ra lỗi như trong trường hợp của OP.

"Patchelf" hoạt động cho nhiều vấn đề khác nhau mà bạn có thể gặp phải khi cố gắng chạy một chương trình, liên quan đến 2 vấn đề này. Ví dụ: nếu bạn nhận được : ELF file OS ABI invalid, nó có thể được sửa bằng cách đặt trình tải mới ( --set-interpreterphần của lệnh) như tôi giải thích ở đây . Một ví dụ khác là về vấn đề nhận được No such file or directorykhi bạn chạy một tệp có ở đó và có thể thực thi được, như được minh họa ở đây . Trong trường hợp cụ thể đó, OP đã thiếu một liên kết đến trình tải, nhưng có thể trong trường hợp của bạn, bạn không có quyền truy cập root và không thể tạo liên kết. Đặt một thông dịch viên mới sẽ giải quyết vấn đề của bạn.

Cảm ơn việc làm của Nga và Michael Pankov cho cái nhìn sâu sắc và giải pháp!


1
Điều này là hữu ích nhất! Tôi đã vá nhị phân python để sử dụng glibc mới cho tenorflow
faizan

Đây là một giải pháp gọn gàng (trước đây tôi chưa biết patchelf), nhưng cụm từ "Không cần ... chỉnh sửa nhị phân" có thể gây hiểu nhầm đôi chút (vì bạn thực sự đang chỉnh sửa nhị phân của mình).
larsks

Ở đó, cố định. ;)
msb

Tiện ích thực sự hữu ích! Cảm ơn bạn! Mặc dù tôi chỉ có thể nhận được lỗi phân đoạn sau nhiều giờ giải quyết phụ thuộc thủ công sau đó vá mọi thứ để cài đặt chrome cục bộ mà không có đặc quyền quản trị viên ...
G. Bergeron

@fgiraldeau cảm ơn vì lời khen. :) nhưng câu hỏi đã được hỏi, trả lời và chấp nhận vào năm 2009, tôi sẽ không mong đợi ai đó đợi 8 năm trước khi chấp nhận câu trả lời. heheh; D
msb

20

Sử dụng LD_PRELOAD: đặt thư viện của bạn ở đâu đó ra khỏi thư mục lib của người đàn ông và chạy:

LD_PRELOAD='mylibc.so anotherlib.so' program

Xem: bài viết Wikipedia


1
nghĩ rằng đây sẽ là một cách giải quyết tốt cho một Makefile phức tạp, nhưng nó không hoạt động với tôi
galactica

đó là hữu ích đặc biệt là những người không có nguồn nhị phân. Cảm ơn
viên

2
ừm ... tôi đã nhầm ,, có vẻ như tôi cần rpath ld-linux.so đến / path / to / new / lib / frist trong khi biên dịch và liên kết nguồn
coder

1
Điều này không hoạt động nếu ld - #. ##. Vì vậy (từ hệ thống glibc lib của bạn) không phải là phiên bản glibc giống như libc.so. # (từ lib glibc thay thế của bạn)
Andy

12

Trước hết, sự phụ thuộc quan trọng nhất của mỗi chương trình được liên kết động là trình liên kết. Tất cả các thư viện phải phù hợp với phiên bản của trình liên kết.

Chúng ta hãy lấy ví dụ đơn giản: Tôi có hệ thống Ubuntu mới, nơi tôi chạy một số chương trình (trong trường hợp của tôi là trình biên dịch D - ldc2). Tôi muốn chạy nó trên CentOS cũ, nhưng vì thư viện glibc cũ hơn nên không thể. tôi đã nhận

ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.15' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2)
ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2)

Tôi phải sao chép tất cả các phụ thuộc từ ubfox sang centos. Phương pháp thích hợp là như sau:

Trước tiên, hãy kiểm tra tất cả các phụ thuộc:

ldd ldc2-1.5.0-linux-x86_64/bin/ldc2 
    linux-vdso.so.1 =>  (0x00007ffebad3f000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f965f597000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f965f378000)
    libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f965f15b000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f965ef57000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f965ec01000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f965e9ea000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f965e60a000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f965f79f000)

linux-vdso.so.1 không phải là một thư viện thực sự và chúng tôi không phải quan tâm đến nó.

/lib64/ld-linux-x86-64.so.2 là trình liên kết, được sử dụng bởi linux để liên kết thực thi với tất cả các thư viện động.

Phần còn lại của các tệp là các thư viện thực và tất cả chúng cùng với trình liên kết phải được sao chép ở đâu đó trong centos.

Giả sử tất cả các thư viện và trình liên kết đều nằm trong thư mục "/ mylibs".

ld-linux-x86-64.so.2 - như tôi đã nói - là trình liên kết. Đó không phải là thư viện động mà là thực thi tĩnh. Bạn có thể chạy nó và thấy rằng nó thậm chí có một số tham số, ví dụ: đường dẫn thư viện (tôi sẽ quay lại nó).

Trên linux, chương trình được liên kết động có thể được ăn trưa chỉ bằng tên của nó, vd

/bin/ldc2

Linux tải chương trình đó vào RAM và kiểm tra trình liên kết nào được đặt cho nó. Thông thường, trên hệ thống 64 bit, nó là /lib64/ld-linux-x86-64.so.2 (trong hệ thống tệp của bạn, nó là liên kết tượng trưng đến thực thi thực tế). Sau đó, linux chạy trình liên kết và nó tải các thư viện động.

Bạn cũng có thể thay đổi điều này một chút và thực hiện thủ thuật như vậy:

/mylibs/ld-linux-x86-64.so.2 /bin/ldc2

Đây là phương pháp buộc linux sử dụng trình liên kết cụ thể.

Và bây giờ chúng ta có thể quay lại tham số đã đề cập trước đó - đường dẫn thư viện

/mylibs/ld-linux-x86-64.so.2 --library-path /mylibs /bin/ldc2

Nó sẽ chạy ldc2 và tải các thư viện động từ / mylibs.

Đây là phương pháp để gọi tệp thực thi với các thư viện choosen (không phải mặc định hệ thống).


Tôi đã biên dịch một chương trình trên RH7 và cần nó để chạy trên RH6. Tôi không muốn xây dựng một tệp thực thi mới hoặc sử dụng patchelf, vì vậy đây là một giải pháp thay thế tuyệt vời.
Mark Rajcok

9

Thiết lập 1: biên dịch glibc của riêng bạn mà không cần GCC chuyên dụng và sử dụng nó

Thiết lập này có thể hoạt động và nhanh chóng vì nó không biên dịch lại toàn bộ chuỗi công cụ GCC, chỉ là glibc.

Nhưng nó không phải là đáng tin cậy như nó sử dụng các đối tượng máy chủ C runtime như crt1.o, crti.ocrtn.ođược cung cấp bởi glibc. Điều này được đề cập tại: https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location Những đối tượng đó thiết lập sớm mà glibc dựa vào, vì vậy tôi sẽ không ngạc nhiên và những cách tinh tế khủng khiếp.

Để có một thiết lập đáng tin cậy hơn, xem Thiết lập 2 bên dưới.

Xây dựng glibc và cài đặt cục bộ:

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`

Thiết lập 1: xác minh bản dựng

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.
     * /programming/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);
}

Biên dịch và chạy với 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

Chương trình đưa ra dự kiến:

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

Lệnh được điều chỉnh từ https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location nhưng --sysrootđã thất bại với:

cannot find /home/ciro/glibc/build/install/lib/libc.so.6 inside /home/ciro/glibc/build/install

Vì vậy, tôi loại bỏ nó.

lddđầu ra xác nhận rằng lddvà các thư viện mà chúng tôi vừa xây dựng đang thực sự được sử dụng như mong đợi:

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

Đầu gccra gỡ lỗi biên dịch cho thấy các đối tượng thời gian chạy máy chủ của tôi đã được sử dụng, điều này rất tệ như đã đề cập trước đây, nhưng tôi không biết cách làm việc xung quanh nó, ví dụ như nó chứa:

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

Thiết lập 1: sửa đổi glibc

Bây giờ hãy sửa đổi glibc với:

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

Sau đó biên dịch lại và cài đặt lại glibc, đồng thời biên dịch lại và chạy lại chương trình của chúng tôi:

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

và chúng tôi thấy hackedđược in một vài lần như mong đợi.

Điều này tiếp tục xác nhận rằng chúng tôi thực sự đã sử dụng glibc mà chúng tôi đã biên dịch chứ không phải máy chủ lưu trữ.

Đã thử nghiệm trên Ubuntu 18.04.

Thiết lập 2: thiết lập nguyên sơ crosstool-NG

Đây là một thay thế cho thiết lập 1, và nó là thiết lập đúng nhất mà tôi đã đạt được cho đến nay: mọi thứ đều đúng như xa như tôi có thể quan sát, bao gồm thời gian chạy C đối tượng như crt1.o, crti.o, vàcrtn.o .

Trong thiết lập này, chúng tôi sẽ biên dịch một chuỗi công cụ GCC chuyên dụng đầy đủ sử dụng glibc mà chúng tôi muốn.

Nhược điểm duy nhất của phương pháp này là việc xây dựng sẽ mất nhiều thời gian hơn. Nhưng tôi sẽ không mạo hiểm thiết lập sản xuất với bất cứ điều gì ít hơn.

xuyên âm-NG là một tập hợp các tập lệnh tải xuống và biên dịch mọi thứ từ nguồn cho chúng tôi, bao gồm GCC, glibc và binutils.

Có, hệ thống xây dựng GCC tệ đến mức chúng ta cần một dự án riêng cho việc đó.

Thiết lập này chỉ không hoàn hảo vì crosstool-NG không hỗ trợ xây dựng các tệp thực thi mà không có -Wlcờ bổ sung , điều này cảm thấy kỳ lạ vì chúng tôi đã tự xây dựng GCC. Nhưng mọi thứ dường như hoạt động, vì vậy đây chỉ là một sự bất tiện.

Nhận crosstool-NG, cấu hình và xây dựng nó:

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`

Việc xây dựng mất khoảng ba mươi phút đến hai giờ.

Tùy chọn cấu hình bắt buộc duy nhất mà tôi có thể thấy, làm cho nó khớp với phiên bản kernel của máy chủ để sử dụng các tiêu đề kernel chính xác. Tìm phiên bản kernel của máy chủ với:

uname -a

cho tôi thấy:

4.15.0-34-generic

vì vậy trong menuconfigtôi làm:

  • Operating System
    • Version of linux

vì vậy tôi chọn:

4.14.71

đó là phiên bản đầu tiên bằng hoặc cũ hơn. Nó phải cũ hơn vì kernel tương thích ngược.

Thiết lập 2: cấu hình tùy chọn

Cái .configmà chúng tôi tạo ra ./ct-ng x86_64-unknown-linux-gnucó:

CT_GLIBC_V_2_27=y

Để thay đổi điều đó, menuconfighãy làm:

  • C-library
  • Version of glibc

lưu .configvà tiếp tục xây dựng

Hoặc, nếu bạn muốn sử dụng nguồn glibc của riêng mình, ví dụ: để sử dụng glibc từ git mới nhất, hãy tiếp tục như sau :

  • Paths and misc options
    • Try features marked as EXPERIMENTAL: đặt thành đúng
  • C-library
    • Source of glibc
      • Custom location: nói có
      • Custom location
        • Custom source location: trỏ đến một thư mục chứa nguồn glibc của bạn

nơi glibc được nhân bản là:

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

Thiết lập 2: kiểm tra nó

Khi bạn đã xây dựng anh ấy toolchain mà bạn muốn, hãy thử nghiệm nó với:

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

Mọi thứ dường như hoạt động như trong Thiết lập 1, ngoại trừ việc bây giờ các đối tượng thời gian chạy chính xác đã được sử dụng:

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

Thiết lập 2: thất bại trong quá trình biên dịch lại glibc hiệu quả

Dường như không thể với crosstool-NG, như được giải thích dưới đây.

Nếu bạn chỉ xây dựng lại;

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

sau đó, các thay đổi của bạn đối với vị trí nguồn glibc tùy chỉnh sẽ được tính đến, nhưng nó xây dựng mọi thứ từ đầu, khiến nó không thể sử dụng để phát triển lặp.

Nếu chúng ta làm:

./ct-ng list-steps

nó cung cấp một cái nhìn tổng quan tốt đẹp về các bước xây dựng:

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.

do đó, chúng tôi thấy rằng có các bước glibc đan xen với một số bước GCC, đáng chú ý nhất là libc_start_filestrước đây cc_core_pass_2, đây có thể là bước đắt nhất cùng vớicc_core_pass_1 .

Để xây dựng chỉ một bước, trước tiên bạn phải đặt .configtùy chọn "Lưu các bước trung gian" trong tùy chọn cho bản dựng nội bộ:

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

và sau đó bạn có thể thử:

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

nhưng thật không may, +yêu cầu như được đề cập tại: https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536

Tuy nhiên, lưu ý rằng khởi động lại ở bước trung gian sẽ đặt lại thư mục cài đặt về trạng thái của nó trong bước đó. Tức là, bạn sẽ có một libc được xây dựng lại - nhưng không có trình biên dịch cuối cùng được xây dựng với libc này (và do đó, không có thư viện trình biên dịch nào như libstdc ++).

và về cơ bản vẫn làm cho việc xây dựng lại quá chậm để có thể khả thi để phát triển và tôi không thấy cách khắc phục điều này mà không vá crosstool-NG.

Hơn nữa, bắt đầu từ libcbước dường như không sao chép lại nguồn từ đó Custom source location, hơn nữa làm cho phương pháp này không thể sử dụng được.

Tiền thưởng: stdlibc ++

Phần thưởng nếu bạn cũng quan tâm đến thư viện chuẩn C ++: Làm cách nào để chỉnh sửa và xây dựng lại nguồn thư viện chuẩn GCC libstdc ++ C ++?


6

Bạn có thể xem xét sử dụng Nix http://nixos.org/nix/ không?

Nix hỗ trợ quản lý gói nhiều người dùng: nhiều người dùng có thể chia sẻ một cửa hàng Nix chung một cách an toàn, không cần có quyền root để cài đặt phần mềm và có thể cài đặt và sử dụng các phiên bản khác nhau của gói.


4

@msb đưa ra giải pháp an toàn.

Tôi đã gặp vấn đề này khi tôi làm import tensorflow as tftrong môi trường conda CentOS 6.5chỉ có glibc-2.12.

ImportError: /lib64/libc.so.6: version `GLIBC_2.16' not found (required by /home/

Tôi muốn cung cấp một số chi tiết:

Đầu tiên cài đặt glibcvào thư mục nhà của bạn:

mkdir ~/glibc-install; cd ~/glibc-install
wget http://ftp.gnu.org/gnu/glibc/glibc-2.17.tar.gz
tar -zxvf glibc-2.17.tar.gz
cd glibc-2.17
mkdir build
cd build
../configure --prefix=/home/myself/opt/glibc-2.17  # <-- where you install new glibc
make -j<number of CPU Cores>  # You can find your <number of CPU Cores> by using **nproc** command
make install

Thứ hai, làm theo cùng một cách để cài đặt patchelf ;

Thứ ba, vá Python của bạn:

[myself@nfkd ~]$ patchelf --set-interpreter /home/myself/opt/glibc-2.17/lib/ld-linux-x86-64.so.2 --set-rpath /home/myself/opt/glibc-2.17/lib/ /home/myself/miniconda3/envs/tensorflow/bin/python

như được đề cập bởi @msb

Bây giờ tôi có thể sử dụng tensorflow-2.0 alphatrongCentOS 6.5 .

ref: https://serverkurma.com/linux/how-to-update-glibc-newer-version-on-centos-6-x/


2

Tôi không chắc chắn rằng câu hỏi vẫn còn liên quan, nhưng có một cách khác để khắc phục vấn đề: Docker. Người ta có thể cài đặt một thùng chứa gần như trống của Phân phối nguồn (Phân phối được sử dụng để phát triển) và sao chép các tệp vào Container. Bằng cách đó, bạn không cần tạo hệ thống tập tin cần thiết cho chroot.


1

Nếu bạn nhìn kỹ vào đầu ra thứ hai, bạn có thể thấy rằng vị trí mới cho các thư viện được sử dụng. Có lẽ vẫn còn thiếu các thư viện là một phần của glibc.

Tôi cũng nghĩ rằng tất cả các thư viện được sử dụng bởi chương trình của bạn nên được biên dịch theo phiên bản glibc đó. Nếu bạn có quyền truy cập vào mã nguồn của chương trình, một phần tổng hợp mới dường như là giải pháp tốt nhất.


1

"Tiếng Nga có việc làm" là một trong những câu trả lời hay nhất và tôi nghĩ tất cả các câu trả lời được đề xuất khác có thể không hoạt động. Lý do đơn giản là vì khi một ứng dụng được tạo lần đầu tiên, tất cả các API mà nó cần sẽ được giải quyết tại thời điểm biên dịch. Sử dụng "ldd" u có thể thấy tất cả các phụ thuộc được liên kết tĩnh:

ldd /usr/lib/firefox/firefox
    linux-vdso.so.1 =>  (0x00007ffd5c5f0000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f727e708000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f727e500000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f727e1f8000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f727def0000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f727db28000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f727eb78000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f727d910000)

Nhưng trong thời gian chạy, firefox cũng sẽ tải nhiều thư viện động khác, ví dụ (đối với firefox) có nhiều thư viện được viết bằng chữ "glib" được tải (mặc dù không có liên kết tĩnh nào):

 /usr/lib/x86_64-linux-gnu/libdbus-glib-1.so.2.2.2
 /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0
 /usr/lib/x86_64-linux-gnu/libavahi-glib.so.1.0.2

Nhiều lần, bạn có thể thấy tên của một phiên bản được liên kết mềm thành phiên bản khác. Ví dụ:

lrwxrwxrwx 1 root root     23 Dec 21  2014 libdbus-glib-1.so.2 -> libdbus-glib-1.so.2.2.2
-rw-r--r-- 1 root root 160832 Mar  1  2013 libdbus-glib-1.so.2.2.2

Do đó, điều này có nghĩa là phiên bản "thư viện" khác nhau tồn tại trong một hệ thống - đây không phải là vấn đề vì nó là cùng một tệp và nó sẽ cung cấp tính tương thích khi các ứng dụng có nhiều phụ thuộc phiên bản.

Do đó, ở cấp độ hệ thống, tất cả các thư viện gần như phụ thuộc lẫn nhau và chỉ thay đổi mức độ ưu tiên tải thư viện thông qua thao tác LD_PRELOAD hoặc LD_LIBRARY_PATH sẽ không giúp ích - ngay cả khi nó có thể tải, thời gian chạy vẫn có thể bị sập.

http://lightofdawn.org/wiki/wiki.cgi/-wiki/NewAppsOnOldGlibc

Thay thế tốt nhất là chroot (được đề cập ngắn gọn bởi ER): nhưng đối với điều này, bạn sẽ cần tạo lại toàn bộ môi trường trong đó thực thi nhị phân ban đầu - thường bắt đầu từ / lib, / usr / lib /, / usr / lib / x86, v.v. Bạn có thể sử dụng "Buildroot" hoặc YoctoProject hoặc chỉ tar từ môi trường Distro hiện có. (như Fedora / Suse, v.v.).


0

Khi tôi muốn chạy trình duyệt crom trên Ubuntu chính xác (glibc-2.15), tôi đã nhận được thông báo (điển hình) "... libc.so.6: phiên bản` GLIBC_2.19 'không tìm thấy ... ". Tôi đã xem xét thực tế rằng các tập tin không cần thiết một cách vĩnh viễn, mà chỉ để bắt đầu. Vì vậy, tôi đã thu thập các tệp cần thiết cho trình duyệt và sudo và tạo môi trường mini-glibc-2.19-, khởi động trình duyệt và sau đó sao chép lại các tệp gốc. Các tập tin cần thiết là trong RAM và glibc ban đầu là như nhau.

as root
the files (*-2.15.so) already exist 

mkdir -p /glibc-2.19/i386-linux-gnu

/glibc-2.19/ld-linux.so.2 -> /glibc-2.19/i386-linux-gnu/ld-2.19.so
/glibc-2.19/i386-linux-gnu/libc.so.6 -> libc-2.19.so
/glibc-2.19/i386-linux-gnu/libdl.so.2 -> libdl-2.19.so
/glibc-2.19/i386-linux-gnu/libpthread.so.0 -> libpthread-2.19.so

mkdir -p /glibc-2.15/i386-linux-gnu

/glibc-2.15/ld-linux.so.2 -> (/glibc-2.15/i386-linux-gnu/ld-2.15.so)
/glibc-2.15/i386-linux-gnu/libc.so.6 -> (libc-2.15.so)
/glibc-2.15/i386-linux-gnu/libdl.so.2 -> (libdl-2.15.so)
/glibc-2.15/i386-linux-gnu/libpthread.so.0 -> (libpthread-2.15.so)

tập lệnh để chạy trình duyệt:

#!/bin/sh
sudo cp -r /glibc-2.19/* /lib
/path/to/the/browser &
sleep 1
sudo cp -r /glibc-2.15/* /lib
sudo rm -r /lib/i386-linux-gnu/*-2.19.so
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.