Pull to refresh
1

Пользователь

2
Subscribers
Send message
К сожалению, Qt всё дальше отстает от апстрима С++. На дворе 2к20й а людям всё ещё надо доказывать что smart-pointer'ы это хорошо и правильно (и нет, в Qt6 их не будет, будем как в 90х делать parent-child на raw-поинтерах).
Всякие std::optional/std::variant завезут только в 6ке и тоже непонятно когда и куда (у TQtC явно не хватает рук да и те разбегаются).
5й абзац =)
Предвосхищая комментарий о том, что Qbs объявлена устаревшей в пользу CMake как система сборки для Qt, сразу отvечу, что сейчас проект развивается сообществом и недавно вышла новая версия.
AFAIK, Qt Creator должен работать с IAR «из коробки» в связке в Qbs.
Я мимокрокодил но вот тут kuzulis вроде бы прикрутил отладчик keil к QtCreator (4.12 версия, по идее)
Поддерживаются ли другие системы сборки, кроме CMake?
Да, новую реализацию стараются прикапывать рядом, не ломая старую. Но оно обычно не противопоставляется старому функционалу, а расширяет его.
Сервисы общаются между собой при помощи неких форматов. Это может быть жисон, когда один сервис запрашивает по http данные у другого. Это может быть protocol buffers, когда один сервис подкладывает файлики другому. Это может быть YT… Вариантов куча. Большинство форматов умеют в опциональные поля — жисон, протобуф. Собственно, при добавления нового поля потребитель проверяет — а новое поле есть? — тогда используем его, иначе работаем «по-старинке».
Сильную попаболь доставлял MMS — там да, чтобы сделать новую версию, приходилось натурально копипастить исходники. Но это, скорее, исключение (к счастью, было нужно редко) и, возможно, flatbuffers тут подошли бы лучше.
Без такой совместимости не получится сделать надежную систему — у вас факап на проде, а откатываться нельзя или очень сложно.

PS: Но я уже больше года не работаю в Яндексе, так что мои знания могут быть немного устаревшими=)
У меня возникает стойкое ощущение, что у вас слишком гранулярное деление на сабмодули. Естественно, никакой геррит вам тут не поможет (и никакой тулинг не поможет, если конечно вы не гугл и у вас есть десятки человеколет на написание этого тулинга). Только это не проблема сабмодулей, это проблема того, как вы их готовите.
Если вы думаете, что в Яндексе постоянно вот так вот приходят и делают коммиты затрагивающие всё дерево сорцов, то вы ошибаетесь — даже «банальное» переименование Stroka в TString делалось поэтапно (если мне не изменяет память).
А между сервисами совместимость _обязана_ быть между версиями. Я конечно мог бы прийти в соседнюю команду и на их java написать использование нового поля, закоммитить всё это одним коммитом… Но какой в этом толк, если 2 сервиса всё равно должны работать в любой комбинации (старый-старый, старый-новый, новый-новый...) на случай факапа и возможного отката одного из них? А еще релизный цикл разный — один сервис катается быстрее чем второй…
Собственно «правильное» деление на сабмодули должно быть по слабо зависящим друг от друга частям — например, репозиторий с сорцами 3rdparty вполне такой кандидат. Или ассеты, если вы разрабатываете игру.
Если у вас одна фича постоянно требует связанных коммитов — подумайте о слиянии зависимых сабмодулей в один. Или подумайте о том, почему эти репозитории так зависимы — может, надо использовать другой формат общения между ними?
В общем. Положим, разраб взял какую-то фичу...


В зависимости от размера проекта, есть два подхода. В случае небольшого проекта, если изменения не конфликтуют по коду (это Gerrit сам ловит) и мы условно не боимся, что изменения конфликтующие, их можно протестировать независимо и потом влить в мастер. Если изменения таки конфликтуют, можно указать разработчику на зависимость и попросить отребейзить изменение на свежий мастер. В общем, ничего нового.
Второй подход заключается в том, чтобы делать staging branch — когда пачка изменений разных разработчиков как-то черри-пикается друг на друга и проверяется в таком виде перед мержем в мастер. Минус что если один коммит ломает что-то, то остальные надо stag'ить заново. Плюс — мы всегда собираем то, что будет в итоге в мастере. Также, этот подход необходим, когда не хватает железа тестировать каждый коммит отдельно. Пример — всё та же Qt, матрица тестируемых систем достаточно большая и нет возможности прогонять тесты ~6 часов для каждого коммита в отдельности.
К сожалению, я не в курсе, сколько второй способ требует усилий, чтобы его реализовать (никогда администрировать gerrit не приходилось).

