LINUX.ORG.RU

Наконец-то нормальный способ (кросс-)компиляции под старые glibc

 , , ,


4

6

Делюсь находкой: в языке программирования zig есть встроенный кросс-компилятор C и C++ под разные архитектуры, а также возможность указания версии символов glibc (от 2.16: Debian 8+, Ubuntu 13.10+, CentOS 7, Fedora 18+).

zig cc / zig c++ обечпечивает режим совместимости с вызовом cc и cpp.

Иными словами, этими командами можно безболезненно:

  1. Кросс-компилировать (и архитектуры, и ОС, т.е. под Windows и macOS из Linux) без заморочек с sysroot’ами
  2. Собирать современный код (C23, C++23) под дистрибутивы последних 10 лет выпуска

Ранее для этого либо собирали кросс-компилятор со старым glibc, либо использовали различные костыли по замене хедеров glibc (bingcc, glibc_version_header), либо патчили, либо собирали на старых ОС вроде CentOS 7 (благо там можно установить свежие компиляторы).

Теперь же можно:

$ gcc -o hello_gcc hello.c
$ nm -D hello_gcc
                 w __gmon_start__
                 U __libc_start_main@GLIBC_2.34 ←←← минимум glibc 2.34
                 U puts@GLIBC_2.2.5

$ zig cc -o hello_zig hello.c
$ nm -D hello_zig
                 w __gmon_start__
                 U __libc_start_main@GLIBC_2.34 ←←← минимум glibc 2.34
                 U puts@GLIBC_2.2.5

$ zig cc -target x86_64-linux-gnu.2.16 -o hello_zig hello.c
$ nm -D hello_zig
                 U __libc_start_main@GLIBC_2.2.5 ←←← минимум glibc 2.2.5
                 U puts@GLIBC_2.2.5

# И даже под Windows @ ARM64
$ zig cc -target aarch64-windows -o hello_zig hello.c
$ file hello_zig
hello_zig: PE32+ executable for MS Windows 6.00 (console), ARM64, 7 sections

# Или вообще с musl libc
$ zig cc -target aarch64-linux-musl -o hello_zig hello.c
$ file hello_zig
hello_zig: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, with debug_info, not stripped
★★★★★

Последнее исправление: ValdikSS (всего исправлений: 4)

Огонь. Zig всё больше нравится.

wandrien ★★★
()
Ответ на: комментарий от EXL

Если старые какиры сделают так, чтобы в системе не было пердолинга, то у них отвалится жопа.

wandrien ★★★
()
Ответ на: комментарий от EXL

Glibc этому противится, они, типа, не хотят обратной совместимости по исходникам, только по бинарникам.

Почитайте: https://github.com/ziglang/libc-abi-tools/tree/master/glibc#strategy

ValdikSS ★★★★★
() автор топика
Последнее исправление: ValdikSS (всего исправлений: 2)

Искренне не понимаю, зачем было писать hello.c так, чтобы вот это всё было нужно. Ну дали вам POSIX, SVr4, какой-нибудь 4.3BSD, в конце концов. Чего вам такого не хватало, что именно к конкретной версии glibc привязываться надо было?

JaneDoe
()

К слову, я не пробовал, но если явно избегать, вызовов в glibc того что выпилили и того что не добавили между всеми (в разумных пределах) версиями, то в принципе должно работать на любом glibc (выбранного диапазона версий где мы себя явно ограничиваем). Вроде логично, но есть ли подвох?

Смысл собираем с распоследней glibc, но гарантируем что нет вызовов того чего не было до некой старой glibc и как бы всё.

LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от JaneDoe

что именно к конкретной версии glibc привязываться надо было?

Почитайте, как работают символы в glibc. Оно автоматически привязыватся к последней версии символов при компиляции. Стрелочки указывают на функцию __libc_start_main (внутренний вызов инициализации перед вызовом main()) которая последний раз обновлялась в glibc 2.34, поэтому и символ @GLIBC_2.34.

На версиях старше, чем glibc 2.34, такая программа не запустится (Debian не ниже 12, Ubuntu не ниже 21.10).

В hello.c бувально только puts("hello");

ValdikSS ★★★★★
() автор топика
Последнее исправление: ValdikSS (всего исправлений: 3)
Ответ на: комментарий от ValdikSS

Да, наступал на такое в go. Бинарник собранный в новой версии системы не запускался в старой версии системы ругаясь как раз на libc-шные символы. Пришлось в контейнере со старой системой собирать

cobold ★★★★★
()

