LINUX.ORG.RU

Qt переходит с qmake на CMake

 , , ,


4

4

Сегодня в официальной рассылке Ларс Кнолл (Lars Knoll) подтвердил давно ходящие слухи об отказе от qmake в пользу CMake начиная с Qt 6.

Данное решение было результатом многочисленных дискуссий по поводу будущего системы сборки Qt. Команда признаёт, что эволюция qmake зашла в тупик и замена его было лишь вопросом времени. В июле Тьяго Мацейра (Thiago Macieira) перечислил требования к будущей системе сборки, из потенциальных кандидатов, удовлетворяющих им, в итоге остались Qbs и CMake.

Qbs разрабатывался внутри The Qt Company как альтернативная система сборки общего назначения, призванная избавиться от болячек qmake и предложить разработчикам декларативный язык описания проекта на основе QML. К сожалению, проект так и не получил достаточного развития и в последнее время поддерживался усилиями буквально одного человека. Для того чтобы Qbs конкурировал на рынке необходимо было бы приложить усилия, несоизмеримые с текущими возможностями и бизнес-целями компании. Таким образом, единственной областью применимой для Qbs мог бы стать перевод на неё самой Qt. Но даже это оказалось трудновыполнимой задачей из-за циклических зависимостей между Qt и Qbs, что прямо противоречило одному из основных требований.

И Qbs, и CMake показали хорошие результаты в ходе эксперимента по сборке Qt, но разработчики отмечают насколько далеко они сумели продвинуться именно с CMake за короткий промежуток времени.

Среди прочих достоинств CMake упоминаются широкое расспространение в экосистеме C++, в частности KDE, хорошая поддержка в популярных IDE и пакетных менеджерах (VCPkg, Conan и прочие), а также большая база пользователей.

Модули CMake уже официально входят в состав Qt 5 и планировались поддерживаться и далее наряду с qmake. Добавление третей системы сборки стало бы слишком тяжёлой задачей, поэтому отказ от Qbs был во многом предопределён.

Компания уверена в своём выборе CMake для Qt 6. Результаты уже сейчас можно опробовать в проекте qtbase, переключившись на ветку wip/cmake. Желающие принять участие в портировании остальных модулей приглашаются к сотрудничеству.

В дополнение, в официальном блоге Qt сегодня также заявили про прекращение разработки Qbs: http://blog.qt.io/blog/2018/10/29/deprecation-of-qbs.

>>> Подробности

★★★★★

Проверено: jollheef ()

Ответ на: комментарий от RazrFalcon

QtC делает автоматом.

Всё ясно с вашим УМВР. С тем же успехом можно было бы написать, что ты чистишь сборку перед каждым запуском. Разговор был именно про инкрементальную сборку, которой в qmake нет.

Кстати, вот ещё эксперимент: добавь в .pro-файл DEFINES += SOMETHING. Даже вызови qmake перед make. Внимание вопрос: почему ничего не пересобирается?

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

Внимание вопрос: почему ничего не пересобирается?

Потому, что оно не умеет такое? Если вы пытаетесь тут что-то доказать - то вы ошиблись адресом.

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

Кстати, вот ещё эксперимент: добавь в .pro-файл DEFINES += SOMETHING. Даже вызови qmake перед make. Внимание вопрос: почему ничего не пересобирается?

А это хороший вопрос. А ещё один хороший вопрос - как сделать, чтобы пересобиралось, не отказываясь от работы через make? У меня пока навскидку только один вариант - добавлять сам Makefile в зависимость ко всем файлам, где это SOMETHING используется. И чем это чревато, я пока не додумал...

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

Ответ как всегда на поверхности. Сгенерированный Makefile не хранит историю. То-есть qmake видит, что .pro-файл изменился, но что там изменилось — неизвестно. Хорошо, если кто-то добавил исходник, а если DEFINE или ещё какой параметр командной строки? Всё что qmake делает в этом случае — просто обновляет Makefile, не трогая уже собранные артефакты сборки, про которые он, кстати, тоже ничего не знает, ведь предыдущий .pro-файл навсегда утерян.

Как результат — уже собранные объектники никто не перезапускает, ведь они новее исходников, а про добавленный DEFINE ничего неизвестно.

Как вариант — действительно ставить зависимости на Makefile. Но это будет равносильно полной очистке всего проекта при любом изменении .pro-файла. Боюсь, в случае qmake решения не существует.

