Целевые триплеты описывают платформу, на которой выполняется код, и являются основной концепцией системы сборки GNU. Обычно триплет содержит три поля: название семейства/модели CPU, поставщика и имя операционной системы. Кроме того, триплет может иметь дополнительное поле, отражающее Application Binary Interface (ABI), например: gnu, gnueabihf, gnu_ilp32.
Просмотреть целевой триплет текущей системы можно с помощью команды `gcc -dumpmachine’:
gcc -dumpmachine x86_64-slackware-linux
Если вы создаете новую систему или собственный GNU/Linux дистрибутив, у вас может возникнуть необходимость иметь собственный целевой триплет. Например, x86_64-radix-linux-gnu для CPU Intel или AMD.
При создании инструментария (toolchain-а) на базе GCC все выглядит элементарно. Достаточно сконфигурировать binutils с опцией —enable-targets=x86_64-radix-linux-gnu. Однако добавление собственного триплета компиляторов LLVM и Rust выглядит уже не совсем тривиально.
Здесь мы рассмотрим добавление нового триплета инструментария языка Rust.
Прежде всего необходимо загрузить исходный код:
git clone https://github.com/rust-lang/rust.git rust-1.82.0 ( cd rust-1.82.0 git checkout -b 1.82.0 tags/1.82.0 git submodule update --init --recursive )
Поскольку репозиторий исходного кода Rust содержит исходный код проекта LLVM, мы сможем одновременно рассмотреть добавление нового триплета и для случая LLVM, и для случая Rust.
LLVM Project
Итак, для того чтобы добавить новый триплет компилятору clang нам необходимо внести изменения в файлы:
rust-1.82.0/src/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp rust-1.82.0/src/llvm-project/llvm/include/llvm/TargetParser/Triple.h rust-1.82.0/src/llvm-project/llvm/lib/TargetParser/Triple.cpp
Патч для Rust 1.82.0 представлен на следующем листинге:
diff --unified -Nr rust-1.82.0-orig/src/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp rust-1.82.0/src/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp --- rust-1.82.0-orig/src/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp2024-11-10 22:33:14.000000000 +0300 +++ rust-1.82.0/src/llvm-project/clang/lib/Driver/ToolChains/Gnu.cpp2024-11-11 01:34:23.586151730 +0300 @@ -2491,7 +2491,7 @@ "x86_64-linux-gnu", "x86_64-unknown-linux-gnu", "x86_64-pc-linux-gnu", "x86_64-redhat-linux6E", "x86_64-redhat-linux", "x86_64-suse-linux", - "x86_64-manbo-linux-gnu", "x86_64-slackware-linux", + "x86_64-manbo-linux-gnu", "x86_64-slackware-linux", "x86_64-radix-linux-gnu", "x86_64-unknown-linux", "x86_64-amazon-linux"}; static const char *const X32Triples[] = {"x86_64-linux-gnux32", "x86_64-pc-linux-gnux32"}; diff --unified -Nr rust-1.82.0-orig/src/llvm-project/llvm/include/llvm/TargetParser/Triple.h rust-1.82.0/src/llvm-project/llvm/include/llvm/TargetParser/Triple.h --- rust-1.82.0-orig/src/llvm-project/llvm/include/llvm/TargetParser/Triple.h2024-11-10 22:33:17.000000000 +0300 +++ rust-1.82.0/src/llvm-project/llvm/include/llvm/TargetParser/Triple.h2024-11-11 01:34:23.585151730 +0300 @@ -183,6 +183,7 @@ Apple, PC, + Radix, SCEI, Freescale, IBM, diff --unified -Nr rust-1.82.0-orig/src/llvm-project/llvm/lib/TargetParser/Triple.cpp rust-1.82.0/src/llvm-project/llvm/lib/TargetParser/Triple.cpp --- rust-1.82.0-orig/src/llvm-project/llvm/lib/TargetParser/Triple.cpp2024-11-10 22:33:17.000000000 +0300 +++ rust-1.82.0/src/llvm-project/llvm/lib/TargetParser/Triple.cpp2024-11-11 01:34:23.585151730 +0300 @@ -251,6 +251,7 @@ case NVIDIA: return "nvidia"; case OpenEmbedded: return "oe"; case PC: return "pc"; + case Radix: return "radix"; case SCEI: return "scei"; case SUSE: return "suse"; } @@ -625,6 +626,7 @@ return StringSwitch(VendorName) .Case("apple", Triple::Apple) .Case("pc", Triple::PC) + .Case("radix", Triple::Radix) .Case("scei", Triple::SCEI) .Case("sie", Triple::SCEI) .Case("fsl", Triple::Freescale)
Первый файл содержит массивы имен целевых триплетов для различных архитектур CPU, и здесь мы добавили наш триплет в массив X86_64Triples[].
Остальные два файла необходимо редактировать на случай того, если вы захотите изменять некоторые величины динамически, во время сборки LLVM. Например, в зависимости от имени операционной системы в триплете, выбирать путь к интерпретатору:
if (Triple.getVendor() == llvm::Triple::Radix ) { LibDir = X32 ? "libx32" : "lib"; } else { LibDir = X32 ? "libx32" : "lib64"; } Loader = X32 ? "ld-linux-x32.so.2" : "ld-linux-x86-64.so.2";
Здесь переменная Triple.getVendor() содержит текущее имя системы и вы всегда можете сравнивать его с тем именем, для которого необходимо выполнить определенные действия.
Rust Compiler
Итак, мы добавили новый триплет в проект LLVM. Теперь необходимо изменить еще несколько файлов, но уже непосредственно для компилятора Rust:
rust-1.82.0/compiler/rustc_target/src/spec/mod.rs rust-1.82.0/library/std/Cargo.toml rust-1.82.0/src/bootstrap/src/core/sanity.rs
И кроме того, в каталог rust-1.82.0/compiler/rustc_target/src/spec/targets/, добавить файл описания целевой архитектуры, соотвествующей новому триплету:
x86_64_radix_linux_gnu.rs:
use crate::spec::{base, Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target}; pub fn target() -> Target { let mut base = base::linux_gnu::opts(); base.cpu = "x86-64".into(); base.plt_by_default = false; base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.stack_probes = StackProbeType::Inline; base.static_position_independent_executables = true; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::KCFI | SanitizerSet::DATAFLOW | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::SAFESTACK | SanitizerSet::THREAD; base.supports_xray = true; // When we're asked to use the `rust-lld` linker by default, set the appropriate lld-using // linker flavor, and self-contained linker component. if option_env!("CFG_USE_SELF_CONTAINED_LINKER").is_some() { base.linker_flavor = LinkerFlavor::Gnu(Cc::Yes, Lld::Yes); base.link_self_contained = crate::spec::LinkSelfContainedDefault::with_linker(); } Target { llvm_target: "x86_64-radix-linux-gnu".into(), metadata: crate::spec::TargetMetadata { description: Some("64-bit Linux (kernel 3.2+, glibc 2.17+)".into()), tier: Some(1), host_tools: Some(true), std: Some(true), }, pointer_width: 64, data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), arch: "x86_64".into(), options: base, } }
В случае x86_64 создание такого файла достаточно просто, его содержимое можно скопировать из файла x86_64_unknown_linux_gnu.rs и изменить в нем имя триплета на x86_64-radix-linux-gnu.
Патч для Rust 1.82.0 представлен на следующем листинге:
diff --unified -Nr rust-1.82.0-orig/compiler/rustc_target/src/spec/mod.rs rust-1.82.0/compiler/rustc_target/src/spec/mod.rs --- rust-1.82.0-orig/compiler/rustc_target/src/spec/mod.rs2024-11-10 22:28:19.000000000 +0300 +++ rust-1.82.0/compiler/rustc_target/src/spec/mod.rs2024-11-11 01:47:03.927109832 +0300 @@ -1646,6 +1646,9 @@ ("i686-unknown-hurd-gnu", i686_unknown_hurd_gnu), + // RcL Triples: + ("x86_64-radix-linux-gnu", x86_64_radix_linux_gnu), + ("aarch64-apple-darwin", aarch64_apple_darwin), ("arm64e-apple-darwin", arm64e_apple_darwin), ("x86_64-apple-darwin", x86_64_apple_darwin), diff --unified -Nr rust-1.82.0-orig/compiler/rustc_target/src/spec/targets/x86_64_radix_linux_gnu.rs rust-1.82.0/compiler/rustc_target/src/spec/targets/x86_64_radix_linux_gnu.rs --- rust-1.82.0-orig/compiler/rustc_target/src/spec/targets/x86_64_radix_linux_gnu.rs1970-01-01 03:00:00.000000000 +0300 +++ rust-1.82.0/compiler/rustc_target/src/spec/targets/x86_64_radix_linux_gnu.rs2024-11-11 01:47:03.927109832 +0300 @@ -0,0 +1,42 @@ +use crate::spec::{base, Cc, LinkerFlavor, Lld, SanitizerSet, StackProbeType, Target}; + +pub fn target() -> Target { + let mut base = base::linux_gnu::opts(); + base.cpu = "x86-64".into(); + base.plt_by_default = false; + base.max_atomic_width = Some(64); + base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); + base.stack_probes = StackProbeType::Inline; + base.static_position_independent_executables = true; + base.supported_sanitizers = SanitizerSet::ADDRESS + | SanitizerSet::CFI + | SanitizerSet::KCFI + | SanitizerSet::DATAFLOW + | SanitizerSet::LEAK + | SanitizerSet::MEMORY + | SanitizerSet::SAFESTACK + | SanitizerSet::THREAD; + base.supports_xray = true; + + // When we're asked to use the `rust-lld` linker by default, set the appropriate lld-using + // linker flavor, and self-contained linker component. + if option_env!("CFG_USE_SELF_CONTAINED_LINKER").is_some() { + base.linker_flavor = LinkerFlavor::Gnu(Cc::Yes, Lld::Yes); + base.link_self_contained = crate::spec::LinkSelfContainedDefault::with_linker(); + } + + Target { + llvm_target: "x86_64-radix-linux-gnu".into(), + metadata: crate::spec::TargetMetadata { + description: Some("64-bit Linux (kernel 3.2+, glibc 2.17+)".into()), + tier: Some(1), + host_tools: Some(true), + std: Some(true), + }, + pointer_width: 64, + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), + arch: "x86_64".into(), + options: base, + } +} diff --unified -Nr rust-1.82.0-orig/library/std/Cargo.toml rust-1.82.0/library/std/Cargo.toml --- rust-1.82.0-orig/library/std/Cargo.toml2024-11-10 22:28:19.000000000 +0300 +++ rust-1.82.0/library/std/Cargo.toml2024-11-11 01:47:03.927109832 +0300 @@ -141,7 +141,7 @@ level = "warn" check-cfg = [ 'cfg(bootstrap)', - 'cfg(target_arch, values("xtensa"))', + 'cfg(target_arch, values("xtensa", "x86_64-radix-linux-gnu"))', # std use #[path] imports to portable-simd `std_float` crate # and to the `backtrace` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg diff --unified -Nr rust-1.82.0-orig/src/bootstrap/src/core/sanity.rs rust-1.82.0/src/bootstrap/src/core/sanity.rs --- rust-1.82.0-orig/src/bootstrap/src/core/sanity.rs2024-11-10 22:28:19.000000000 +0300 +++ rust-1.82.0/src/bootstrap/src/core/sanity.rs2024-11-11 01:47:03.927109832 +0300 @@ -34,6 +34,7 @@ // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap). const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined + "x86_64-radix-linux-gnu" ]; /// Minimum version threshold for libstdc++ required when using prebuilt LLVM
Make and Install
Теперь мы готовы к сборке Rust инструментария.
Сконфигурировать исходный код Rust можно с помощью следующей команды:
./configure --prefix=/opt/toolchains/RUST/1.82.0 \ --sysconfdir=/opt/toolchains/RUST/1.82.0/etc \ --disable-codegen-tests \ --disable-vendor \ --build=x86_64-unknown-linux-gnu \ --host=x86_64-unknown-linux-gnu \ --target=x86_64-unknown-linux-gnu,x86_64-radix-linux-gnu \ --enable-clang
Здесь мы выбрали стандартный целевой триплет для архитектуры x86_64, а также наш новый триплет x86_64-radix-linux-gnu.
После выполнения данной команды, будет создан файл config.toml следующего содержания:
profile = 'dist' change-id = 129295 [llvm] clang = true [build] build = 'x86_64-unknown-linux-gnu' host = ['x86_64-unknown-linux-gnu'] target = ['x86_64-unknown-linux-gnu', 'x86_64-radix-linux-gnu'] vendor = false configure-args = ['--prefix=/opt/toolchains/RUST/1.82.0', '--sysconfdir=/opt/toolchains/RUST/1.82.0/etc', '--disable-codegen-tests', '--disable-vendor', '--build=x86_64-unknown-linux-gnu', '--host=x86_64-unknown-linux-gnu', '--target=x86_64-unknown-linux-gnu,x86_64-radix-linux-gnu', '--enable-clang'] [install] prefix = '/opt/toolchains/RUST/1.82.0' sysconfdir = '/opt/toolchains/RUST/1.82.0/etc' [rust] codegen-tests = false [target.x86_64-unknown-linux-gnu] [target.x86_64-radix-linux-gnu] [dist]
Этот файл также необходимо отредактировать, добавив идентификатор изменений:
change-id = 129295
Его можно легко получить попробовав команду make, которая приведет к неудаче, но выведет на экран необходимый идентификатор. Вообще, правильный путь поиска величины change-id состоит в том, чтобы посмотреть последнюю запись ChangeInfo в файле:
rust-1.82.0/src/bootstrap/src/utils/change_tracker.rs
В приведенном выше файле config.toml мы уже сделали эти изменения.
В нашем случае, секцию [target.x86_64-radix-linux-gnu] изменять нет необходимости. Однако если вы захотите создать триплет для другой архитектуры, требующей cross-сборки, то вам будет необходимо собрать GCC-toolchain и добавить в соответствующую секцию сведения об основных утилитах, например, так:
[target.aarch64-m1000-linux-gnu] linker = '/opt/toolchains/aarch64-M1000-linux-glibc/1.11.3/bin/aarch64-m1000-linux-gnu-gcc' cc = '/opt/toolchains/aarch64-M1000-linux-glibc/1.11.3/bin/aarch64-m1000-linux-gnu-gcc' cxx = '/opt/toolchains/aarch64-M1000-linux-glibc/1.11.3/bin/aarch64-m1000-linux-gnu-g++' ar = '/opt/toolchains/aarch64-M1000-linux-glibc/1.11.3/bin/aarch64-m1000-linux-gnu-ar' ranlib = '/opt/toolchains/aarch64-M1000-linux-glibc/1.11.3/bin/aarch64-m1000-linux-gnu-ranlib'
Здесь мы не будем рассматривать тонкости создания cross-компилятора Rust.
После того, как исходный код Rust сконфигурирован, собрать и инсталлировать компилятор можно с помощью следующих команд:
make make install
Далее необходимо инсталлировать утилиту cbindgen:
export PATH=/opt/toolchains/RUST/1.82.0/bin:$PATH cargo install --root /opt/toolchains/RUST/1.82.0 --version 0.27.0 cbindgen
Теперь Rust инструментарий готов к работе.
Если вы уже инсталлировали cargo в домашний каталог, то вы можете подключить собранный вами инструментарий (toolchain) в набор уже инсталлированых ранее toolchain-ов, например, с именем RcL-1.82.0-x86_64-unknown :
rustup toolchain link RcL-1.82.0-x86_64-unknown-linux-gnu /opt/toolchains/RUST/1.82.0
По завершении данной команды, список ваших toolchain-ов может выглядеть, например, так:
rustup toolchain list stable-x86_64-unknown-linux-gnu RcL-1.82.0-x86_64-unknown-linux-gnu 1.71.1-x86_64-unknown-linux-gnu (default)
Итак, в отличие от GNU Коллекции Компиляторов, проекты LLVM и Rust построены так, что элементарные настройки превращаются в достаточно нетривиальную последовательность действий. А ведь все начиналось весьма просто, но в какой-то момент в очередной выпуск доступных cross-компиляторов Rust (после версии 1.71.1) забыли добавить триплет mipsel-unknown-linux-gnu. Тогда-то и пришлось задуматься о сборке собственных кросс-инструментариев Rust, чтобы обрести некоторую независимость, ведь сейчас все больше и больше открытых проектов выбирают язык Rust.
Источники:
Enjoy.
ссылка на оригинал статьи https://habr.com/ru/articles/857564/
Добавить комментарий