А что такое делают в zig что им это понадобилось?

cobold ★★★★★
()

Это самая полезная фишка Zig ради которой его и используют в продакшене. Сам язык еще сыроват, а вот как крос компилятор используют уже давно даже в Uber об этом писали.

На одном из моих проектов зашли еще дальше, и подключили Zig как кросс линкер к компилятору Rust. И получилось без проблем кросс компилировать раст бинари под древнюю libc на девайсе и не мучаться с кастомным gcc тулчейном.

pftBest ★★★★
()
Ответ на: комментарий от GPFault

В таком случае в имплементации zig должны быть обёртки и прочие хуки для обхода этого и преобразования, в ином случае моя мысля верная, но лишь в тех рамках где было изменение добавили/убрали/изменили вызовы, но типы данных остались как есть, просто диапазон версий режется по изменениям ABI типов, а не ABI наличия вызовов 🤔 конечно не всё так просто, но как концепт, чёбы нет. У меня просто в мыслях было опираясь на ABI Tracker например автоматизировать это дело, так чтобы сборка была всегда такой чтобы работала на как можно большем числе версий глибц, ну типа такой подход для ленивых, это не убережёт от того что в новой либц что-то выкинут/изменят и всё сломается гарантированно, но вот в обратную сторону в плане собрал на новом, запускается на старом уже железно стабильно всё.

Ну, это пока так, мысли в слух просто, ни руками, ни умом я пока до этого не дорос :) Предложенное ТС прикольно, но неприкольно что для сишной сборки нужна имплементация другого языка да и ещё которая тащит за собой LLVM, хотелось бы некого решения «в себе» или типа того, да это шашечки, а не ехать, ну, а почему бы и не хотеть.

LINUX-ORG-RU ★★★★★
()

Этой находке 100 лет в обед. Я ещё пару лет назад делал тулчейн для цмаке, собирающий проекты этим зиг цц.

В целом, хоть сам zig и малоюзабелен как язык программирования, но идеи у его разрабов крайне здравые.

В отличие от тех же растоманов, которые не думают, а просто тащат к себе в проект все что блестит.

Lrrr ★★★★★
()
Последнее исправление: Lrrr (всего исправлений: 1)
Ответ на: комментарий от cobold

Да, наступал на такое в go. Бинарник собранный в новой версии системы не запускался в старой версии системы ругаясь как раз на libc-шные символы. Пришлось в контейнере со старой системой собирать

На ЛОР ребята меня учили, что go вообще никак не связан с libc на хосте.

У go, цитата:

Он собирает не под тот Линукс, на котором ты его запускаешь, а под некий common greatest denominator линуксов. Он линкует бинарник не с системным glibc, а с стабом glibc, который несёт с собой. И этот стаб содержит символы с низкими номерами версий.

Не так?

Toxo2 ★★★★★
()

Спасибо большое, что поделились. Эх, если б лет на 8 раньше…

blex ★★★★
()

Собирать современный код (C23, C++23) под дистрибутивы последних 10 лет выпуска

Опаньки! Выглядит годно.

// Для сборки своих хобби-проектов под дистрибутивы последних 10 лет выпуска пользуюсь виртуалкой с некромантской Ubuntu 18.04. С задачей справляется, но у меня там никакого C++23 нет, максимум местами C++11. Между тем, и модули из C++20 хотелось бы покатать, и ещё кое-что.

Так что, возможно, возьму в работу. Спасибо.

hobbit ★★★★★
()

Интуиция мне говорит что всё сломается как не крути по-любому.

ext4
()
Ответ на: комментарий от LINUX-ORG-RU

Так вроде glibc ничего старого не выкидывает, оставляя ради совместимости и старый вариант ABI в виде каких-то обёрток совместимости и новый с другой версией экспортируемого символа. Поэтому условно «собираем под ABI 2.17 и работает с 2.17 вплоть до актуальных». При этом к старому нет заголовкат то есть официально с точки зрения разработчиков glibc - к нему нельзя прилинковаться

Линковка силами zigcc или сборка в окружении centos7 как раз так и делает

Возможно когда-то glibc забьют на совместимость с ствсем старыми ABI, тогда надо будет обновить, но пока такого не было. Иначе куча старых бинарников бы пооттваливалось, а такого нет

GPFault ★★★
()
Последнее исправление: GPFault (всего исправлений: 1)

А у меня Chromium не собирается потому что линковщик не нашел символы rust__realloc и в том духе.

LongLiveUbuntu ★★★★★
()

