Pull to refresh

Comments 38

первый раз про такое слышу, очень полезно!

Ого, не знал даже о таком, хотя это и выглядит как "мы добавили компилятор в компилятор.."

Из личного опыта cMake уже давно шагает куда-то не туда. Он должен удобно описывать сборку, а не превращаться в надстройку и еще один язык программирования со своими особенностями и подводными

Для себя сформировал такую линейку сложности сборки:

  1. bash - все просто и понятно. Даже если чего то не хватает или криво, то ты это поймешь. Проблемы могут быть но очень редко нерешаемые.

  2. Makefile - эдакий наследник баш-скриптов. Сложности могут быть и первым камнем преткновения может вылезти то, как и откуда запускается этот самый мейкфайл в системе (что проблема потому как даже явное прописывание параметров запуска может не помочь по причинам). Даже если какие-то проблемы с мейкфайлом, всегда можно его "руками" упростить до простых консольных команд

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

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

Он должен удобно описывать сборку, а не превращаться в надстройку и еще один язык программирования со своими особенностями и подводными

Отчасти я согласен. Но CMake изначально был надстройкой для упрощения кроссплатформенной сборки (аналог automake/autoconf).

Сейчас в CMake и правда добавили очень много всего. Но я не сказал бы, что это проблема. Ведь необязательно использовать весь функционал CMake. Что бы сделать простейший C/C++ проект, хватит CMake скрипта из трех команд: `project()`, `cmake_minimum_required()` и `add_executable()`.

Версии, особенности, подпараметры и прочая срань.

Да, с обратной совместимостью и правда бывают нюансы. Еще есть проблема того, что концепции использования CMake периодически меняются. И одни рекомендованные практики заменяются другими.

А еще подводные зависящие от того, как и где запускают и в каком именно режиме. А еще они очень легко превращаются в огромную запутанную вермишель кода, вермишель которая очень легко позволяет подключать файлы зависимостей из-за чего запутанность только преумножается

Думаю это сильно зависит от того, кто пишет CMake скрипты. На любом языке можно написать плохой код =)

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

Интересно, с таким я не сталкивался. Может есть примеры "оберток на Python для сборки сишников"?

Интересно, с таким я не сталкивался. Может есть примеры "оберток на Python для сборки сишников"?

то же platformio это чистый питон

Китайцы если соизволяют выложить в открытый доступ какие-то средства для сборки и отладки, то они на питоне в 9 случаев из 10 (исключения это чисто сишные тулзы)

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

Думаю это сильно зависит от того, кто пишет CMake скрипты. На любом языке можно написать плохой код =)

Я до сих пор вспоминаю SDK для poketbook которое не удалось завести даже в режиме отладки просто потому что иди нафиг, вот почему) Нигде больше не встречал настолько запутанных макарон для сборки (благо есть готовые докер образы для работы с этой сранью)

platformio

Точно, забыл про него. Там они используют SCons. Он конечно написан на Python, но все же это не совсем "python скрипты для сборки". Хотя штука интересная, правда я никогда не использовал ее вне `platformio`.

Мне просто интересно, что именно делают в python скриптах. Делают подобие bash скриптов для вызова компилятора?

Китайцы если соизволяют выложить в открытый доступ какие-то средства для сборки и отладки

Вполне может быть. Хотя что касается китайских микроконтроллеров, то там чаще выкладывают проекты для Keil/IAR/CubeIDE.

при всей моей нелюбви к питону (и в VSC), platformio получился неплохим. Его возможности встраивания скриптов прямо в сборку и не только (логи например) прям киллер-фича.

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

при всей моей нелюбви к питону (и в VSC), platformio получился неплохим.

Тут я полностью солидарен =)

Проблема в CubeIDE и прочих визуалках без обратной связи из исходного кода "наверх" - невозможность динамической реконфигурации. Иными словами, допустим, в какой-то момент необходимо переключить ШИМ в шестишаговый режим, пробросить UART сделав Remap пинов, по ходу дела менять режимы DMA например. То есть система программируется изначально как нечто статическое. Конечно для большинства простых задач этого хватает но на специализированных применениях это может создать больше проблем. Плюс HAL/LL вместо регистров это отдельная тема, попытка языковыми средствами из 70-х с надеждой на упорство компилятора создать абстракцию, вроде как ООП на С, и да и нет, в итоге проще сделать какой-нибудь кодогенератор и единственный заголовочник.