Заодно — phabricator смотрели?

Нет, но коллега на текущей работе пользуется и очень хвалит. Сами мы вообще на svn пока что=(
Я не призываю полностью отказаться от веток, я ярый противник «технических» веток, когда feature branch создается на любой чих просто потому что «так все делают» или потому что так хочет тулинг (github).
Надо поддерживать N предыдущих версий — вперед, релизные ветки рулят.
Начали работать над новой версией библиотек — вперед, долгоиграющая feature branch.
Портируете проект с автотулз на cmake? Тут тоже пригодится feature branch.
Вот только не надо создавать ветку чтобы убрать\добавить пробел в выражении=)
Мне очень нравится gerrit. Проблема в том что он проприетарный (в том смысле что нет опен сорс аналога уровня GitHub), страшный как смерть (сейчас уже получше, но всё равно...), поэтому о нём мало кто знает и почти никто не пользуется. Мой поинт в том, что гитхабовская схема с pull request, которая _форсит_ создание feature branches — не единственная возможная. Просто там ветки — это деталь реализации, зачем-то торчащая наружу.
В общем и целом Gerrit по процессу очень похож на внутренний яндексовый велосипед для ревью и прекоммит проверок — по факту вы и там и там коммитите «напрямую в транк» безо всяких pull requests и фича веток.
Что, конечно же, не отменяет возможности создать feature branch по желанию. Просто Gerrit не навязывает схему с pull requests и\или git flow.
Я постоянно вынужден создавать ветки в нескольких репозиториях и отправлять их на ревью. Да, всё заливается вместе, CI, вот это всё, но это менее удобно, чем создать ветку в одном репозитории.


Вы путаете теплое с мягким. Ветки вас заставляет создавать git flow, а не сабмодули. Не используйте git flow — не будет и миллиарда веток в сабмодулях.
Вообще, «монорепе» обычно противопоставляется «микрорепы», когда границы проводятся по каждой библиотеке. Истина же где-то по-середине — слишком мелкое деление так же вредно как и отсутствие его. Qt5 разделена на примерно 50 сабмодулей, кажется, это слегка перебор (и, естественно, идут разговоры о «монорепе», как будто по середине ничего нет)
Если сделать svn co Аркадии, потом сделать git init && git add && git commit (то есть, импортировать всё без истории коммитов), а потом попробовать с этим поработать, то, например, git status будет занимать 3 секунды. Не очень удобно.
Так kuzulis и пилит=)

В целом, там есть несколько разработчиков, которые что-то потихоньку делают (в том числе, (бывший) основной разработчик из Qt Company), например, запиливают новые фичи
Проблема в том, что философия qbs подразумевает 1 тулчейн.


Это не совсем так, философия в том, чтобы всё автодетектить, в частности, можно в одном проекте собирать под macOS и iOS одновременно. Проблема в том, что cpp модули весьма сильно прибиты гвоздями (так как писались еще на заре проекта) и не переведены, например, на module providers.
Но можно попробовать указать профиль для продукта явно и посмотреть, что получится:
qbs.profile: "my-stm32-profile-name"
В частности, в автотестах есть такой код
qbs.profiles: isBlubbOS ? ["blubb-profile"] : [project.profile]
Ничего в теме не понимаю, но попробую объяснить, что я вижу в файле.
Сборку можно параметризовать типом cpu (переменная cpu_name). Из консоли будет как-то так (в Креаторе похожим образом):
qbs build project.cpu_name:E3
Если ничего не передавать, то используется «E1».

Далее идут вспомогательные мапы, где ключом является вышеупомянутый cpu_name, а значениями — cpu, core и perif, соответственно. Эти мапы/переменные соответствуют конфигам в папке openocd, ключу компилятора "-mcpu" и «драйверам периферии» (чтобы это ни значило), которые лежат тут.

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

