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 ()
Последнее исправление: Deleted (всего исправлений: 13)
Ответ на: комментарий от Dendy

qt5_use_modules

Ох уж это извечное CMake'овское: вводим, а чуть позже депрекейтим и забиваем на backward compatibility.

Вообще они начинали хорошо: давайте мол сделаем CMake-модули к популярным либам и будем их обновлять. А потом кончили за упокой и отказались от своего же решения. В итоге теперь каждый проект тянет за собой собранные по помойкам чужие CMake-модули и криво написанные свои. Впрочем, об этом я уже писал когда-то:

Оценки хелловорлда тред (комментарий)

забудь всё, что ты знал.

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

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

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

Нет. О чём и речь. Можно посмотреть на waf, например. На молодой meson. И ещё лёгкий premake на Lua. Если ты любишь Java — смотри в сторону Gradle. Существуют проекты (C/C++), которые используют Gradle для сборки. Например, https://github.com/dreamstalker/rehlds

Я в большинстве случаев использую CMake. Он популярный и различными костылями затачивается под свои нужды. Это не значит что он мне нравится, но в IT довольно часто выигрывает самое угрёбищное решение из представленных. В случае с CMake он просто был одним из первых, которого поддержали крупные игроки рынка.

Red Hat недавно сделал свою ставку на Meson и перевёл кучу проектов на него: XOrg, GNOME, systemd и пр. Но хрен его знает что теперь будет с Meson'ом в связи с последними новостями по Red Hat.

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

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

Бутстрапить CMake нет особой необходимости, так как он внешний по отношению к Qt. Там мы дойдём для сборки GCC под нужды :) Пакет или бинарь CMake'а, установленный компилятор и сборщик (make/ninja) и ты готов к действиям.

А с QBS возникает проблема. Например, добавили новый модуль в Qt. Он специфичный и ему нужна новая версия QBS для сборки. QBS молодой проект который должен был активно развиваться, а посему та версия, что шла бы в пакетах дистрибутива, является де факто устаревшей и неспособной на сборку. И здесь действительно начинаются циклические зависимости. Либо старым QBS собираем новый, а новым потом собираем Qt, либо собираем новый QBS другой системой сборки, а потом собираем весь Qt собранным QBS'ом. При этом сам QBS уже весомая часть Qt. Что делать со собранным QtQML, который собирается в процессе компиляции сборочного инструмента? Пересобирать его снова собранным QBS или оставить как есть и тогда в результирующем выхлопе будут части Qt собранные разными системами сборки? Всё это проблемы, которые без внешней тулзы по отношению к Qt красиво не решишь.

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

Ох уж это извечное CMake'овское: вводим, а чуть позже депрекейтим и забиваем на backward compatibility.

Этот модуль был написан в мохнатые годы, пока в самом Qt не было поддержки. Помню пользовался им лет 6 назад. Естественно, что как только модули CMake стали частью Qt, старые задепрекейтили.

Думаю, что они и сейчас работают для тех версий Qt (5.0?), только кому они нужны. Естественно, этот модуль невозможно использовать для новых версий Qt из-за множества изменений. Здесь винить разработчиков CMake не в чём.

Dendy ★★★★★
() автор топика

Окей, как переводить проект с 4300 (4279 если быть точнее) с qbs на cmake, если я совершенно не знаю его (cmake)? Могу я где-то найти уроки, где я могу освоить его за 10-20 часов (нашел это, но это больше похоже на какой-то сборник рецептов)? Надеюсь, Digia не до конца обезумели, и выложат конвертер qbs->cmake.

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

А примитивного уровня и достаточно в большинстве случаев для предупреждений.

Заглушить warning'и при компиляции старого Legacy-кода на новых компиляторах, на кривом системном API и пр. довольно популярный юзкейс при работе с чужим кодом. Особенно для кросс-платформы.

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

А дальше уже идёт статический анализ средствами связки clang/clazy и пр. инструментария.

CMake в кросс-платформенное задание предупреждений не умеет.

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

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

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

Digia

The Qt Company же.

Ну и в тыкву qbs ближайшее время не превратится.

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

предупреждений для разных компиляторов вагон. warn_on/warn_off это очередной костыль

С таким подходом можно считать и set (CMAKE_CXX_STANDARD 11) костылём.

Однако, его сделали. И он удобен. Правда, насколько я помню, без поддержки 03.

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