Годная штука. А есть где мануалы как это прикрутить к, например, сборке Qt-проекта к Qtcreator? Я бы рад был из родного линукса собирать вендовые ехешники для заказчиков. А то сейчас дуалбут приходится держать(да, знаю что можно виртуалку, но так уж повелось).

Loki13 ★★★★★
()
Ответ на: комментарий от cobold

у вас там

./main: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found (required by ./main)
./main: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.32' not found (required by ./main)
что понятно - собираете-то golang'ом из Ubuntu24.

Только это не из-за libc на хосте ведь. А из-за версии самого go.

Установил сейчас на свой ArchLinux

go install golang.org/dl/go1.10.7@latest
версию go, которая была времен Ubuntu18

и собрал ей

~/go/bin/go1.10.7 build main.go
и в бинарнике символы от GLIBC_2.3.2 максимум. И не нужен контейнер.

Т.е. получается правы тут ребята были - go за собой таскает вместе с версией себя версию glibc в среднем по больнице.

Toxo2 ★★★★★
()
Ответ на: комментарий от Toxo2

Только это не из-за libc на хосте ведь. А из-за версии самого go.

Полагаю, из собранной версии golang. Вы тоже качаете собранную кем-то, а так как версия старая, то и собирали её давно и со старым glibc.

В golang всё просто: если не используете функции, завязанные на glibc, в своей программе, то можно собирать без него с помощью CGO_ENABLED=0.

ValdikSS ★★★★★
() автор топика
Ответ на: комментарий от Toxo2

Так это hello world можно собрать старой версией. А если приложение использует фичи современных версий компилятора? Есть ещё опция выключить CGo при сборке и таким образом получить статический бинарник. Но и у этого способа тоже есть недостатки

cobold ★★★★★
()
Ответ на: комментарий от max_lapshin

Зачем поощрять бабушколюбов, которые используют Centos 7?

Чтобы не было необходимости иметь отдельные сборочные машины. А то на девелоперской вообще bleeding edge у меня, если у себя соберу, оно не то что на centos 7 не будет работать, а и на ubuntu 22.04.

Loki13 ★★★★★
()
Последнее исправление: Loki13 (всего исправлений: 1)
Ответ на: комментарий от Loki13

Не, вопрос в другом. Зачем поощрять дурь с «раньше девки были краше и центось была более седьмой»?

Это же абсолютно админская придурь с неумением обновлять сервера, откатывать, мониторить их и работать с ними. Вместо современных инструментов непонятные древние знания и навыки с «я умею компилять на сервере, мне проповедники говорили, что это даст 1% прироста производительности, если я причащусь перед этим».

Не нужно собирать ничего под centos 7, особенно учитывая что сборка под ней вообще не дает гарантий работы под ней. Это особенная дичь, учитывая как кичатся её стабильностью, которая полное враньё.

max_lapshin ★★★★★
()
Ответ на: комментарий от max_lapshin

Так, а как иначе охватить максимальное количество пользователей? Вот у нас, на работе, есть клиенты с астрой какой-то древней, мы им софт продаем, и что? Приходится собирать под них. Только с лишним геморроем.

Loki13 ★★★★★
()
Ответ на: комментарий от Toxo2

На ЛОР ребята меня учили, что go вообще никак не связан с libc на хосте

это не совсем правда. Если используешь net/http, то программа на go слинкуется с libc на линуксе, чтобы дергать оттуда getaddrinfo. Но это можно отключить, тогда получится статический бинарник.

Ну и в некоторых случаях в гошном софте явно используют сишные библиотеки. Вон syncthing например, в который недавно впилили sqlite.

Lrrr ★★★★★
()
Ответ на: комментарий от Loki13

не, ну астра - это да, боль страдания, но регуляторка.

Оно просто есть, как плохая погода или налоги.

max_lapshin ★★★★★
()
Ответ на: комментарий от Toxo2

Он собирает не под тот Линукс, на котором ты его запускаешь, а под некий common greatest denominator линуксов. Он линкует бинарник не с системным glibc, а с стабом glibc, который несёт с собой. И этот стаб содержит символы с низкими номерами версий.

Простите, а почему после осознания необходимости вот этих всех выкрутасов никто не потрудился найти разрабов glibc и хорошенько отп?!&ить их в воспитательных целях?

hateyoufeel ★★★★★
()
Ответ на: комментарий от hateyoufeel

Да и вообще, сейчас вся экосистема построена на том, чтобы завернуть всю операционную систему в контейнер и держать по 20 копий программного стека на каждый чих.

