Как стать автором
Обновить

Комментарии 33

Попробуйте ещё vcpkg для зав исимостей. Если хорошо его изучить, то это значительно упростит вам работу с third party.

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

Спасибо за рекомендацию, рассмотрим vcpkg, когда дойдут руки!

А что касается поддержки разных мажорных версий Qt, то здесь мы ориентировались на потребность наших заказчиков: какую версию Qt они использовали для разработки своего ПО на основе нашего продукта. Сейчас запроса на Qt 4.8.7 уже не осталось, поэтому эту совместимость мы решили более не поддерживать в угоду развитию проекта.

Начать с vcpkg несложно. Вытянуть с гита и передать путь одним аргументом в CMAKE_TOOLCHAIN_FILE. И оппа, у вас из коробки сами собираются нужные зависимости (vcpkg install список чего нужно).

ИМХО, при работе c vcpkg следует сразу начинать с файлов манифестов (vcpkg.json), чтобы в каждом проекте можно было держать именно нужные версии зависимостей. Ибо при наличии единственного "глобального" vcpkg и ручного vcpkg install ... очень легко случайно обновиться до самых свежих, но несовместимых с предыдущими, версий зависимостей.

И да и нет. Не буду спорить, тут надо понимать что делаешь и это уже не совсем базовое использование. Попробую кратко рассказать про свой костыльный подход. Возможно я сделал велосипед и для моих нужд можно средствами vcpkg создать набор автономных собранных пакетов. Но мне удобно всем этим рулить через vcpkg.json.

Я использую манифест в каждом проекте, но внутри cmake я принудительно выключаю режим манифеста. Цель: исключить запуск vcpkg на стадии конфигурирования проекта и исключить копирование собранных пакетов в build директорию. У меня есть скрипт который берёт манифест и ставит его содержимое в installed для vcpkg. Я осознанно ставлю специфические версии внутрь инстанса vcpkg.

Далее - для каждой группы проектов, которые гарантированно шарят одинаковые версии у меня свой инстанс vcpkg.

Всё это позволяет использовать версионирование, но при этом даёт полный контроль над тем, когда запускается vcpkg. Это очень удобно на CI в контейнерах, где до начала сборки проекта можно все third party «закэшировать» в отдельный слой.

Цель: исключить запуск vcpkg на стадии конфигурирования проекта и исключить копирование собранных пакетов в build директорию.

А зачем это может потребоваться? Что-то я не понял :(

Пример из недавнего прошлого. Требование к CI: в чистую папку выкачать проект, скомпилировать, прогнать тесты, собрать дистрибутив.

vcpkg на распаковку кэша (время на первую сборку опустим) тратил порядка 7-9 минут на билд агенте. Из тяжеловесов там был буст и кутэ.

Поэтому vcpkg install с передачей манифеста зашивается в докер. А сама сборка (из запущенного контейнера) уже видит все нужные зависимости.

Спасибо. Да, такой сценарий делает ваше описание намного понятнее.

target_link_libraries(ㅤㅤㅤtargetㅤㅤㅤㅤㅤ ㅤㅤㅤPUBLIC Qt5::Core ㅤㅤㅤQt5::Gui ㅤㅤㅤQt5::Widgets)

У вас target_link_libraries() везде без ключевого слова (то есть по умолчанию PRIVATE), а здесь PUBLIC (что, кстати, приведёт к ошибке при конфигурации). Это специально так (тогда зачем)? Просто если вы соберёте статический Qt, а ваша библиотека будет динамическая, то этот PUBLIC заставит следующий в цепочке проект (который будет линковаться с вашей библиотекой) тоже искать бинарники Qt. Но у вас тут не библиотека, так что наверное не очень важно.

add_library(my_static_lib STATIC ...)

Я бы не рекомендовал хардкодить тип библиотеки, это должно контролироваться через BUILD_SHARED_LIBS при конфигурации. Но если она у вас не экспортирует никаких символов, тогда да, имеет смысл.

install(TARGETS hello DESTINATION bin)

Вместо руками написанных hello и bin лучше было бы сделать так (для библиотеки инструкций будет побольше, но пути такие же):

include(GNUInstallDirs)
install(TARGETS ${PROJECT_NAME}
    # можно даже их вообще не прописывать, они и так по умолчанию такие,
    # только лучше тогда CMAKE_INSTALL_PREFIX явно указать при конфигурации,
    # иначе он попытается поставить в /usr/local или Program Files 
    #RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} # bin
)

install(TARGETS ${PROJECT_NAME}

Так не пойдет, если таргетов несколько.

Ну это очевидно, как бы.
Но мне пока чаще попадались проекты с одним таргетом на один CMakeLists.txt.

Работа проделана огромная. Но ещё столько же впереди, если учесть комментарии.

qt_add_executable это обвязка которая делает очень много работы связанной с тулзами кутэ и автоматической регистрацией типов. Хотя моё личное мнение, что это актуально только для проектов на qml. (Впрочем, на мак собирать бандлы стало возможно без лишних телодвижений)

CPULIST=x86 make -C src install -j8

Здесь сразу производилась установка. В других замерах только сборка. Не так ли?

Да, верно. Действительно, для полноты картины следовало привести еще этап cmake install. Однако, на результирующее время это бы ничтожно повлияло, т. к. в CMake инсталляция представляет собой обычное копирование файлов. Этот этап занимает меньше секунды по времени, он практически мгновенный.

Бывает, что обычное копирование файлов занимает значительное время. На самом деле больший интерес представляет именно сборка.

Результаты опроса к статье показательны: большинство проголосовавших выбирают CMake. Автор, вы пошли по верному пути, как я считаю. Для развития вашего проекта шаг однозначно правильный. Успехов!

Увы, cmake выбирают из-за отсутствия альтернатив :). Это наверное самое стабильное и популярное собрание костылей. Одни generator expressions чего стоят.

meson+ninja, не? mpv их использует например.

Почему в эпоху ИИ этот самый интеллект не переводит с морально устаревшего GNU Autotools на современные системы сборки такие как cmake? Я видел множество нелепых проектов, в основном люди пытаются найти в ИИ собеседника, но кажется лучшее применение ИИ - это перевод на современные системы сборки.

Ну, для начала, у CMake просто-напросто нет аналога для ряда конструкций, которые есть в "морально устаревшем" Autotools. Например, там нет аналога AC_SEARCH_LIBS, нужно будет писать свой велосипед.

Ээээ, а CheckCXXSourceCompiles тогда что делает?

Я никогда не юзал autotools но вроде это оно, судя по Гуглу

Нет, это не оно. Это то, с использованием чего придётся писать соответствующий велосипед.

Ну под велосипедом вы понимаете сэмулировать вызов функции по её имени? Или одну строку кода: взять адрес функции. Не выглядит особой проблемой, да и такой функционал мне не кажется нужным на регулярной основе :)