Dendy ★★★★★ ()

Согласен с многочисленными отписавшимися в треде, что CMake — лютое говно.

Но у Qt не было особого выбора. То чем сейчас собирается Qt — гибрид козы с быком (под MS Windows вообще бинарём sic!), мимикрирующий под autotools и под капотом генерирующий кучу Makefiles с помощью QMake. Это прямо таки 1998 год, когда всякие там premake, progen, tmake и imake были в моде.

Всем ясно и понятно, что с этим нужно что-то давно делать. Да, CMake хрень и говно, но как минимум он популярен и позволяет генерировать проектные файлы для различных IDE и систем сборки, той же Ninja. А не только для ущербного make, который не умеет нормально в многопоточность (костылину -jN давно пора выкинуть на мороз). Стоит взять и сравнить скорость сборки каким-нибудь ninja или почившем ныне qbs'ом с этим make -jN. Что уж говорить если мегатормозной Gradle на Java сегодня в многопоточной сборке собирает C/C++ куда как быстрее дедовского make? В Qt в своё время пытались решить проблему с тормозным make и его деривативом nmake и даже запилили аналог, который назывался jom.

По поводу QBS — жалко. Но The Qt Company очень маленькая компания и она не может позволить сделать и развить собственную систему сборки. QBS, конечно, был хороший но уж слишком декларативный и поэтому был жирным и зависел от кучи кишков Qt и их модулей, вроде того же движка JavaScript'а.

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

А то прям жесть с cmake в QtCreator

4.2

ты старее ссылку на стэк-оверфлоу найти не мог? :)

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

А чего старее, если тот же кал повторяется в Ubuntu 18.04

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

Проблема не в том, что qmake не делает зависимостей от инклудов, он их делает как надо, а в том, что он не делает зависимости Makefile от всех исходников.

На третьем шаге у тебя появилась зависимость foo.h от bar.h, поэтому должен быть запущен qmake кем-то.

Вариантов тут два: либо ты руками запускаешь qmake после апдейта из репа или когда сам понаписал такое, что приводит к новым зависимостям. Второй вариант - это всегда запускать qmake (или иной генератор Makefile) перед сборкой.

Решения для второго варианта описано здесь: http://blog.mgsxx.com/?p=2166

cmake всегда проверяет зависимости перед сборкой или вручную нужно его запускать?

anonymous ()
Ответ на: комментарий от hobbit

Сейчас чаще всего используются 3 «конструктора» систем сборок - autotools, cmaks, scons. На всех из них частенько хочется оторвать руки девелоперам за извращения которые они там делают из-за скудоумия или непонимания, или от нежелания думать, или по злому умыслу. Когда все боролись с autotools и славили cmake или scons, что там всё плавно и без костылей, были у меня сомнения, так-как в проектах, на которых работал я не было таких проблем с autotools... Да, был ряд скриптов, которые нужно было дернуть для фикса .la файлов, но это было уже сто раз отлажено и работало десятилетиями. Но что у cmake что у scons было полно детских проблем, в основном из-за ЧСВ и странных предположений о реальном мире, сделанных разработчиками. Сейчас все более-менее везде одинаково. Костылей везде натыкано, с кросс-компиляцией везде проблема. Смысла что-то выбирать и хейтить уже нет. Разве что scons что-то тормоз на больших проектах...

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

cmake всегда проверяет зависимости перед сборкой или вручную нужно его запускать?

Если у меня в CMakeLists.txt файлы проекта заданы не поимённо, а wildcard-ом, то после добавления нового файла я делаю touch CMakeLists.txt (это быстрее чем добавлять новый файл туда ручками, у меня скрипт на шоткате). При изменении уже существующих файлов cmake распознаёт изменения.

dimgel ()
Ответ на: комментарий от Dendy

По поводу зависимостей. qmake написан на самом Qt. Ninja собирается сам собой. CMake тоже собирается сам собой, требуя предыдущую версию. Продолжать? Ключевое слово — bootstrap.

QMake ведь использует только QtCore. Для QBS требуется куда больше модулей. Где там у них движок Js сегодня? В QtQML? Сколько он собирается даже на мощных билд-станциях? Несколько минут. В этом и причина. Чтобы собрать свежий QBS в дереве Qt для сборки самого Qt, нужно собрать половину Qt с помощью каких-то других систем сборки (или старого QBS) а уж потом собирать им оставшийся исходный код.

