LINUX.ORG.RU

C++20 modules + gnu make — поделитесь success story?

 , ,


0

5

Нашёл у себя в makefile камент:

# После перехода на gcc:11 попробовал заюзать модули (объявил модуль test_MyClass_module в файле test_MyClass.cpp),
# но в .d-файлах генерируется что-то невразумительное, e.g.:
#     main.o: test_MyClass_module.c++m
#     CXX_IMPORTS += "test_MyClass_module.c++m"
# Да и QtCreator модуль не находит. Независимо от того, пихаю я gcm.cache в корень проекта или в target
# (для чего вызывал makefile из target, подкрутив в нём все пути).

Что делать с этими *.c++m и CXX_IMPORTS, откуда брать *.c++m и как всё это юзать в makefile? Хрен бы с ним с QtCreator пока что.

★★★★★

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

Неее, тут ты вручную все зависимости прописываешь. Это и я могу, но такое только для hello world годится. А мне надо чтобы .d-файлы работали.

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

Это и я могу, но такое только для hello world годится.

Так товарищ @fsb4000 только helloworld’ы то и пишет. Вот он тебе со своей колокольни и советует. Всё сходится.

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

Но лицензию он к своим helloworld’ам прикладывать не забывает.

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

Qt 3 и RPM-пакеты тоже в LSB-стандарте.

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

Неее, тут ты вручную все зависимости прописываешь. Это и я могу, но такое только для hello world годится. А мне надо чтобы .d-файлы работали.

Ok. Понял что нужно. Поищу в доках gcc, если найду, то напишу тут

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

нашёл такую бумагу:

Гы, она у меня открыта в браузере, как и предыдущая. Первую щас перечитываю, со второго раза идею понял. Авось как вторую перечитаю, что-то прояснится.

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

Модули в C++ не взлетят, скриньте.

Кэмерон статью написал: https://devblogs.microsoft.com/cppblog/moving-a-project-to-cpp-named-modules/

Может кому-то будет полезно…

Потихоньку информации будет больше как переходить на модули. По сути осталось лишь дождаться поддержки gcc и clang модулей в CMake.

И всё.

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

Но что-то ветка у меня не собирается:

Ага, вспомнил, только начав перечитывать бумагу: это пропозал по добавлению фичей в сам make. Пока что моя чуйка говорит, что пробовать все эти сырые костыли ещё слишком рано. :(

UPD: И как раз в этой второй бумаге он описывает, как должны выглядеть правила для *.c++m. Не вполне допонял при чём тут патченый make… может на обычном попробовать?… А, блин, туплю: интеграция с mapper-server же… Короче всё плохо.

// По первой бумаге (p1184r1) нашёл у себя на системе:

/usr/libexec/gcc/x86_64-pc-linux-gnu/11.2.0/g++-mapper-server
/usr/libexec/gcc/x86_64-w64-mingw32/11.1.0/g++-mapper-server

и сходу от них видна только одна польза (если запустить их вручную и добавить опцию –mapper-server как в бумаге написано): у них есть параметр, указывающий расположение кеша модулей, т.е. можно перекинуть gcm.cache внутрь target.

// Эх, сделать бы свой make с блекджеком и шлюхами у которого makefile был бы сорцом на плюсах – т.е. с внутренним DSL возможностью нормально императивно генерить правила внутри самого makefile. Короче, воспоминания о sbt для скалы покоя не дают. UPD: Надо бы глянуть на suckless.org: может там уже есть какой-нибудь suckless make?

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

императивно
makefile

Выбери что-то одно.

возможностью нормально императивно генерить правила внутри самого makefile

GNU Make умеет перечитывать зависимые вложенные make-файлы и перестраивать дерево целей.

LamerOk ★★★★★
()

В С++ уже давно есть модули. Это инклюды. Всё остальное это дошколятский высер.

anonymous
()

В общем, с учётом этого видео, почти получилось. Почти – потому что:

  1. У меня мультиплатформные цели, и правило
%.c++m : $(CXX_MODULE_PREFIX)%.gcm ;

из статьи хрен напишешь, потому что в зависимости от текущей цели этот %.c++m должен зависеть либо от target/windows/%.gcm, либо от target/linux/%.gcm. От обоих зависеть нельзя, потому что некоторые модули платформно-специфичные. Написал Nathan Sidwell с предложением как лечить: писать в .d-файлы не .c++m, а .gcm после применения маппинга.

Может быть я забабахаю это преобразование сам: вывод gcc буду писать в .d0, а потом %.d : %.d0 с преобразованием .c++m в .gcm. Тогда и правило это дурацкое вообще не потребуется.

  1. Лень возиться с .SECONDEXPANSION (см. ниже зачем), может попозже добью.

В остальном, алгоритм наклёвывается такой (если без мультиплатформенности):

  1. Приводим пути файлов в соответствии с именами модулей: модуль a.b.c (т.е. исходник, в котором есть строка export module a.b.c;) должен лежать в файле src/a/b/c.cpp. С интерфейсами, разбитыми по нескольким сорцам, пока что не заморачивался.

  2. Рисуем баш-скриптик, который делает cd src; grep -RlP '^export\s+module\s+\w' и генерирует target/module-map вида:

$root target
a.b.c a/b/c.gcm

(В случае мультиплатформенности, скриптику передаётся параметр windows|linux, он создаёт соответственно target/$1/module-map с первой строчкой \$root target/$1.)

Таким образом, .gcm-файлы ложатся рядышком с .d и .o. И тогда становится тривиальным другое правило из статьи:

%.gcm: | %.o ;
  1. Вызывать этот скриптик можно перед make (у меня есть ./build.sh, вызывающий make -j14 «$@»), а можно и правила подкрутить (несколько по беспределу, но у меня проект маленький):
/target/module-map: $(ALL_CPPs)
    @create-module-map.sh

target/%.o: src/%.cpp target/%.d target/module-map
    ...

Наверное можно было бы и без баш-скриптика, а тупо юзать маппер по умолчанию, тогда модули ложились бы в gcm.cache/a.b.c.gcm, и .SECONDEXPANSION пришлось бы применять к другому правилу.

  1. В команды CC добавляем опции -std=c++20 -fmodules-ts -fmodule-mapper=target/module-map

  2. Остаётся правило, на которое я жаловался в начале камента: зависимость %.c++m от %.gcm; здесь нужно в prerequisite заменять точки на слеши, e.g.:

a.b.c.c++m : a/b/c.gcm ;

Полагаю, как раз для этого придётся юзать .SECONDEXPANSION чтобы выполнить два $(subst ): сначала . —> /, затем /c++m на .gcm. Ежели кто подскажет-нарисует (я с ним досконально не разобрался), буду благодарен.

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

Ежели кто подскажет-нарисует (я с ним досконально не разобрался), буду благодарен.

Если есть список модулей, я бы так попробовал:

define gen_module_dep
$1: $(patsubst %.c++m,%.gcm,$(subst .,/,$1))
endef
$(foreach m, $(modules), $(eval $(call gen_module_dep,$m)))
xaizek ★★★★★
()
Ответ на: комментарий от xaizek

Хм, оно умеет кастомные функции определять? Охренеть. :)