Но ок. В целом согласен.

Нет. Суть AC_SEARCH_LIBS в том, что она определяет, какую именно библиотеку из заданного списка следует подключить для того, чтобы можно было использовать некую функцию (а может быть, вообще не потребуется ничего подключать, это она тоже определяет). CheckCXXSourceCompilesделает всего лишь часть этой работы - проверяет, что некий код компилируется, а все остальное кто делать будет?

Mой месседж был о том, что разработчикам ИИ стоило натренировать его на переписывание кода на современные системы сборки. С костылями или без - другой вопросы.
Но вы утверждаете что без AC_SEARCH_LIBS система сборки можно сказать неполноценная? Такое CMake решение одобряете? Вы задавались вопросом как же вся вселенная Qt собирается без AC_SEARCH_LIBS?

А почему вы думаете, что какая-либо тренировка ИИ в его нынешнем состоянии тут как-то поможет?

Такое CMake решение одобряете?

А где там решение? Частный случай модуля для поиска конкретно std::filesystem - это не решение.

Вы задавались вопросом как же вся вселенная Qt собирается без AC_SEARCH_LIBS?

А причём тут "вселенная Qt"? Факт, что эта конструкция широко используется в софте, использующем Autotools, а аналогичного механизма в CMake нет. Тут и до "тренировки ИИ" нужно сделать кучу работы по реализации каких-то support module, видимо.

Увы, за 15 лет мне ни разу не понадобился такой сценарий. Я всегда осознанно подключаю внешние либы и знаю что где лежит. А если для cmake написан аккуратный модуль (install config), то вообще всё прекрасно.

А для каких языков это работает? Только для си? Плюсы с перегрузкой функций/методов умеет? Учитывается ли разный ABI компиляторов (например при попытке подкинуть собранную mingw либу в msvc?

Ну, а мне приходилось использовать. Ибо на некоторых платформах для работы с сокетами надо линковать с libsocket, хочешь вызывать getnameinfo()/getaddrinfo() - вероятно, придется линковать с libresolv, а, может, с libnsl, а, может, вовсе с каким-нибудь libxnet. Более того, в некоторых версиях GCC (32-битных), если хочешь работать с атомиками, нужно линковаться с libatomic (а в некоторых - нет). В CMake определение этого всего требует некоторого количества бойлерплейта (вот здесь например зацените секс с определением библиотек, с которыми нужно линковаться для использования тех же getnameinfo() сотоварищи или getnetbyname_r()), в Autotools же подобные тесты доступны искаропки. Я использовал это для поиска C библиотек, потому что системные библиотеки только такие, плюсовые обычно не держат-с. Соответственно вопросов с манглингом имен или с ABI у меня не возникало.

Да, теперь понимаю. У меня просто очень давно не было платформозависимых вещей. Спасибо.

В завершение, CMakePresets.json добавлять не думали?

Зарегистрируйтесь на Хабре, чтобы оставить комментарий