Затем задаётся тип нашего продукта. В qbs любой конечный результат сборки, будь то приложение, библиотека или автогенеренный файл называется Product, а различаются они типами. Именно по типу qbs понимает, что вот эту пачку cpp файлов надо собрать как библиотеку, а вот эту — как приложение. Типов у одного продукта может быть несколько, как в нашем случае — помимо сборки «приложения» мы еще собираем из него «bin» и «hex» файлы.

Дальше мы подтягиваем зависимость от модуля cpp, это модуль, который содержит правила для сборки всякого нативного стаффа (будь то c++, чистый си или objective-c). Грубо говоря, этот модуль «объясняет» qbs как из cpp файла получить конечный «application».

Дальше мы добавляем разные файлы в наш проект — это то, что мы будем собирать. Конструкции вида app_path + "/**/*", по сути, включают все файлы в папке app_path. Так обычно не делают, а перечисляют каждый файл явно, но так как это шаблон, то можно и так. Само по себе добавление ничего не делает, просто qbs теперь знает, что наш продукт зависит от только этих файлов.

Затем задаются различные флаги компилятора. Некоторые опции qbs знает сама и для этих опций выделены отдельные переменные, которые в нашем случае еще и зависят от инварианта сборки (дебаг/релиз)

А дальше начинается самое интересное — это правила сборки для файлов «bin» и «hex». Правила еще и отличаются в зависимости от дебага и релиза, в дебаге мы собираем только «bin»

Когда qbs что-то собирает, она смотрит на то, какой тип продукта мы хотим, ищет подходящее правило сборки с таким же выходным типом, смотрит, от чего это правило зависит (т.е. какой тип оно хочет на вход) и так по цепочке до тех пор, пока не найдет файл с нужным входным типом. В нашем случае цепочка примерно такая «cpp файл -> внутренняя кухня qbs -> application -> bin».

Собственно, вход правила задается переменной input, выход задается с помощью айтема Artifact (впрочем, есть также пропертя outputArtifacts), просто способ через Artifact выглядит «декларативнее».
То, как именно собирать, описывается скриптом prepare, который возвращает Command для отложенного вызова системного процесса (что-то типа future). Бывает еще JavaScriptCommand, которая вызывает кусок кода на жабаскрипте.

В общем, как-то так, если где наврал, поправьте=)
А потом один такой курсант вырос и теперь управляет страной… Простите за политоту
Угу, давайте возьмем какой-нибудь std::sort и сравним с qsort

Что мы видим? Компаратор во втором случае передается как указатель на функцию, то есть мы _всегда_ обязаны вызывать эту функцию, пихать значения в регистры, делать джамп, вот это всё. В первом случае компилятор может взять и заинлайнить компаратор (если там что-то тривиальное, типа сравнения Точек).
Во втором случае тело функции находится в библиотеке, что, опять же, заставляет компилятор делать явный вызов. В первом случае всё также может заинлайнится.
Итак, как N+1 гарантированных вызовов функций могут быть быстрее 1 или 0 вызовов функций?
Поэтому мне гораздо больше нравится стиль, принятый в Qt (Doxygen такое тоже умеет, хз насчет Ява-дока):
    /** 
     * Creates a new Product with the given \a maker and \a price.
     */
    Product(String maker,double price){
        this.setMaker(maker);
        this.price=price;
    }


Количество боилерплейта сведено к минимуму (что не отменяет капитанства комментария, но а как прокомментировать конструктор?)
2D графика в последнее время очень не сильно изменилась по той простой причине, что это простой подход, но упершийся в потолок развития. Императивный подход (а-ля, нарисуй круг, линию, потом дугу) весьма тормозной, гораздо производительнее использовать 3Д библиотеки и рисовать ими 2D.
Или, с другой стороны, дальнейшее развитие 2D рисования — это выкинуть текущее АПИ в помойку и сделать новое с нуля; что и происходит (но только в 3D) — Vulkan, Metal

Information

Rating
Does not participate
Location
Den Haag, Zuid-Holland, Нидерланды
Date of birth
Registered
Activity