Я уже придумал другое решение (отредактировал свой камент, добавив решение под первую жалобу): вместо этого дурацкого правила, дублирующего логику маппера, можно преобразовывать сами .d-файлы (дублировать логику маппера там, бггг). Раз сам gcc этого не делает.

Надо подумать, какой вариант лучше.

UPD. Наверное всё-таки .d0 плохо: банально SSD жалко. Алгоритм маппера тривиальный, не жалко и продублировать.

UPD2. Ай блин, мне ж для мультиплатформенности; .d0 без вариантов.

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

Хм, оно умеет кастомные функции определять? Охренеть. :)

На самом деле это просто другая запись присваивания a = b, которая может включать переносы строк. В данном случае не нужно, но так привычнее выглядит. А «вызвать» через $(call) можно любую переменную, оно просто заменяет $1, $2 и т.д. на аргументы.

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

На языке общего назначения не надо было бы в стотыщпятьсотый раз реализовывать ни строковые функции, ни прочие функции общего назначения, ни интерпретаторы, ни eval. Собственно работа с графом зависимостей – это малая часть кода make, и при этом – единственная его существенная фича. И API к этому графу на высокоуровневом языке дало бы на выходе гораздо более гибкий и мощный инструмент. Всё упирается в выразительность языка общего назначения для написания внутренних DSL. На скале это можно сделать на ура (да собственно и сделано в sbt), но jvm – не наш метод; а на плюсах я хз как нынче DSL-и модно писать и на что они годятся. Впрочем, синтаксис правил всё равно будет более громоздким чем у makefile; да и влом. Так что не выёживаюсь и продолжаю жрать чё дают.

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

CMake

И в автотулзах.

Кстати, cmake же поддерживает модули Fortran 2018, так что должно взлететь.

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

