
Предисловие
Официальная вики Gentoo пишет: «LLVM profiles are experimental. Most people do not want these.»
Эта статья — хроника моей реальной миграции на LLVM-тулчейн с заменой libstdc++ на libc++.
1. Что меняется и почему это может быть больно
libc++ вместо libstdc++
Ключевое изменение — ABI-несовместимость. libc++ оборачивает все свои символы в inline-namespace std::__1, libstdc++ этого не делает (у неё std::__cxx11 — лишь inline-namespace для части типов вроде std::string). Манглированные имена не совпадают, поэтому объектники и библиотеки, собранные с разными C++ stdlib, нельзя связывать друг с другом.
Следствие: недостаточно пересобрать LLVM. Нужен полный:
emerge -e @worldGCC после этого не может быть запасным C++ компилятором. C-код он всё ещё собирает, но C++ соберёт бинарники с libstdc++, которые не слинкуются с системными библиотеками на libc++.
default-lld
При использовании lld можно использовать дополнительные возможности линкера (--icf=all, -z pack-relative-relocs). Но при сборке GCC часть bootstrap-процесса игнорирует системный linker и вызывает GNU ld напрямую, поэтому эти флаги ломают сборку.
GCC остаётся в системе навсегда
Причин три:
- glibc не собирается clang на Gentoo — ebuild принудительно подставляет gcc через gcc-config. На практике это единственный такой пакет: при аудите моей системы из 768 установленных пакетов с CC=gcc собран только glibc.
- GCC — поставщик рантайм-библиотек: libstdc++.so.6 нужна бинарным пакетам (zen-bin, vesktop-bin и т.п.), libgcc_s.so.1 — всем Rust-бинарникам (об этом ниже).
- Полное удаление GCC невозможно без поломки системы — и не нужно: его наличие не мешает LLVM-тулчейну.
2. Подготовка
2.1. Предварительные условия — установка Clang на старом профиле
Это самый важный шаг, который нельзя пропустить. До смены профиля на LLVM у вас уже должны быть установлены и работать Clang, LLD и остальной LLVM-тулчейн.
Сейчас мы находимся на обычном профиле с GCC. Все установки выполняются до смены профиля.
Установить LLVM и Clang (собираются GCC):
emerge llvm-core/clang llvm-core/llvm llvm-core/lld \
llvm-runtimes/compiler-rt llvm-runtimes/libunwindБутстрапнуть Clang — пересобрать его самим собой через package.env:
# /etc/portage/env/compiler-clang
COMMON_FLAGS="-march=native -O2 -pipe"
CFLAGS="${COMMON_FLAGS}"
CXXFLAGS="${COMMON_FLAGS}"
CC="clang"
CXX="clang++"
LDFLAGS="-fuse-ld=lld -rtlib=compiler-rt -unwindlib=libunwind -Wl,--as-needed"
# /etc/portage/package.env
llvm-core/clang compiler-clang
llvm-core/llvm compiler-clang
llvm-core/lld compiler-clang
llvm-runtimes/compiler-rt compiler-clang
llvm-runtimes/libunwind compiler-clang
llvm-runtimes/libcxx compiler-clang
llvm-runtimes/libcxxabi compiler-clang
llvm-runtimes/compiler-rt-sanitizers compiler-clang
emerge llvm-core/clang llvm-core/llvm llvm-core/lld \
llvm-runtimes/compiler-rt llvm-runtimes/libunwind \
llvm-runtimes/libcxx llvm-runtimes/libcxxabi \
llvm-runtimes/compiler-rt-sanitizers
Теперь Clang установлен и проверен в работе на старом профиле. Следующие шаги делаются уже после этого.
2.2. Смена профиля
LLVM профиль включает libc++, compiler-rt, lld и llvm-libunwind через профильные настройки USE. Вручную дублировать их обычно не требуется.
(default/linux/amd64/23.0/llvm)
eselect profile set 19(default/linux/amd64/23.0/llvm/systemd)
eselect profile set 20env-update && source /etc/profile2.3. make.conf — замена тулчейна
В make.conf:
CC="clang"
CXX="clang++"
LD="ld.lld"
AR="llvm-ar"
NM="llvm-nm"
RANLIB="llvm-ranlib"
READELF="llvm-readelf"
STRIP="llvm-strip"
OBJCOPY="llvm-objcopy"
SIZE="llvm-size"
STRINGS="llvm-strings"
OBJDUMP="llvm-objdump"
ADDR2LINE="llvm-addr2line"Вообще, LLVM-профиль уже задаёт всё это сам. Явный блок в make.conf — это осталось ещё до того, как я перешёл на LLVM профиль, так что, добавлять особой нужды нет, вреда от него нет.
LDFLAGS:
LDFLAGS="
-fuse-ld=lld
-rtlib=compiler-rt
-unwindlib=libunwind
-Wl,--as-needed
-Wl,-O2
-Wl,--hash-style=gnu
"При желании можете добавить дополнительные оптимизационные флаги:
-Wl,-z,pack-relative-relocs
-Wl,--icf=all2.4. Что НЕ трогать в make.conf
- LLVM_TARGETS — Не изменяйте LLVM_TARGETS без необходимости. Ручное переопределение может привести к проблемам.
- USE с default-* флагами — профиль сам установит.
- -rtlib=compiler-rt -unwindlib=libunwind в LDFLAGS — профиль дублирует, но мешать не будут.
2.5. GCC с флагами lld
GCC при bootstrap лезет в /usr/x86_64-pc-linux-gnu/binutils-bin/.../ld (GNU ld), игнорируя системный lld. Флаги --icf= и -z pack-relative-relocs GNU ld не понимает.
Решение
cat > /etc/portage/env/gcc-clean-lf << 'EOF'
LDFLAGS="-Wl,--as-needed -Wl,-O2 -Wl,--hash-style=gnu"
EOF
echo 'sys-devel/gcc gcc-clean-lf' >> /etc/portage/package.envЭтот файл не удалять — он нужен будет при каждой пересборке GCC.
Опциональный вариант (у меня в системе именно он): собирать сам GCC компилятором clang — отдельный env-файл с CC="clang" CXX="clang++" и чистыми LDFLAGS. GCC 15 собирается clang'ом без проблем.
3. Пошаговая сборка
Фаза 1: LLVM toolchain без libc++
Сразу включить default-libcxx нельзя — cmake собран с libstdc++, упадёт с symbol lookup error.
Временно отключить default-libcxx
cat > /etc/portage/package.use/toolchain-bootstrap << 'EOF'
llvm-runtimes/clang-stdlib-config -default-libcxx
llvm-runtimes/clang-runtime -default-libcxx
llvm-core/clang-common -default-libcxx
EOFПересобрать тулчейн
emerge -1 --keep-going dev-build/cmake llvm-core/llvm llvm-core/clang \
llvm-core/lld llvm-runtimes/compiler-rt llvm-runtimes/libcxx \
llvm-runtimes/libcxxabi llvm-runtimes/libunwind sys-devel/gccФаза 2: полный ребилд на libc++
rm /etc/portage/package.use/toolchain-bootstrap
emerge -e --keep-going @world4. Верификация
clang --version
# clang version 22.1.8+libcxx → ключевое "+libcxx"
ld.lld --version
# LLD 22.1.8 (compatible with GNU linkers)
# любой пакет, написанный на C++:
readelf -d /usr/bin/btop | grep libc++
# libc++.so.1 — C++ пакеты пересобраны на libc++
Системный аудит — кто ещё ссылается на libstdc++ (ожидаем только /opt/* у бинарных пакетов и /usr/lib/gcc/* у самого GCC):
scanelf -qRn /usr /opt 2>/dev/null | grep -F 'libstdc++.so.6'Кто реально был собран GCC (ожидаем только glibc):
for f in /var/db/pkg/*/*/environment.bz2; do
bzcat "$f" 2>/dev/null | grep -qm1 '^declare -x CC="gcc"' && echo "$f"
doneЧем собрано ядро (если собирали его clang):
cat /proc/version
# Linux version ... (clang version 22.1.8+libcxx, LLD 22.1.8) ...В моей системе итог аудита: из ~4400 ELF-файлов 595 слинкованы с libc++.so.1, а libstdc++.so.6 осталась только у бинарных пакетов из /opt и у собственных библиотек GCC. Ни один файл не линкует обе stdlib сразу.
5. Известные исключения
- glibc — собирается только GCC, так зашито в ebuild.
- Бинарные пакеты (www-client/zen-bin, net-im/vesktop-bin и подобные) — собраны апстримом, навсегда останутся на libstdc++. Лечится только сборкой из исходников.
- Rust-бинарники (fish, niri, yazi, librsvg...) — линкуют libgcc_s.so.1 by design: target-spec x86_64-unknown-linux-gnu жёстко добавляет -lgcc_s. Так выглядят даже официальные сборки Rust на любой системе.
Бонус: sanitizer-рантаймы на libc++
Даже после полной миграции shared-рантаймы санитайзеров (libclang_rt.{asan,hwasan,ubsan_standalone}-*.so) продолжают линковать libstdc++ — это дефолт апстрима (SANITIZER_CXX_ABI=default — на Linux подставляется libstdc++). Исправляется пользовательской переменной MYCMAKEARGS для cmake-ebuild'ов:
cat > /etc/portage/env/sanitizers-libcxx << 'EOF'
MYCMAKEARGS="-DSANITIZER_CXX_ABI=libc++"
EOF
echo 'llvm-runtimes/compiler-rt-sanitizers sanitizers-libcxx' >> /etc/portage/package.env
emerge -1v llvm-runtimes/compiler-rt-sanitizersПроверка:
scanelf -n /usr/lib/clang/22/lib/linux/libclang_rt.asan-x86_64.so
# было: libstdc++.so.6, libgcc_s.so.1, ...
# стало: libc++abi.so.1, libgcc_s.so.1, ...
Итог
Переход с GCC/libstdc++ на LLVM/Clang + libc++ — это не просто замена компилятора в make.conf, а полноценная смена C++ окружения системы с другим ABI, runtime и особенностями сопровождения.
В результате получается полностью LLVM-ориентированный toolchain:
- Компилятор: clang
- Линкер: lld
- C++ stdlib: libc++
- C++ ABI: libc++abi
- Рантайм: compiler-rt
- Unwinder: llvm-libunwind
- Binutils: llvm-ar/llvm-nm/llvm-objcopy/...
Но стоит понимать: переход на LLVM не является чудотворным способом ускорить систему. Тут не будет заметного прироста FPS, меньшего потребления памяти или ускорения каких-либо системных приложений.
Основные преимущества находятся в другом:
- LLD значительно быстрее GNU ld.bfd, что особенно заметно при сборке больших проектов и частых пересборках Gentoo.
- LLVM toolchain становится более цельным: все основные компоненты используют одну экосистему вместо смешивания GCC/binutils/libgcc.
- Clang предоставляет удобный набор инструментов для разработки: хорошие диагностики, sanitizers, статический анализ и тесную интеграцию с LLVM-экосистемой.
- В некоторых задачах Clang может давать отличающиеся результаты по размеру или производительности бинарников, хотя это сильно зависит от конкретного проекта.
При этом есть и обратная сторона. LLVM-профиль остаётся экспериментальным и требует понимания того, как работает сборка. Использование libc++ ломает совместимость с привычным libstdc++ ABI, поэтому переход требует полной пересборки и дальнейшего внимательного сопровождения.
Для большинства пользователей стандартный профиль с GCC/libstdc++ остаётся самым простым и предсказуемым вариантом.
Также стоит отметить, что использование Clang не требует перехода на libc++. Можно оставить стандартный libstdc++ и просто собрать LLVM/Clang toolchain поверх существующей системы. То есть можно остановиться на пункте 2.1, или следовать по инструкции с Gentoo Wiki, согласно которой LLVM используется как компилятор, но C++ ABI остаётся совместимым с привычным окружением.
Переход на libc++ — это уже отдельный шаг, который меняет ABI и значительно усложняет сопровождение системы. Поэтому для большинства пользователей разумным вариантом будет использовать Clang + LLD + compiler-rt, сохранив libstdc++, а полноценный переход на libc++ рассматривать как эксперимент или осознанный выбор.
Комментарии
13:50
> В некоторых задачах Clang может давать отличающиеся результаты по размеру или производительности бинарников, хотя это сильно зависит от конкретного проекта.
По ходу чтения у меня и возник вопрос — а зачем всё это нужно, зачем внутрянку копашить, ради чего? Для настоящих гентушников это может и не проблема, небольшая, но есть риск всё поломать, испортить, то есть усилия и время окажутся потраченными зря. Возвращаясь в начало моего комментария, у меня они "жили" по- соседству: GGC разных версий собран, он довольно быстро собираеется, а вот LLVM/Clang были бинарниками, потому что сборка локальная прерывалась (и 21, и 22).
Когда был на кальке, не всё собиралось через LLVM, например, браузер Librewolf собирается через него по умолчанию, но с ошибкой, меня ему use-флаг, успешно сборка проходила через gcc, то есть иногда это можно задать для пакета через флаги.
И в конце вопрос — а сразу, при установке выбрать профиль с LLVM выбрать?
14:18
14:27
По сути, незачем, если система «просто работает». Я об этом прямо говорю в «Итоге»: прироста FPS не будет, и для большинства стандартный профиль - правильный выбор.
Практический выхлоп довольно узкий: LLD заметно быстрее линкует, единый тулчейн, clang-tools для разработки.
Остальное - интерес и «потому что Gentoo позволяет».
16:14
16:20
19:57
Он сильно ниже будет
20:53
21:02
21:13
Вот здесь поподробнее: это где там провал в производительности заложен?
21:21
В брауере не почувствуется и в играх видно не будет конечно
Хотя ..с fasm мне это как то параллельно... не моя тема
Но рад был познакомиться )
21:58
Исключения: исключения в C++ zero-cost - unwinder запускается только при реальном throw, программы не тратят время на раскрутку стека, поэтому скорость unwinder на общую производительность не влияет в принципе. Но и разницы там нет: llvm-libunwind и unwinder из libgcc реализуют один и тот же Itanium ABI и делают одну и ту же работу.
И заметьте: сначала у вас «FPS будет сильно ниже», потом «в играх видно не будет». Здесь я согласен - именно так и есть.
Кстати, libc++ - стандартная stdlib Android NDK и всех устройств Apple. Телефоны - это как раз те устройства, где «провал производительности в идее» обошёлся бы дороже всего, и там его почему-то нет.
22:30
длина строк разная..работа с памятью разная... да охренеть различий...ну охота вам этот зоопарк поддерживать...на здоровье
Телефоны и производительность??? ...да вы блин издеваетесь?
Apple для меня не устройство.. это маркетинг. На моем телефоне камера уже равнозначна яблоку..а проц очень сильно яблоко обогнал. макбук для меня точно огрызок...мне на нем неудобно потому что... архитектура...ограничения по низким уровням...да там куда ни ткни ограничения... нейронка на нем не дышит... это техника для понтов и обычного пользователя...офис..игры... ну пасьянс там тоже есть.
Я не хаю вашу реализацию, она уместна но для единиц мне кажется. Тем более в дженту. У меня и так каждое обновление мира через скрытие, раскрытие use флагов и это самая простая проблема. А ваша реализация ещё больше головной боли вызывает. Ну и минусы есть. Я их как раз описывал
07:19
А то, что реализации несовместимы, - это правда. Именно поэтому переход требует пересборки мира. Об этом написано в разделе «1. Что меняется и почему это может быть больно».
Насчёт Apple: мой аргумент был не в том, что Apple хорош, а в том, что на устройствах с жёстким бюджетом производительности этот стек используют миллиарды пользователей.
21:32
22:47
Так что никакой ежедневной возни нет и не будет. А если какой-то пакет и не соберётся, то это решается не игрой с USE-флагами, а скорее с package.env.
22:59
Отсюда это интересно мне... Вам . ... И ещё паре челов.... Не тот ресурс где это расписывать.
Но ещё раз пов
торюсь... Мне приятно было вас узнать...
P.S. только меня ассемблеры интересуют... Но общей сути это не меняет
23:08
А где ещё об этом писать, на форуме, на котором бородатые дядьки 50+? Да и не все записи с форумов индексируются поисковиками, я крайне редко что-то вижу оттуда. Тут обратный пример — аудитория подростающая местами, местами опытная и знающая, зато материалы с главной или из каталога ПО отлично находятся поисковиками.
23:12
23:22
15:28
> Я учить не могу
Если б молодость знала, если б старость могла. Так у многих — не все могут изложить свои знания и передать другим. Я статьи писал для освоения/изучения чего-либо, в комментариях часто приходят любящие поправлять, это не только у себя такое наблюдал. Сейчас, спустя время, если открываю писанину свою, чему-то могу радоваться или даж гордится (хотя второе слишком), а где-то наоборот понимаю, какую ерунду написал.
> 4pda по андроида можно ответ в личке … получить
И не факт, что он поможет. Точно его не увидят другие и придётся повторять. Так и появились блогеры, которые регулярно что-то пишут, излагают свою позицию/взгляд на проблему, или видео снимают.
23:41
04:09
Причина этого лежит в области лицензирования, а не в каких-то технических преимуществах.
09:27
09:52
Дело же не в собираемом софте, а в закрытии самого "сборщика". Gcc не закроешь, а вот дописать llvm под m5 или PS6...
А переходить с GNU на проприетарную лицензию... не)
22:08
Just for fun.
23:16
https://pingvinus.ru/gallery/5512#c126035
Я ж про переход, про смену на переправе, так сказать.
20:34
23:49
03:58
19:56
04:01
15:37
16:03
16:35
14:14
16:18
А про «обновление мира» - это чушь: на современном железе оно не занимает много времени, а даже если всё ещё медленно, есть бинарные пакеты - можно вообще обойтись без сборки или совмещать сборку с ними.