Для начала поведаю, зачем это нужно Тут всё банально. Пишу небольшой проект (есть у меня на гитхабе, ссылку дам в конце), который может работать как под windows, так и в линуксе. Когда пришла пора испытывать его в «боевых» условиях, решил поставить его к себе на VPS (минимальная конфигурация, но для моих нужд вполне достаточна). Эту VPS я арендую уже много лет и крутится там та самая 16.04. Много лет и без апгрейдов. А зачем? Работает и хорошо. Заливаю свежесобранный exe'шник (или как там у линуксоидов оно называется), который собирался в убунте 22.04 при помощи gcc 15, и, ожидаемо получаю ошибку типа: version `GLIBC_2.35' not found
. Всё, приехали. Предварительные танцы с бубном ничего не дали. Систему я обновить не могу (тариф VPS это не позволяет), gcc 10 (минимальный для сборки c++20) там уже нет. Опыта в линуксах у меня никакого. Что делать?
Самое простое решение, которое удалось нагуглить и напромптить — прилинковать все библиотеки статически, указав ‑static в опциях компилятора. И это чудесным образом заработало, увеличив исполняемый файл в два раза.
На этом можно было бы и остановиться, но меня смущали ворнинги, утверждающие, что работать оно будет плохо (ругалось на некоторые системные вызовы). И вообще статическая линковка библиотек — это вообще не linux way. Поэтому я решил все таки попробовать пойти по более сложному пути, а именно обновить gcc и собрать всё на месте. О чем и пойдет речь далее.
Первым делом выяснилось, что последняя версия gcc, которую можно легко поставить в столь древней убунте — это gcc 9. Что‑ж, с нее и начнем:
sudo apt install gcc-9
# добавим ее в систему выбора альтернатив. Это сделает gcc-9 активным по умолчанию
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-9 90
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-9 90
Более новые версии в готовом виде найти не удалось, поэтому остался единственный путь: собирать gcc 11 прямо из исходников. Не знаю почему 11 а не 15. Наверное, решил не рисковать и начать с малого, впрочем кто‑то может начать сразу с 15-й, но я не гарантирую результат, т.к. не пробовал, а точнее я таки поставил 15-ю, но уже после 11-й. Вопреки ожиданиям (я windows‑программист и для меня мир линукса — страшная тёмная комната), сей процесс оказался не таким уж сложным. Были мелкие камешки, о которые я спотыкался по неопытности, но в целом всё получилось. Ах да, сначала надо обновить/установить разные непонятные штуки. С трудом понимаю их смысл, но все руководства наперебой советуют это сделать, значит будем делать:
sudo apt install build-essential libgmp-dev libmpfr-dev libmpc-dev texinfo
далее серия команд с комментариями, что и зачем:
# заходим в домашнюю папку (корее всего вы уже там)
cd ~
# скачиваем исходники 11-й версии gcc
wget https://ftp.gnu.org/gnu/gcc/gcc-11.2.0/gcc-11.2.0.tar.xz
# распаковываем
tar -xf gcc-11.2.0.tar.xz
# теперь у нас есть папка gcc-11.2.0. зайдем в нее и скачаем необходимые зависимости
cd gcc-11.2.0
./contrib/download_prerequisites
# всё, покидаем эту папку, в ней нам больше делать нечего (важно! сборка должна проходить в другой папке)
# создаем отдельную папку для сборки:
cd ..
mkdir gcc11
cd gcc11
# мы внутри gcc11, конфигурируем:
../gcc-11.2.0/configure --enable-languages=c,c++ --disable-multilib --disable-bootstrap --disable-selftest --enable-lto --prefix=/opt/gcc-11
# пояснение к параметрам конфигурации:
# --enable-languages=c,c++ - будем собирать только c и c++
# --disable-multilib - оставляем только сборку под текущую архитектуру, остальные долой
# --disable-bootstrap --disable-selftest - ускоряем сборку, выкидывая из нее тесты
# --enable-lto - возможно оно включено и так, но лучше включить явно. Очень полезная штука - Link Time Optimization
# --prefix=/opt/gcc-11 - самая главная опция - путь, куда после сборки gcc будет установлен
# без этой опции мы не сможем переключаться между версиями gcc и вообще будут проблемы
# далее запускаем сборку (если у вас 4 ядра то укажите ключ -j4, чтобы собиралось быстрее)
make
# ждем
Сборка пошла. Можете пойти выпить кофе. Минимум 10 минут у вас есть. По окончании сборки, устанавливаем свежесобранный gcc:
sudo make install
Ура! Мы получили gcc 11 в нашей древней системе. Половина квеста пройдена. Сейчас надо добавить этот gcc в систему в качестве альтернативы, чтобы в будущем иметь возможность переключаться между версиями.
sudo update-alternatives --install /usr/bin/gcc gcc /opt/gcc-11/bin/gcc 110
sudo update-alternatives --install /usr/bin/g++ g++ /opt/gcc-11/bin/g++ 110
Для переключения надо будет выполнять:
sudo update-alternatives --config gcc
sudo update-alternatives --config g++
Компилятор‑то мы обновили. А вот сборщик — нет. Всякие новомодные инструкции, типа avx2, если таковые будут в вашем коде, не дадут exe‑шнику собраться. В моём проекте они были — именно так я узнал, что gcc — это только компилятор. Есть еще binutils — утилиты сборки. Ну что‑ж, будем обновлять binutils:
# качаем и распаковываем последнюю версию на момент написания этой статьи
wget https://ftp.gnu.org/gnu/binutils/binutils-2.44.tar.gz
tar -xf binutils-2.44.tar.gz
# также создаем отдельную папку для сборки
mkdir bu244
cd bu244
# конфигурируем и запускаем сборку
../binutils-2.44/configure --prefix=/opt/binutils244
make # или make -jN, где N - количество ядер - для ускорения сборки
# устанавливаем
sudo make install
Почти всё. теперь, чтобы собрать ваш проект, нужно заставить gcc использовать свежие binutils. Самый простой способ — добавить новые binutils в путь перед сборкой:
export PATH=/opt/binutils242/bin:$PATH # этот путь был указан при конфигурировании
make # это сборка вашего проекта, если что
Проверить, что будет использована свежая версия binutils можно так:
ld --version
Я у себя решил пойти дальше и проделал все эти шаги для установки более свежей версии gcc-15. Все получилось. Я не знаю, получилось бы у меня собрать 15-ю версию gcc с помощью 9-й, не проверял. Но 11-я справилась прекрасно.
Вот теперь точно всё. Код c++20 прекрасно собрался и заработал на старенькой Ubuntu 16.04. То что надо.
ссылка на проект, как обещал
Не хочу тут описывать, что за проект. Статья, не о нем все-таки. Скажу только - это 3proxy на максималках. Кто знает, тот знает.