CMake инороден для Qt и в этом его преимущество в данном случае.

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

У CMake генерация зависимостей вынесена на этап самой сборки, после этапа конфигурации. То-есть при вызове cmake зависимости C++ ещё не собраны. Они будут самостоятельно обновляться в фоне и никогда не бывают сломаны. Переконфигурация также вызывается самостоятельно и только в случае, когда сами скрипты были потроганы, но не C++ код.

Кроме того, в отличии от вышеописанной проблемы с Makefile, который не хранит историю, CMake таки её хранит и знает с какими параметрами был собран каждый объектник, и если они изменились — он будет пересобран. То-есть проблемы с добавлением define'ов нет. К примеру, в случае с Ninja эти параметры хранятся в файле .ninja_deps и обновляются на лету. С Makefile всё немного замороченей, поскольку из коробки в нём такого нет, то CMake сам сохраняет параметры сборки в отдельный файл.

Мораль — нужно генерировать столько промежуточных файлов, сколько нужно. QMake с его идеологией «сломанный Makefile, зато всего один» — сам себе вырыл могилку.

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

Что хеадеры забыли в таргете? А так верный способ привести к помойке, особенно в большом проекте.

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

я делаю touch CMakeLists.txt (это быстрее чем добавлять новый файл туда ручками, у меня скрипт на шоткате)

...тем временем в нормальных языках..

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

Ты хотел сказать в src? Там внутренние классы либы. Как раз борьба с помойкой: лишнего наружу торчать не должно.

dimgel ()
Ответ на: комментарий от fornlr

Последние 2 года _активно_ работаю в QtC и с cmake'ом. Не замечал особых проблем.

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

CMake инороден для Qt и в этом его преимущество в данном случае.

CMake тоже не подарок, в случае с бутстрапом он фактически собирается два раза. И кода там ой-ой. А ещё нужен Ninja, благо он сравнительно маленький.

Всё-таки между выбором: быстрый бутстрап, зато кривая система сборки, либо медленный/требует внешние пакеты — я бы выбрал второе. Бутстрап это такая штука, которая не должна быть быстрой. И жертвовать чистотой кода будет себе дороже.

Когда Qt собирается с нуля в каком-то OpenEmbedded — там все плевать хотели сколько это займёт по времени, всё равно делается один раз. На девелоперских машинах тот же Qbs поставили бы из пакетного менеджера, или собрали один раз руками в какой-нибудь /usr/local. Проблема бутстрапа, мне кажется, сильно преувеличена.

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

Нет, я хотел сказать, что всему этому

"include/*.h src/*.h src/*.hpp"
не место в таргете.

invy ★★★★★ ()

По поводу CMake, тут 100% попадутся его апологеты.

1. Как в CMake кросс-платформенно включить предупреждения компилятора? Или я всё так и вынужден, как в 90-ых писать аля:

IF ( CMAKE_COMPILER_IS_GNUCC )
    Target_compile_options(main PRIVATE "-w -Wall -Wextra -pedantic -Werror")
ENDiF()
iF ( MSVC )
    target_compile_options(main PRIVATE "/W4")
ENDIF()
If ( CLANG )
    TARGET_COMPILE_OPTIONS(main PRIVATE "-w -Weverything")
Endif()

Чудесный синтаксис, не правда ли? Регистронезависимость это здорово! Именно такое вырвиглазие благодаря CMake вы можете увидеть в практически любом OSS-проекте. Особо упоротые наркоманы с LOR'а предлагали даже отдельный Coding Standard применять к проекту в частности CMake-файлов. Наряду с уже существующими для C и C++.

Так о чём это я. А, вот: ведь даже в жутко примитивном QMake, внезапно, есть:

CONFIG += warn_on
CONFIG += warn_off

2. Как в CMake включить отлов изменений файла не по дате файла, like 70s, а нормально, как это делают современные сборочные системы вроде Gradle и Scons — по чек-сумме. Зачем это нужно? Да для того же Qt. В куче Qt-проектов переводы генерируются с помощью lupdate/lrelease, которые бампают дату файла (но не обязательно вносят в него изменения) и поэтому тупой CMake продолжает каждый раз заново компилировать переводы при сборке.

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

Есть ли что-то хорошее из альтернатив? В первую очередь интересует пункт 1 для кросскомпиляции.

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

Сорри, но не верю. Не изучал и пока что не собираюсь, а не верю из общефилософских соображений.