С таким подходом можно считать и set (CMAKE_CXX_STANDARD 11) костылём.

Всё-таки критерии стандарта C++ чётко определены, поэтому подобный вызов подразумевает вполне конкретное поведение. Чего нельзя сказать про всевозможные предупреждения, которые нигде и никак не специфицированы.

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

Всё-таки критерии стандарта C++ чётко определены, поэтому подобный вызов подразумевает вполне конкретное поведение

$ cat CMakeLists.txt 
set(CMAKE_CXX_STANDARD 03)
add_executable(test shit.cpp)

$ cmake . 
CMake Error at CMakeLists.txt:3 (add_executable):
  CXX_STANDARD is set to invalid value '03'

Да, скорее всего у Clang и MSVC ключ и стандарт для C++98 и C++03 один.
Но ведь у GCC был отдельный флажок -std=gnu++03, насколько я помню. Или он тоже уже совмещён?

Чего нельзя сказать про всевозможные предупреждения

ИМХО, похожая ситуация. Куча ключей для стандартов у разных компиляторов аля 0x, 1z, 1y, 2a. Но для типовых значений утверждённых стандартов (кроме 2003-го), опция есть. Что мешает сделать типовые опции «отключить предупреждения» и «включить наиболее высокий уровень предупреждений»?

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

А когда надо настроить что-то другое, дай угадаю, в qmake будет тот же if-elseif, да?

Когда нужно настроить что-то другое, тогда и будет разговор.

В данном случае цель:

Включить максимально высокий уровень предупреждений компилятора (GCC тут особенный, конечно, и у него нельзя включить все предупреждения, как и отключить все оптимизации. Но это уже другой разговор).

В QMake: CONFIG += warn_on
В QBS: warningLevel = «all»
В Premake: warnings «Extra»
В CMake: портянка из if-elseif-else или НЕКРОССПЛАТФОРМЕННАЯ переменная окружения (то бишь портянка if-elseif-else выше по уровню CMake).

Цель #2: Выключить предупреждения компилятора при сборке кода.

В QMake: CONFIG += warn_off
В QBS: warningLevel = «none»
В Premake: warnings «Off»
В CMake: портянка из if-elseif-else или НЕКРОССПЛАТФОРМЕННАЯ переменная окружения (то бишь портянка if-elseif-else выше по уровню CMake).

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

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

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

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

Это не только OK, а отличный подход. Иначе всё превращается в таких лапшевидных монстров, как autotools m4, наркоманский CMake DSL на макросах, QMake DSL с захардкоженным стилем программирования и прочие непотребства.

У waf, кстати, Python. А у Premake — Lua.

Kotlin dsl для gradle, когда обрастет документацией, станет тоже норм решением с точки зрения гибкости описания билда.

Да у Gradle и так сейчас нормально, ибо Groovy.

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

зато портянка будет ожидаемо cыпать ошибками error: unsupported option '-Wshit' и требовать правку CMakeLists.txt или переменную окружения на отдалённо поддерживаемом компиляторе, а у прочих всё будет скорее всего ровно и гладко

Пофиксил тебя, не благодари.

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

Параметр CMAKE_CXX_STANDARD это абстракция, потому что не существует стандартных ключей абстрактного компилятора в вакууме. Главное, что для поддерживаемых значений (которые начинаются с 11?) код гарантированно будет собираться соответствующим стандартом.

У предупреждений вообще нет никакой совместимости, это детали реализации и они никак не специфицированы. Я лучше напишу короткую простынку под каждый компилятор, зато для читателя будет понятно как она работает.

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

Это не только OK, а отличный подход. Иначе...

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

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

CMAKE_CXX_STANDARD

Не нужно. Долой прокси-слои:

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -march=x86-64 -Wall")

А ежели это плач на тему «хочу единые настройки для разных компиляторов», то так всё равно не бывает.

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

код гарантированно будет собираться соответствующим стандартом.

Да ладно. А во всех ли компиляторах? Что насчёт всяких там Watcom C/C++, IBM xlC/C++, да даже того же ECC под Эльбрус. C++11 там есть, а вот отработает эта опция в CMake или нет — тот ещё вопрос. CMAKE_CXX_STANDARD точно такая же абстракция и точно такие же детали реализации в каждом компиляторе, как в случае с опцией (CMAKE_CXX_WARNINGS Off), если бы она была.