Уже то, что glibc которое десятилетие сохраняет обратную совместимость с приложениями и не апает мажоный номер до 3, – за это сказать спасибо надо.

Потому что с подходом как в qt, уже бы полдюжины несовместимых версий было.

wandrien ★★★
()
Ответ на: комментарий от wandrien

Потому что разрабы glibc еще ничего на фоне прочего пердолева

Ну надо же с чего-то начинать!

сейчас вся экосистема построена на том, чтобы завернуть всю операционную систему в контейнер и держать по 20 копий программного стека на каждый чих.

Да. И это сраный позор, так-то.

hateyoufeel ★★★★★
()
Последнее исправление: hateyoufeel (всего исправлений: 1)
Ответ на: комментарий от hateyoufeel

glibc сопровождают качественно, она обратно совместима. Старые бинарники работают с новой glibc, не падают. Это благодаря версионированным символам. Во время динамической линковки (т.е. во время запуска бинарника) динамический линкер видит в бинарнике GLIBC_2.11 (например), и достаёт из libc.so.6 символы с версией @GLIBC_2.11, а не какие-то другие.

Но вот во время сборочной линковки почему-то нельзя указать, с какой версией символов ты хочешь линковаться. Линкер линкует с версией по умолчанию, указанной в библиотеке, и она может быть только одна. Логично, что она самая последняя.

И тут вступает в игру многолетний идиотизм: пакет glibc-devel зависит от пакета glibc, причём той же версии. Потому что в пакете glibc-devel нет файла libc.so, а есть только симлинк libc.so -> libs.so.6. В результате ты не можешь поставить glibc-devel другой версии, чем твой рантаймовый glibc.

Думаю эта экономия дискового пространства за счёт использования симлинка была придумана давным давно бородатыми вытиранами.

На мой взгляд достаточно разорвать эту зависимость. Положить в пакет glibc-devel файл libc.so (а не симлинк). Тогда можно будет ставить glibc-devel любой версии и линковаться с любой версией glibc.

iliyap ★★★★★
()
Последнее исправление: iliyap (всего исправлений: 1)
Ответ на: комментарий от iliyap

glibc сопровождают качественно, она обратно совместима. Старые бинарники работают с новой glibc

Нет

hateyoufeel ★★★★★
()
Ответ на: комментарий от max_lapshin

Не нужно собирать ничего под centos 7

CentOS 7 используют не потому, что нужно что-либо запускать конкретно на этой версии, а потому, что это современный дистрибутив в смысле пакетов — туда штатным образом можно установить gcc 12, например, из extra-репозитория.

Это единственный дистрибутив, сочетающий относительно свежие версии ПО и старую версию glibc, а значит, максимально совместимый и с другими дистрибутивами тоже. В условной Ubuntu 18.04 и 20.04, например, свежих пакетов нет, никто особо ничего не пакетирует.

ValdikSS ★★★★★
() автор топика
Ответ на: комментарий от Loki13

А есть где мануалы как это прикрутить к, например, сборке Qt-проекта

я собрал qt5 в венде, и далее через wine собираю приложение не перезагружаясь

x905 ★★★★★
()

Также добавлю, что Zig, кроме компиляторов С/С++/Obj-C, предоставляет ещё неплохую систему сборки (с возможностью fetch’ить архивы с сети). И, да, её можно использовать для сборки С/С++ проектов.

Единственный минус на данный момент - Zig как проект находиться в WIP стадии, стабильного API нет.

P.S.: Хотя мне больше нравится rust’овый Cargo. Попроще как-то.

P.S.S: Владик, спасибо за windows2usb, отличная штуковина для железа с BIOS!

mak8kammerer
()
Последнее исправление: mak8kammerer (всего исправлений: 2)
Ответ на: комментарий от Loki13

Годная штука. А есть где мануалы как это прикрутить

Но, как я отмечал выше, API лихорадит, гайды, возможно, уже не актуальны.

к, например, сборке Qt-проекта к Qtcreator?

Проблема в том, что все ваши зависимости должны использовать zig as build system, иначе вам придётся самостоятельно писать билд-скрипт для библиотеки (как это делается в первой ссылке для googletest). Некоторые С/С++-библиотеки уже имеют поддержку билд-системы Zig’a (например, raylib), для других существуют форки с патчами (SDL, GLFW ). Могу ошибаться, но qt не использует zig as build system.

Ещё, наверное, возможно как-то в Сmake zig cc/c++ юзать, но я не уверен.

mak8kammerer
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.