У плюсов философия и языка, и его развития вполне логичная в рамках базовых принципов, озвученных Страуструпом: «не платишь за то что не используешь», «отсутствие необходимости в более низкоуровневом языке для системного программирования», третий не помню. Если эту идею почувствовать, и учесть накладываемые устаревшим синтаксисом ограничения, то всё начинает выглядеть вполне логично и предсказуемо.

Я к тому, что ни раст, ни кто-либо ещё в принципе не могут быть лучше сразу по всем фронтам: у них неизбежно будут свои собственные ограничения. Отличающиеся от плюсовых, обусловленные их собственными базовыми принципами (ежели таковые существуют; если нет, то этот язык будет хуже по всем фронтам, зато как обычно завоюет бешеную популярность).

Так что размен плюсов на раст или что-либо другое — это размен шила на мыло. А точнее, на кота в мешке, который пока ещё неизвестно выстрелит ли.

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

1. Сомневаюсь, что есть решение, предупреждений для разных компиляторов вагон. warn_on/warn_off это очередной костыль, который в общем случае включит/выключит не то что тебе нужно. А то что нужно просто заверни в общий код и экспортируй в виде переменной конфигурации.

2. В CMake для этого давно завезли BYPRODUCTS.

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

CMake кросс-платформенно включить предупреждения компилятора?
А, вот: ведь даже в жутко примитивном QMake, внезапно, есть:

Ворнинги компилятора один единственный юзкейс. А когда надо настроить что-то другое, дай угадаю, в qmake будет тот же if-elseif, да?

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

Это список исходных файлов проекта. Где ты там target увидел?

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

движка JavaScript'а

Ну идея узать полноценный язык программирования для системы сборки сама по себе ОК. Но лучше бы это был не js. Kotlin dsl для gradle, когда обрастет документацией, станет тоже норм решением с точки зрения гибкости описания билда.

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

Где ты там target увидел?

Все что в FILES ты «добавляешь» в library.

add_library(${NAME} STATIC ${FILES})

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

А то что нужно просто заверни в общий код и экспортируй в виде переменной конфигурации.

Написание скрипта сборки начинается с написание плагинов для системы сборки. Отлично.

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

Вообще-то в add_library как раз перечисляются сорцы проекта:

add_library(mylib STATIC mylib.cpp mylib.h)

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

Я к тому, что ни раст, ни кто-либо ещё в принципе не могут быть лучше сразу по всем фронтам: у них неизбежно будут свои собственные ограничения.

Ему достаточно быть лучше. А это не так сложно. И ему это удалось. Достаточно взять cargo, модули, unsafe, std и ADT.

Понятное дело, что он ещё сырой, но даже в таком виде он далеко впереди.

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

2. В CMake для этого давно завезли BYPRODUCTS.

Хмм...

The BYPRODUCTS option is ignored on non-Ninja generators except to mark byproducts GENERATED.

А под проекты MS VS интересно работает оно или нет. Надо бы проверить. Но вообще, это больше претензия к Make, чем к CMake. У него должна давно появится такая опция, но с этим Make диды носятся словно со святой коровой и боятся туда залазить. При этом они уже не раз ломали совместимость новых/старый версий, например:

https://github.com/GodFox/magx_kernel_xpixl/commit/5ca246809be3d726ad14477168...

Ранее make там проходил без проблем.

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

Там выше по треду invy уже ответил, что qmake ничем не лучше. Собственно, это одна из больший претензий — вместо краткого и лаконичного API qmake состоит из тысячи полудокументированных костыликов «для себя, ну может ещё кому пригодится».

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

qmake сделан чтобы собирать Qt проекты. тчк. Единственный недостаток - это кривое обновление переводов. Всё остальное одной строчкой делается.

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

3. Раньше поддержка Qt-проектов у CMake была просто замечательная:

Cmake Qt 5.6 undefined reference to vtable

Если структура дерева исходников была отличной от той, которую придумали CMake-разработчики, MOC для файлов просто не вызывался, сборка падала на ошибках линковки и нужно было всё аккуратно прописывать ручками в CMakeList.txt

Вот это вроде бы поправили? Dendy посмотри пожалуйста, сейчас AUTOMOC для другой структуры вызывается нормально или CMakeLists.txt требует каких-то правок?

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