Стандарт задекларирован. А вот ключи для его активации, будь это -std=c++11 или --use_c++11_luke, не стандартизированы. Однако, это не мешает разработчикам CMake добавить вызовы нужных ключей стандарта для каждого поддерживаемого CMake'ом компилятора. Что мешает им сделать так же в случае с -Wno-everything,-w,/w — загадка.

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

В своём «hello world» я использовал meson, я не профи, но если я правильно понял суть проблемы с qmake, там с этим всё было в порядке. При изменении не нужно было дергать meson, ninja сама всё разруливала.

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

Если что-то стандартом не поддерживается, то проект не сконфигурируется. Для этого при первой конфигурации запускаются тесты фич запрашиваемого стандарта. Ещё раз, никого не волнуют ключи компиляторов, которыми настраивается стандарт, если они вообще есть. В случае ошибок никаких абстракций быть не может, а если даже они приблизительно и есть, то имеют мало смысла, потому что каждая конкретная опция обрабатывается человеком индивидуально. Что-то принудительно включается, что-то выключает. А не абстрактно везде «ошибок побольше» или «поменьше».

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

Да, концептально мезон очень схож с CMake с точки зрения разделения этапов конфигурации, сборки, обработки зависимостей. Сам не пользовался мезоном, но никаких причин подозревать в нём болячки qmake 15-тилетней давности нет. В конце концов, он самый молодой из существующих систем, выучившийся на ошибках старших товарищей.

Dendy ★★★★★
() автор топика

Просто победа, сгенерировал conan зависимости для cmake, и сразу понял, какое у меня прекрасное будущее будет. Для сравнения: Cmake; QBS. Наверное, надо завершать карьеру программиста C++.

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

Что-то принудительно включается, что-то выключает. А не абстрактно везде «ошибок побольше» или «поменьше».

Из всех современных систем сборки наверное только CMake такой отсталый, что для него приходится писать простыни.

В конце концов, он самый молодой из существующих систем, выучившийся на ошибках старших товарищей.

Как минимум одну ошибку в головах CMake-разработчиков Meson уже пофиксил:

$ meson --help
  --werror              Treat warnings as errors
  --warnlevel {0,1,2,3}   Compiler warning level to use (default: 1).
EXL ★★★★★
()
Ответ на: комментарий от EXL

А если у меня в cmake-скрипте вот такое? "-Wall -Wno-noexcept-type" Это для gcc. Не факт что для clang все названия ошибок и ворнингов будут такими же; я скорее поставлю на наоборот. И в результате как только требуется тонкая настройка, тут же этот фасад-API универсального для всех размера идёт лесом.

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

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

Фасад-API универсального для всех никто и не требует. Нужны возможности:

1) отключить предупреждения.
2) включить их хотя бы тупо в дефолт без всяких там уровней.

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

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

CMake можно много в чём винить, но только не в обработке зависимостей

Вообще-то где-то в документации cmake черным по белому написано, что при обсчете зависимостей он использует самодельые костыли, которые не поддерживают #ifdef-ы. И выше по треду что-то про protobuf было.

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

если тебе нужно что-то специфичное, то, по крайне мере в qbs, не знаю что там у остальных есть Properties item где ты можешь поставить свои флаги (причем можно добавлять к существующим флагам через concat) для определенной платформы, а для всех остальных выставить warnLevel, и это будет работать. Это просто экономия времени и глаз дальнейших читателей.

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

По поводу зависимостей. qmake написан на самом Qt

Откуда вы такие берётесь? ldd лень запустить?

user@localhost:~$ ldd /usr/lib/x86_64-linux-gnu/qt5/bin/qmake
	linux-vdso.so.1 (0x00007fff9c16f000)
	libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f5d16d08000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f5d1696a000)
	libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f5d16752000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5d16361000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f5d17529000)
anonymous
()
Ответ на: комментарий от EXL

Red Hat недавно сделал свою ставку на Meson и перевёл кучу проектов на него: XOrg, GNOME, systemd и пр.

Вот только Red Hat напоминаю, мёртв, и поэтому уже не имеет никакого значения, какую утилиту пара школьников из него свелосипедила последней, чтобы обеспечить бывшему начальству контроль над используемыми инструментами.

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

где-то в документации cmake черным по белому

Так всё-таки где-то-там-незнаю-чёрти-где или чёрным-по-белому-калёным-железом-выгравировано-как-отрезано? Ссылку.