Что касается сборки на С, когда надоело каждый раз переписывать в h-файлах прототипы функций, смотреть на ворнинги и эрроры, сделал perl-скрипт, который сканирует все C, достаёт оттуда прототипы структур/функций (написанных в едином стиле дабы не усложнять парсер до уровня bison/flex) и кладёт в единый заголовочник. Перед сборкой выполняется этот скрипт который вытаскивает из исходников необходимое. Для идентификатора функции использовал пустой макрос DEFUN. Именно в этом русле языки программирования до сих пор не обзавелись встроенными средствами для системы построения. Ничего кроме #pragma и /*-*тут мои настройки-*-*/, всяких __меня_не_трогать__ не подвезли. Хотя вполне могли были быть ключевые слова вроде link, make, debug, version, compile_unit с указанием что эту функцию оптимизировать, эту для отладки, у той одна версия, у этой другая, вот там имя функции юнит теста (а не файла) итд

Как-то так
my ($statick, $curlopenbr) = (0,0,0,0,0,0,0);
my $strtag = "";my $strname = "";my $curlword = ""; my $curlclword = "";
my @statarr = ();
my $str;
my $stracc;
foreach my $stra (@raws)
{
    $str = $stra;
    #search for DEFUN keyword
    #skip definition
    if ($str =~ /DEFUN.+\;/g)
    {
        $statick = 0;
        $stracc = "";
        next;
    }
    if ($str =~ s/(DEFUN.+)\{// and $statick eq 0)
    {
        $str = $1;
        push @statarr,$str;
        $statick = 0;
        $stracc = "";
    }
    if ($str =~ s/(DEFUN.+)// and $statick eq 0)
    {
        $statick = 1;
        $stracc = $1." ";
        next;
    }
    if ($str =~ s/(.*)\{// and $statick eq 1)
    {
        $stracc = $stracc." ".$1;
        push @statarr,$stracc;
        $statick = 0;
        $stracc = "";
    }
    #accumulate brackets and DEFUN content
    if ($statick eq 1)
    {
        $stracc = $stracc.$str." ";
    }
   
}

у меня за годы работы собралась целая библиотека баш-файлов которые я встраиваю в автоматизации. Чисто по коду очень много что делаю генерируемым и по комит-хукам, например версионность и прочее это с нуля генерируемый *.h файл. Работа с памятью тоже через генератор, где саму структуру я описываю в csv файле.

Руками все писать вы далеко не уедите. За перл хз, собсвено потому и и баш, а не питон, что бы меньше головняка с переносами и развертываниями.

Собирал всякую opensource дичь и там часто встречается Meson. Он проще чем СMake и кросс-компиляция проходила всегда легче. Можно его поставить между 2)Makefie и 3)CMake в списке.

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

Растовский cargo в этом плане интересен тем что там есть четкое разделение между простой декларативной частью в виде toml конфига, и опциональной кастомной логикой на самом расте. В cmake же пытаются это объединить в одного монстра.

Проблема в том что сделать это с сохранением обратной совместимости совсем непросто, и выходит какой-то монстр.

Думаю это болезнь любого развивающегося проекта. В целом,политики не плохо справляются с сохранением обратной совместимости.

CMake и правда "в последние годы" стал понятнее и логичнее.

Все изначально так и было. Мейк, симейк и прочее были разработаны в другую эру, когда сложность была совсем другой, а для установки зависимостей хватало системного пакетного менеджера.
И вот с функцией пакетника или сложной, многоязыковой сборки они не справляются.
И это не лучшее что есть на рынке. Есть bazel, nix, meson. Это для любых языков.
Для раста есть cargo который лучше любого на голову, но любой шаг за пределы растовой экосистемы - и ты уже пишешь свой nix или bazel.
В 2025 без владения инструментами для современных задач сложной сборки никуда. А попытки натянуть старье на новые задачи, а особенно написать сборку на питоне "потому что он простой, понятный и доступный всем" ВСЕГДА заканчиваются переизобретением nix и bazel, которые работают быстрее и решают задачу в несколько строк кода на своём языке, который изначально спроектирован под управление пакетами.
Особенно когда дела доходят до сборки и тестирования в ВМ.

Тут возникает довольно серьёзная проблема, когда скомпилированный пакет не имеет каких-либо идентификаторов от системы сборки. И нет никаких средств проверить целостность, атрибуты и единство пакета, который был собран самостоятельно и внедрён в систему или локальное окружение помимо репозитория. В основном упор идёт на дату и номер версии, а также то что если изменить 1 байт - это уже новый пакет. Поэтому в системе разрастается зоопарк версий, особенно весело когда программа тянет за собой двоичники необходимых зависимостей, что для .NET что для MSVC redistributable, .deb/.rpm могут притянуть различные только им нужные .so, Python 2.7/3 - уже стало именем нарицательным, если песочница использует символические ссылки - уже достижение. В подавляющем большинстве случаев весь этот довесок летит в Program Files или bin. Вообщем по-всей видимости без инфраструктурных изменений вряд ли что-то можно улучшить существенным образом.

По другому наверное проще сказать в сторону cmake. Он пытается стать пакетным менеджером универсиальным в стиле С++. Поэтому он добавляет куча винтиков для этого, а каждый потом пилит свой пакетный менеджер ( Избыточно), вместо того чтобы быть просто пакетным менеджером. С точки зрения написания простого проекта и привинтить к нему пару тройку зависимостей - очень просто

Спасибо, теперь знаю что и vscode это можно, а то раньше сложные cmake в плагине visualgdb отлаживал

Я сам был сильно удивлен, когда узнал про эти фитчи =)

Про плагин не знал, спасибо. Очень интересно, что статья по вашей ссылке 2018 года. Хотя поддержка отладчика в CMake была добавлена только в 2023 году. Получается Visual Studio сделали какой-то свой отладчик. Хитро.

CMake медленно но верно как было замечено превращается в уже почти в графическое IDE. Наверняка уже завезли вещи связанные с Git, проверкой версий пакетов онлайн, среды окружения, тестирование самого компилятора на правильность. Но опять-таки краеугольный камень - что он не заходит внутрь файла забрать пользовательские идентификаторы, ориентируется на время/дату и прочие системные штуки при обновлении, не создаёт атрибутов файлов или дампов этапов построения с обработкой исключений при ошибках компиляции с целью не прервать процесс а максимально скомпилировать всё что без ошибок. Ну и разумеется танцы с макросами и зависимыми переменными. Вообщем скорее всего этот инструмент поглотит некий perl/python с явной кодогенерацией по шаблону из мета-языка, пригодного для конкретного применения, включая тот же bash/bat для сборки (локальной/тест/релиз). CMake же пытается объять необъятное и уже требует ненулевой порог входа для обучения.

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

Кажется это не зона ответственности CMake. Он ведь не занимается сборкой проектов. CMake - это генератор сборочных систем. Он просто генерирует файлы той сборочной системы которую вы ему укажете (Make, Ninja и т.д.). А дальше сборкой занимается указанная сборочная система.

Ну и разумеется танцы с макросами и зависимыми переменными.

А что тут имеется ввиду?

Имеется в виду то что до сих пор в качестве аргументов используются различного рода вещи, которые тянутся из того что нужно собрать в систему сборки, не важно какого высокого она уровня. Иными словами включить/выключить CUDA/AVX/SSE, сделать море #define-ов, сгенерировать какой-либо .pm итд. То есть до сих пор нет каких-то встроенных в сам язык средств, поддерживающих сборку, иными словами требуется пересмотр самого принципа текст-компилятор-редактор связей-отладчик с наличием утилиты в этом механизме, отвечающей за сборку, включая данные о распределении памяти, опции подключаемых библиотек, версий, причём, инвариантно к именам/расширениям файлов, собирая непосредственно объекты и функции но это уже не задача make. До сих пор системы сборки и контроля версий по-сути обёртка на принципы работы и тулкиты, которые были ещё с середины 80-х. В даже в настоящее время проект - это просто папки и набор файлов в них с описанием того что нужно с этим сделать, вместо указания того, что нужно сделать непосредственно с их содержимым.

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

Я не понимаю разницу?
Или хочется чтобы, то как собирается приложение было сразу в исходном коде?

Именно так. Что изменение коммента не есть изменение кода что не нужно перекомпилировать весь мир или обходить это с использованием иных абстракций. То есть в самом коде начинают присутствовать элементы версий, git, контрольные суммы, даты/дескрипторы создания, модификаций функций и классов, включая всевозможные фичи для отладки вроде лишних assertion, опций оптимизации конкретного фрагмента кода начиная от -O0 и заканчивая -O3, когда необходимо отладить только вот какой-то конкретный кусочек функции без её вытаскивания в отдельный файл, прагмы станут уже нормальными опциями для статического динамического размещения, map/ld-файл уже как-то ближе к коду а не отдельная сущность, включая настройки, нормальные унифицированные интрисики как стандартное расширение языка и многие другие фишки. Вообщем система сборки должна уже давным давно проникнуть внутрь компилятора и стать его частью а не костылём снаружи, включая управление precompiled headers, опций изменений, макрорасширений/шаблонов, внешние ссылки на линковку по идентификаторам а не по файловой мешанине, избежать дублирование зависимостей итд итп.

То есть в самом коде начинают присутствовать элементы версий, git, контрольные суммы, даты/дескрипторы создания, модификаций функций и классов, включая всевозможные фичи для отладки вроде лишних assertion, опций оптимизации конкретного фрагмента кода начиная от -O0 и заканчивая -O3

Если добавить все это в код, то не станет ли сложнее читать и понимать код? К тому же, если потребуется скопировать файл из одного проекта в другой, то придется копировать с "элементами версий и опциями оптимизации", что может быть не нужно в другом проекте.

Например, сейчас можно написать C файл, который потом использовать в разных проектах с разными компиляторами и системами сборки. А вашем случае, получается что файл с кодом будет жестко задавать то, как его собирать и использовать. Мне кажется это не совсем правильным поведением.

Я думаю, код в первую очередь должен описывать логику работы программы, а не то как его компилировать.

P.s. Хотя мне нравится мысль о том, что система сборки может научится не пересобирать код если изменились только комментарии.

Это уже другой вопрос что сложность понимания кода дополняется сложностью понимания вспомогательных инструментов - помимо языка надо знать bash/bat/git/флажки компилятора, различные прагмы-макросы, непосредственно make-языки. Иными словами количество вбираемой информации не изменится если её часть переместится внутрь языка и станет его атрибутом, то есть можно использовать можно нет. Ну это как С++ вместо ООП и прочего синтаксического сахара можно вполне использовать как С с классами или просто как процедурный. Бывало даже видел программы состоящие прямиком из asm-вставок, компилятор нужен был только для аргументов функции и возврата. Поэтому код, который удобно отлаживать, делать опции при сборке для тех или иных компонент кода, а не файлов, будет гораздо лучше чем если это дело отдельно отдать управлять внешним инструментом который просто сложился исторически а не был создан изначально, плюс набегают ошибки, когда действие делается не одним инструментом а двумя и более, много синхронизируемых сущностей, там один флажок, здесь другой, там имя файла не совпадает там ещё что-то, часовой пояс поменяли до уровня up to date, переменную среды не прописали, path не туда. То есть за кодом тянется дополнительная вереница исключительно системных дел. Если это уйдёт в код то он станет самособираемым и практически исчезнет необходимость во внешнем инструменте. Там на самом деле не так много необходимо будет выучить. Думаю ключевых слов version, debug, link, map, control, request, exclude, update, hash, options, optimize, code_id, testfunc и что то в этом роде будет не так много, которые практически полностью позволят настроить как и что собирать если что-то не нравится по умолчанию. Движение на этот счёт имеется в виде танцев с бубном но как-то слабо из за гигантского легаси и разросшихся вспомогательных инструментов, что пора бы уже комитету C++26 уже сделать более дружелюбным к системам сборки и версионирования наравне с другими языками.

Можно ли это реализовать в новом компиляторе c++, который будет одновременно поддерживать стандарт и расширять его необходимыми фичами для самособираемости кода? С учетом модулей, возможно даже без нестандартных pragma можно будет уже собирать код с дефолтными флагами.

Так все новые фичи для компилятора могут быть инициированы как внутри исходника, например, какой-либо прагмой зависящей от версии а также явным указанием. Например gcc поддерживает опции -std=c23 или что-то вроде -std=iso9899:2023. При компиляции можно указать какой именно стандарт и расширение использовать. Вообщем в любом случае все эти свистки командной строки должны уйти внутрь кода и самого языка и убрать файл как структурную единицу проекта, это ведь просто именованная запись а не сам код так сказать. Иными словами проблему путей, линковок, зависимостей, символических ссылок, всяких copy/rm/ls и прочих песен с файлопапками искоренить на уровне идентификаторов и пространств имён в самом языке. Компилятор будет понимать файлы и подкаталоги как единое целое, но внутри вполне всё может быть разбито на проекты, например, ключевым словом project, нечто вроде архива, производить индексацию библиотек, синхронизацию итд. Вообщем это уже комбайн для сборки, но один, без распыления на отдельные утилиты со своими капризами и запросами. То есть меняется мировоззрение по самому представлению проекта уже вне файловой системы на языке предметной области. Конечно все привыкли к тому чему учили, но это не может уже продолжаться полвека.

А как управлять внешними зависимостями? Единый репозиторий пакетов, где все лежит в стандартизированном виде, или поддержка различных инструментов, как клонирование напрямую с git или штуки на подобии conan и vcpkg. А в каком виде? Так же в коде типо `import "https://github.com/fmtlib/fmt#master"`?

Совершенно верно. В этой концепции в принципе нет разделения на тип хранилища объектов. Это может быть облако сервер:порт, сайт https, запрос к БД, к диску C: или по UART к контроллеру. Система управления версий изначально была заточена под управление именно файлами а не непосредственно программными элементами. В этом и есть главная беда. Потенциально в новых подходах указывается источник данных и необходимые атрибуты, такие как версия, хеш, дата, некое имя/ID (например, обозначающее ветку), и указывается для конкретно того что нужно - пространства имён, функции или класса. Нет смысла тянуть файл который на усмотрение разработчиков может содержать пиктограммку в Base64 просто потому что так захотелось. Также на уровне линковки в elf/so/dll уже давным давно должны появиться атрибуты версий объектов, идентификаторы, контрольные суммы. Поэтому посреди бинарников всегда можно выбрать только то что необходимо а не дублировать всё по папкам или релизить вместе с программой, также это позволяет инкапсулировать то что является условно read-only как системная библиотека, что-то в локалях у пользователя что-то вместе с программой. Указывая эти идентификаторы практически полностью можно исключить ошибки линковки при встрече двух файлов, т к. линкёр уже будет знать что именно из них вытягивать, в противном случае надо играться с path который будет показывать откуда что брать, это вечная проблема когда необходимо держать локальный зоопарк из нескольких версий. Более того, если в объектнике, формат которого не менялся с середины 80-х будут уже более современные атрибуты, связанные с управлением версиями а не просто 64 бит этикетка, их можно объединять и укрупнять а имя файла или либы уже значения иметь не будет, содержимое может быть индексировано уже на уровне ОС, плюс взаимосвязь с объектами включения, чтобы заголовочники были также синхронизированы с dll/so (это отдельная боль), в этом случае добавляется инструкция с идентификатором, позволяющая точно согласовать версию заголовочника и двоичника.

Это все важно, но не суперпроблема.

Проблемы начинаются с автогенерации кода. Надо тут подучиться у Явы, наверное с ее атрибутами

Вот, потихоньку всё начинает приходить к общему знаменателю, который ещё вывел Ван Россум для Python-а в далёком 91м году на основе ОС Амёба. Там в конце довольно интересная публикация от 88 года на предмет Parallel make. Так вот тогда ещё предполагалось что среда разработки и язык могут стать единым целым и помогать друг другу. Это к вопросу к табуляциям которые фактически и являются атрибутами вложенности и области видимости. Также можно было бы точно такие же фичи сделать для комментариев и иных вещей. Вообщем спустя 40 лет похоже будет очередной виток.

Feb1991: X\Python\ does not (yet!) provide an intelligent input line editing Xfacility, so you have to type a tab or space(s) for each indented line. XIn practice you will prepare more complicated input for \Python\ with a

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

С профилированием нужно быть аккуратным. На моем проекте оверхед был почти в два раза.

Вы наверное имеете ввиду профилирование C программ? Просто я не совсем понимаю о каком оверхеде в CMake файлах идет речь.

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

А это можно научить работать с CMake presets?

Да. Нужно добавить "cmake.useCMakePresets": "always" в settings.json.

Потом нажать Ctrl+Shift+P, ввести select preset и тогда появится меню для выбора пресетов:

После настройки пресетов, запустите отладку тем же способом, который описан в статье.

Это расширение для VSCode. А если рабочая IDE это vim/neovim?

Я к сожалению не пользуюсь vim и мало что могу подсказать.

Но отлатчик работает по DAP. И по идее, можно написать свой плагин для vim.

UPD. Нашел плагин для neovim: https://github.com/gergol/cmake-debugger.nvim
(но не знаю насколько он рабочий)

Sign up to leave a comment.

Information

Website
yadro.com
Registered
Founded
Employees
5,001–10,000 employees
Location
Россия
Representative
Ульяна Соловьева