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.o
và crtn.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 ldd
và 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 gcc
ra 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ó -Wl
cờ 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 menuconfig
tôi làm:
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 .config
mà chúng tôi tạo ra ./ct-ng x86_64-unknown-linux-gnu
có:
CT_GLIBC_V_2_27=y
Để thay đổi điều đó, menuconfig
hãy làm:
C-library
Version of glibc
lưu .config
và 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_files
trướ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 .config
tùy chọn "Lưu các bước trung gian" trong tùy chọn cho bản dựng nội bộ:
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ừ libc
bướ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 ++?