Зависимости в C++ генерирует компилятор. Про протобуф я там же выше по треду отписался.

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

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

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

Капец ты отбитый...

Нет, Вася, это ты отбитый, а чувак тебе все верно толкует. Система сборки должна быть надежной, как скала - то есть всегда приводить артефакты в соответствие коду и конфигурации. Если ты этого не догоняешь, тебе надо бы сменить разработку ПО на лепку борщей.

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

А что не так? Согласно дискуссии с Тобиасом в рассылке и просто по почте, пока САМ CMake не предоставит возможности через его вызовы добавлять файлы к целям, добавления файлов не будет. CMake будет использоваться только как источник информации для формирования кодовой модели. В данный момент, по возможности, используется CMake Server, что бы разбирать проект, параметры, файлы, формировать кодовую модель. Переход Qt на CMake этого не решит. Парсер CMake никто писать не собирается.

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

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

Ну... если они перекинут силы с плагина для qmake на CMake, может что и случится. Хотя... За последний год-два плагин для CMake и так изрядно преобразился. Появились фичи, которых не хватает уже и в других IDE, к примеру в CLion, к примеру: возможность визуально задать конфигурацию для CMake, а если CMake файл написан для людей, ещё и с отображением пояснений, для чего опция нужна, сформировать списки возможных параметров и т.д. (и всё, согласно официальной документации CMake).

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

compile_commands.json сейчас не сильно нужно для QtC. В новых CMake появился Server Mode, QtC его использует, что бы напрямую спросить про файлы, таргеты, параметры сборки и т.д. и потом передать это знание в модель кода (читай: парсер C++, который сейчас на основе clang/llvm). Ровно как и генератор для qmake/qbs не сильно нужен при таком функционале.

А проблему ДОБАВЛЕНИЯ файлов через IDE генераторы тоже не решат (ровно как и Server Mode): они из существующего CMakeLists.txt формируют что-то, что дальше может строить код, а не наоборот.

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

Когда нужно настроить что-то другое, тогда и будет разговор.

Ну вообще-то, если у тебя не helloworld, то на каждой платформе сборка почти всегда отличается многими параметрами. Потому тулчейн сконфигурировать надо.

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

Версию точно укажи самого QtC. Хотя, я вообще на master ветке сижу :)

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

В KDevelop 4 это решалось собственным парсером CMake. Который время от времени подгонял и всё равно приходилось писать ручками. В новых KDevelop его выпилили. В Clion схожая картина.

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

Шаблон поменять можно: PREFIX/share/qtcreator/templates/wizards/classes/cpp/file.h

либо свой написать, что бы стандартный не трогать.

h4tr3d ★★★★★
()

Сегодня:

Qt отказывается от qmake

Завтра:

Qt отказывается от Qt и мертвого гэтэка три

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

А проблему ДОБАВЛЕНИЯ файлов через IDE генераторы тоже не решат (ровно как и Server Mode): они из существующего CMakeLists.txt формируют что-то, что дальше может строить код, а не наоборот.

Это интересная проблема со скриптовыми неструктурированными системами сборок. Те же Gradle и Qbs изначально ориентировались на декларативное описание и семантический разбор скрипта сборки. Далеко за примерами ходить не нужно, Android Studio прекрастно умеет комбинировать ручную правку проекта с мышекликанием. Равно как и QtCreator для дизайна QML.

Возможно и CMake это научится путём понимания определённых маркеров в скрипте, хотя это прямо противоречит его императивной сути описания проекта.

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

Такое не всегда работает. Например, при сборке проекта с Qt автоматически в конец CMAKE_CXX_FLAGS будет дабавлен Qt-шный -std=c++11, который заменит -std=c++17. CMAKE_CXX_STANDARD исправляет эту проблему.

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

ибо Groovy.

Гарантированная подсказка в ИДЕ (ну когда они её починят) и компил тайм чек - то чего реально не хватает популярным системам сборки

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

Возможно и CMake это научится путём понимания определённых маркеров в скрипте, хотя это прямо противоречит его императивной сути описания проекта.

Ну, если следовать рекомендациям не юзать GLOB, то дело не слишком сложное.

С другой стороны, элементарно делается добавление файла в проект генератора: создаем файл, перезапускается cmake dir, а в каком-нибудь сгенерённом эклипсе проект переподгружается с новым файлом уже. Такое же в QtCreator сделать бы

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