Так-с. Ну в целом можно сказать попробовал.

  1. Вместо заморочек с доп. правилами .d0 –> .d, тупо редактирую .d inplace в том же правиле где вызываю gcc, следующей же командой после вызова gcc.

  2. При редактировании .d восстанавливаю его mtime: stat() отдаёт наносекунды, utimes() берёт микросекунды, я округляю вниз (ns - 999) / 1000, т.к. .o зависит от .d и если mtime(.d) > mtime(.o) то получается постоянная пересборка.

  3. .c++m упоминается в .d гораздо чаще чем я думал: в .d-файле самого модуля там накручено дохрена, в т.ч. правило «.c++m : .gcm» без wildcards (т.е. маппер таки-применён; и самому это правило химичить не нужно, .SECONDEXPANSION тоже не нужен). Я вычищаю вообще все упоминания «.c++m».

  4. Я делал makefile по руководству http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/, но для модулей оно сбоит: если после make clean исходник A, импортирующий модуль, начинает компиляться раньше/одновременно исходника B, экспортирующего модуль, то т.к. файла A.d ещё нет (по ссылке этот файл генерится не отдельным правилом, а одновременно с .o), то компиляция A падает т.к. модуль B не найден. Без модулей (т.е. с инклудами) это руководство работает т.к. инклуды изначально лежат в src, независимо от порядка сборки. Возможно, придётся возвращаться к классическому подходу: разные правила для .o и .d.

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

Гы. Работает. Надо же. Правило «%.d : %.cpp» отдельное, и чуть потрахался с опциями gcc: кто ж знал, что «-E -MMD …» работать будет, а «-MMD … -E» и «-MM» – нет; и это далеко не единственные перебранные варианты, я теперь блин эксперт по опциям.

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

Ещё б теперь со шлангом разобраться, как ему в QtCreator подсунуть module maps. Не подскажет ли кто?

  1. В доке его какая-то дичь – гигантская простыня, и глянув быстренько по диагонали – синтаксис module map file дико громоздкий и вроде бы там только про implicit modules (precompiled headers).

  2. На ютубе по запросу «cppcon clang c++20 modules» нарыл упомиание про некий clang-scan-deps, но в слайдах к нему нету примеров вызова (смотрю вот теперь всё видео целиком, но подозреваю там тоже не будет: это шланговый междусобойчик, они там на своей волне), и наобум он не вызывается: давай мне, говорит, опцию –compilation-database! Даю, говорит – нет такого файла! Чё с ним делать-то? В вышеуказанной доке он тоже не упоминается. А между прочим он ещё в 9-ю версию добавлен.

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

clang-scan-deps не нужен.

  1. На вход берёт https://clang.llvm.org/docs/JSONCompilationDatabase.html, на выходе make-правила – зависимости (вместо нужного мне module map), которые мне мне gcc и так уже генерит. Причём:

  2. Выплёвывает в stdout все зависимости всех файлов скопом – а не как в .d-файлах, где у каждого сорца свой файл с зависимостями.

  3. Нет опции «без системных инклудов», в отличие от gcc.

  4. При анализе сорца, содержащего import myModule, clang-scan-deps ругнулся «модуль myModule не найден». Разумеется он не найден, ты сука тупая, я тебя вызвал чтобы зависимости сгенерить перед компиляцией в т.ч. этих самых модулей. Так что степень корректности генерируемых правил для модулей уже не проверял.

UPD. Впрочем, возможно, что оно пытается найти исходник модуля, и эта ошибка – следствие отсутствия module map.

  1. Ну и брать на вход лог компиляции (чем и является, как выяснилось, compilation database) для того чтобы выяснить требуемый порядок компиляции – это что-то уже за гранью. Вкупе с предыдущм пунктом, у меня не то что матерных – вообще никаких слов нету, чтобы выразить своё отношение.
dimgel ★★★★★
() автор топика
Последнее исправление: dimgel (всего исправлений: 1)
Ответ на: комментарий от dimgel

Вкупе с предыдущм пунктом, у меня не то что матерных – вообще никаких слов нету, чтобы выразить своё отношение.

Мне Nathan Sidwell(автор тех бумаг :), https://github.com/urnathan) сегодня ответил по поводу clang и моей просьбе дать GNU Makefile с примером, чтобы самому явно не прописывать зависимости.

it's being actively worked on is all I can really say

https://imgur.com/a/tGy4k3n

Так что походу у них нет самих примера того, как ты хочешь. Лишь явно задавать зависимости модулей самому…

Discord чатик LLVM: https://discord.gg/XMEw2XEw

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

ответил по поводу clang

Чёт про clang ты к нему не по адресу: он над gcc работает.

с примером, чтобы самому явно не прописывать зависимости

target/build/linux/%.d: src/%.cpp
	@mkdir -p $(@D)
	@$(CCL) -E -MMD -MP -MF $@ -MT "$(@:.d=.o)" -o /dev/null $<
	@util/make-transform-d.cpp $@

И куришь получившийся .d файл. Без моих заморочек с мультиплатформенными целями даже и трансформация по большому счёту не нужна… хотя добавить сам d-файл в цели первого правила – не лишне.

Так что походу у них нет самих примера того, как ты хочешь. Лишь явно задавать зависимости модулей самому…

Ты пишешь про makefile, тут всё есть и всё работает, я ж выше отписался. А вот в qt-creator похоже ещё не завезли. В пятой версии появится экспериментальная полная замена ClangCodeModel на LanguageClient, там возможно будут подвижки.

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

чет я уже год жду модули и ниче нет.

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