Скала много лет была далеко впереди жавы. На несколько голов выше. И только совсем недавно вошла в 20-ку самых популярных языков. Непонятно кстати, как она туда попала, если в жаву проникает и ФП, и вывод типов, и даже метапрограммирование (lombok). Хотя по компактности синтаксиса и мощности жава всё равно в глубокой жопе; да и lombok надо клонировать чтобы свои макросы писать.

Вот когда раст приподнимется чутка (необязательно до 20-ки, но точного критерия не дам), тогда и займусь. Это ж не просто пару туториалов глянуть, тут надо основательно вгрызаться и шишки набивать.

Расскажи кстати плиз, в чём по твоим понятиям заключается сырость раста. Т.е. на что обращать внимание в будущих новостях по нему. Я только помню что там были проблемы с параллелизацией сборки, на генте у меня и раст, и firefox в одно ядро собирались.

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

Насколько я помню, BYPRODUCTS в Makefile работал нормально, реализовывался либо через рекурсивный вызов, либо через include(byproduct), которого нет на системе, зато есть правило сборки, его создающее. Лень разбираться.

Главное — правильно расставить зависимости между целями сборки.

Но, по большому счёту, в случае CMake и при наличии Ninja, make не имеет смысла.

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

под MS Windows вообще бинарём sic!

Хм. Это, вроде было в Qt4, в Qt5 уже скриптом (но как плата, нужен дополнительно устанавливаемый питон).

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

Смысла что-то выбирать и хейтить уже нет.

Угу, хейтить можно всё сразу :)

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

Чесгря, автомоком никогда не пользовался. Но судя по дате того треда, qt5_use_modules() и cmake_minimum_required(VERSION 2.8) — забудь всё, что ты знал. Я помню только одну проблему, которую ленивые жопы из TQtP отказывались чинить с моками, пока CMake сами не выкатили фичу file(GENERATE).

Dendy ★★★★★ ()

Блин, пичалька, думал qds допилят.

ya-betmen ★★★★★ ()
Ответ на: комментарий от dimgel

проблемы с параллелизацией сборки

Не слышал. У меня все ядра использует. Возможно приколы сборки самого FF.

в чём по твоим понятиям заключается сырость раста

Именно в сырости.

  • Экосистема молодая (но уже в 100500 раз лучше C/C++, ибо нормальная std и cargo). Действительно хороших либ маловато.
  • Модули к Rust 2018 собираются сильно перекроить. В лучшую сторону, но всё равно.
  • Неясности с обработкой ошибок. Опять же, лучше чем в плюсах, но консенсуса пока нет. Чего только стоит то, что trait Error в std частично помечен как deprecated.
  • async/nll/bench/rustc-test до сих пор unstable.
  • Нема GUI. Это самая большая боль. Хотя его ни для какого языка нет, не считая JS.

С другой стороны, я за два года использования ни разу не нарвался на баг компилятора/std. Правда я пишу код для людей, а не извращения.

RazrFalcon ★★★★★ ()

Продолжаем разбор полётов систем сборки.

Следующий на очереди — QMake.

Почему в *.pro файле не срабатывает else для greaterThan() ?

Там у нас отличились и захордкодили стиль программирования K&R/1TBS.

// Неверно!
greaterThan(QT_MAJOR_VERSION, 4)
{
  CONFIG += c++11
} 
else 
{
  QMAKE_CXXFLAGS += -std=c++11
}

// Верно!
greaterThan(QT_MAJOR_VERSION, 4) {
  CONFIG += c++11
} else {
  QMAKE_CXXFLAGS += -std=c++11
}

Шаг в сторону от стиля — ничего собираться не будет, QMake просто будет плеваться ошибками, которые настолько неочевидны, что пользователи даже создают темы на форумах.

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

Это, вроде было в Qt4, в Qt5 уже скриптом (но как плата, нужен дополнительно устанавливаемый питон).

Да ну? Я точно помню configure.exe в архивах исходников Qt 5. Возможно этот файл просто потеряли:

https://bugreports.qt.io/browse/QTBUG-51355

Может спустя два года, конечно ситуация и изменилась и его выкинули. Лень смотреть. Но до Qt 5.7 этот файл точно был там.

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

Императивная билд-система на самом языке. Хорошо.

За консультацию спасибо.

Про параллельность сборки — обсуждалось на ЛОРе раньше, кто-то отписывался, что над этим работают, и упоминал про блокирующие эту фичу проблемы, суть которых я не запомнил.

dimgel ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.