Setup 1: kompilasi glibc Anda sendiri tanpa GCC khusus dan gunakan
Penyiapan ini mungkin berfungsi dan cepat karena tidak mengkompilasi ulang seluruh rantai alat GCC, hanya glibc.
Tapi itu tidak dapat diandalkan karena menggunakan tuan C runtime objek seperti crt1.o
, crti.o
, dan crtn.o
disediakan oleh glibc. Ini disebutkan di: https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location Benda-benda itu melakukan penyetelan awal yang bergantung pada glibc, jadi saya tidak akan terkejut jika ada hal-hal yang terjadi pada glibc, dan cara-cara yang sangat halus.
Untuk pengaturan yang lebih andal, lihat Pengaturan 2 di bawah ini.
Bangun glibc dan instal secara lokal:
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`
Setup 1: verifikasi 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.
* /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);
}
Kompilasi dan jalankan dengan 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
Program menghasilkan yang diharapkan:
gnu_get_libc_version() = 2.28
The atomic counter is 10000
The non-atomic counter is 8674
Perintah diadaptasi dari https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location tetapi --sysroot
membuatnya gagal dengan:
cannot find /home/ciro/glibc/build/install/lib/libc.so.6 inside /home/ciro/glibc/build/install
jadi saya menghapusnya.
ldd
output mengonfirmasi bahwa ldd
pustaka dan yang baru saja kita bangun sebenarnya digunakan seperti yang diharapkan:
+ 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)
The gcc
kompilasi men-debug output yang menunjukkan bahwa host saya objek runtime yang digunakan, yang buruk seperti yang disebutkan sebelumnya, tapi saya tidak tahu bagaimana bekerja di sekitarnya, misalnya mengandung:
COLLECT_GCC_OPTIONS=/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crt1.o
Pengaturan 1: modifikasi glibc
Sekarang mari kita ubah glibc dengan:
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)");
Kemudian mengkompilasi ulang dan menginstal ulang glibc, dan mengkompilasi ulang dan menjalankan kembali program kami:
cd glibc/build
make -j `nproc`
make -j `nproc` install
./test_glibc.sh
dan kami melihat hacked
dicetak beberapa kali seperti yang diharapkan.
Ini lebih lanjut menegaskan bahwa kami benar-benar menggunakan glibc yang kami kompilasi dan bukan yang host.
Diuji pada Ubuntu 18.04.
Pengaturan 2: pengaturan murni crosstool-NG
Ini adalah sebuah alternatif untuk setup 1, dan itu adalah setup yang benar yang paling saya telah mencapai jauh: semuanya sudah benar sejauh yang saya dapat mengamati, termasuk runtime C objek seperti crt1.o
, crti.o
, dancrtn.o
.
Dalam pengaturan ini, kami akan mengkompilasi toolchain GCC khusus yang menggunakan glibc yang kami inginkan.
Satu-satunya downside ke metode ini adalah bahwa pembangunan akan memakan waktu lebih lama. Tapi saya tidak akan mengambil risiko setup produksi dengan sesuatu yang kurang.
crosstool-NG adalah sekumpulan skrip yang mengunduh dan mengkompilasi semuanya dari sumber untuk kita, termasuk GCC, glibc dan binutils.
Ya sistem build GCC sangat buruk sehingga kami membutuhkan proyek terpisah untuk itu.
Pengaturan ini hanya tidak sempurna karena crosstool-NG tidak mendukung pembuatan executable tanpa -Wl
flag tambahan , yang terasa aneh karena kami telah membangun GCC sendiri. Tapi semuanya sepertinya berhasil, jadi ini hanya ketidaknyamanan.
Dapatkan crosstool-NG, konfigurasikan dan bangun:
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`
Pembangunan memakan waktu sekitar tiga puluh menit hingga dua jam.
Satu-satunya opsi konfigurasi wajib yang dapat saya lihat, adalah membuatnya cocok dengan versi kernel host Anda untuk menggunakan header kernel yang benar. Temukan versi kernel host Anda dengan:
uname -a
yang menunjukkan saya:
4.15.0-34-generic
jadi di menuconfig
saya lakukan:
jadi saya pilih:
4.14.71
yang merupakan versi sama atau lebih tua pertama. Itu harus lebih tua karena kernel kompatibel.
Setup 2: konfigurasi opsional
Yang .config
kami hasilkan ./ct-ng x86_64-unknown-linux-gnu
memiliki:
CT_GLIBC_V_2_27=y
Untuk mengubahnya, menuconfig
lakukan:
C-library
Version of glibc
Selamatkan .config
, dan lanjutkan dengan membangun.
Atau, jika Anda ingin menggunakan sumber glibc Anda sendiri, misalnya untuk menggunakan glibc dari git terbaru, lanjutkan seperti ini :
Paths and misc options
Try features marked as EXPERIMENTAL
: disetel ke true
C-library
Source of glibc
Custom location
: bilang iya
Custom location
Custom source location
: arahkan ke direktori yang mengandung sumber glibc Anda
di mana glibc dikloning sebagai:
git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.28
Setup 2: ujilah
Setelah Anda membangun rantai alat yang Anda inginkan, ujilah dengan:
#!/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
Semuanya tampaknya berfungsi seperti dalam Pengaturan 1, kecuali bahwa sekarang objek runtime yang benar digunakan:
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
Penyiapan 2: upaya rekompilasi glibc gagal yang efisien
Tampaknya tidak mungkin dengan crosstool-NG, seperti yang dijelaskan di bawah ini.
Jika Anda hanya membangun kembali;
env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`
maka perubahan Anda ke lokasi sumber glibc khusus diperhitungkan, tetapi itu membangun semuanya dari awal, sehingga tidak dapat digunakan untuk pengembangan berulang.
Jika kita melakukannya:
./ct-ng list-steps
ini memberikan gambaran bagus tentang langkah-langkah pembuatan:
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.
oleh karena itu, kita melihat bahwa ada langkah-langkah glibc yang terkait dengan beberapa langkah GCC, terutama libc_start_files
datang sebelumnya cc_core_pass_2
, yang kemungkinan merupakan langkah paling mahal bersama dengancc_core_pass_1
.
Untuk membangun hanya satu langkah, Anda harus terlebih dahulu mengatur opsi "Simpan langkah-langkah lanjutan" di .config
untuk membangun awal:
dan kemudian Anda dapat mencoba:
env -u LD_LIBRARY_PATH time ./ct-ng libc+ -j`nproc`
tapi sayangnya, +
diperlukan seperti yang disebutkan di: https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536
Namun perlu dicatat bahwa memulai kembali pada langkah menengah me-reset direktori instalasi ke keadaan selama langkah itu. Yaitu, Anda akan memiliki libc yang dibangun kembali - tetapi tidak ada kompiler akhir yang dibangun dengan libc ini (dan karenanya, tidak ada perpustakaan kompiler seperti libstdc ++ juga).
dan pada dasarnya masih membuat pembangunan kembali terlalu lambat untuk dapat dikembangkan, dan saya tidak melihat cara mengatasinya tanpa menambal crosstool-NG.
Lebih jauh lagi, mulai dari libc
langkah sepertinya tidak menyalin dari sumber lagi dari Custom source location
, lebih lanjut membuat metode ini tidak dapat digunakan.
Bonus: stdlibc ++
Bonus jika Anda juga tertarik dengan pustaka standar C ++: Bagaimana cara mengedit dan membangun kembali sumber libstdc GCC ++ C ++ standar?