LINUX.ORG.RU

Модули... модули? Какие модули?!

 ,


0

5

Привет, ЛОР!

Решил я тут взять C++ для одного своего маленького проекта. Давно ничего сложнее багфиксов в старый код не писал на этом языке по причине его особой не нужности, но тут подумал: «Почему бы и нет?» Естественно, хочу C++ со всеми последними вкусностями, в частности нормальными модулями.

Скажи, ЛОР, как эти модули вообще использовать? Если в рамках моего проекта всё примерно понятно, то использование модулей из сторонних библиотек вызывает много вопросов. Стандартная библиотека, как я понимаю, в модули до сих пор не обёрнута?

Компиляция вот этого примера падает с кучей странных ошибок:

import <iostream>;
import <string>;

std::string s = "Hello World";

int main(void)
{
  std::cout << s << std::endl;
}
$ g++ -std=c++2b -fmodules-ts mod.cc -o mod
In module imported at mod.cc:1:1:
/nix/store/z9jxhrbxm5lxrjpia9xcqjgk990ffr2j-gcc-11.1.0/include/c++/11.1.0/iostream: error: failed to read compiled module: No such file or directory
/nix/store/z9jxhrbxm5lxrjpia9xcqjgk990ffr2j-gcc-11.1.0/include/c++/11.1.0/iostream: note: compiled module file is ‘gcm.cache/./nix/store/z9jxhrbxm5lxrjpia9xcqjgk990ffr2j-gcc-11.1.0/include/c++/11.1.0/iostream.gcm’
/nix/store/z9jxhrbxm5lxrjpia9xcqjgk990ffr2j-gcc-11.1.0/include/c++/11.1.0/iostream: note: imports must be built before being imported
/nix/store/z9jxhrbxm5lxrjpia9xcqjgk990ffr2j-gcc-11.1.0/include/c++/11.1.0/iostream: fatal error: returning to the gate for a mechanical issue
compilation terminated.
$ 
$ clang++ -std=c++2b -fmodules-ts mod.cc -o mod
mod.cc:1:8: error: header file <iostream> (aka '/nix/store/dlni53myj53kx20pi4yhm7p68lw17b07-gcc-10.3.0/include/c++/10.3.0/iostream') cannot be imported because it is not known to be a header unit
import <iostream>;
       ^
mod.cc:2:8: error: header file <string> (aka '/nix/store/dlni53myj53kx20pi4yhm7p68lw17b07-gcc-10.3.0/include/c++/10.3.0/string') cannot be imported because it is not known to be a header unit
import <string>;
       ^
mod.cc:4:1: error: use of undeclared identifier 'std'
std::string s = "Hello World";
^
mod.cc:8:3: error: use of undeclared identifier 'std'
  std::cout << s << std::endl;
  ^
mod.cc:8:21: error: use of undeclared identifier 'std'
  std::cout << s << std::endl;
                    ^
5 errors generated.

GCC и Clang почти последние: 11.1 и 12.0.1. Выходит, модули не работают? Что делать, ЛОР? Отложить C++ до лучших времён?

★★★★★

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

В том же хацкелле можно компилировать функции в отдельные объектные файлы.

это вообще про «звон, не знаю где он».

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

а почему нет? только это вовсе не значит, что функция «раздельно компилируемая».

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

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

В смысле, референсным? Модули появились до модулы.

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

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

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

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

не может, а должен. если он не совсем примитивный.

вы определитесь, что для вас такое - «единица компиляции».

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

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

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

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

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

А «модули» - да от лукавого оно всё…

bugfixer ★★★★★
()

Так и что, ТС в итоге доделал свой хелло-ворлд на модулях?

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

самолично такой загрузчик писал.

Стесняюсь спросить - пригодился?

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

Кругозор чего? У тебя процессор напрямую выполняет инструкции твоего языка или что? Если нет, то у тебя есть этап сборки. Просто ты его прячешь за шебангом.

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

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

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

правда в этом случае оптимизации уже просто так не сделать. зато сама система получается простой.

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

Кругозор чего? У тебя процессор напрямую выполняет инструкции твоего языка или что? Если нет, то у тебя есть этап сборки. Просто ты его прячешь за шебангом.

але вы жертва какого питона?

код генерит компилятор, там остается только правильно расставить внешние адреса.

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

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

сборка это линкер, товарищ. а компиляция - компилятор…

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

Сборка – это build, т.е. компиляция + линковка. Линкер занимается линковкой или связкой.

Но я понял о чём ты теперь.

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

Но я понял о чём ты теперь.

просто я не си начинал. там «сборки» как таковой не было вообще. была компиляция отдельно. линковка отдельно… которая и называлась «сборкой».

но были там и загрузчики модулей, что обходились и без линковки вообще.

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

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

есть кстати прикольные архитектуры, где сборка и все эти адреса - ненужны в принципе.

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

команда выглядит так(псевдокод):

mov [10].100, 0

то есть - взять 10 ый адрес из таблицы(то есть стартовый адрес данных модуля с номером 10), сместиться на 100, и положить ноль. тогда при загрузке надо просто проставить туда адреса расположения данных модуля в памяти, и не надо ничего провязывать. то есть загрузчик вообще строк 200. по кодовым секциям модулей аналогично.

а компилятор соответственно такой код и генерит. ко внешним адресам - через таблицу, а внутри самого модуля адресация относительная.

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

есть кстати прикольные архитектуры, где сборка и все эти адреса - ненужны в принципе.

Есть.
Например PDP-11 /СМ-1, СМ-1М, СМ-2М, …/.
В ОСРВ загрузчик именно так и работал.
Разработал загрузчик и manager, которые обеспечивали многозадачность /штатный загрузчик этого не умел/.
Все было ok

В архитектуре команд поддерживалась кстати многоуровневая косвенная адресация и для для поддержки в 32KB разделе в котором находилась ОС 2KB отводилось.
Классная штука!

anonymous
()

Вот можешь почитать ещё, возможно на Linux заработает: https://itnext.io/c-20-modules-complete-guide-ae741ddbae3d

В msys2 команды для clang++ не сработали, хотя у меня clang 12.0.1 и libc++ установлены, так что для Windows это пока не работает 100%.

Update: проверил в Manjaro, да там собираются header units с помощью тех команд, которые указаны в статье…

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

Правнуки наших детей все это увидят …

Это не нападки на C++, а переживание за его развитие.
Вот смотрите:

 -  придумываем классы;  
 -  придумываем макросы;
 -  разработчик с использованием их пытается расширить язык и разрабатывает STL;
 -  придумываем template;  
 -  ...   
 -  ...

Всю эту функциональность нужно сделать непротиворечивой

 - добавляем сотни ограничений;  
 - ...

На кривом фундаменте дом хорошим будет?

Не скажу, что C++ доконали и это

ВЕЛИКОЛЕПНО

Для разработки алгоритмов как известно нужны выражения и управляющие операторы.
Для системного программирования нужнен удобный синтаксис для работы с памятью.
Конечно должна предоставляться возможность создания и использования типов данных.

Может быть что и упустил, но и этого достаточно для того, чтобы обеспечить возможность разработки 99% алгоритмов.

Остальное все

 - библиотеки;  
 - метаданные;

Но они не должны быть прибиты гвоздями к языку программирования.
Именно таким Си и создавался.
Ныне мало кто это понимает и ПРОСТО ЗАХЛОМЛЯЮТ как Си так C++ …

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

Sorry за грамматику

ЗАХЛАМЛЯЮТ, …, …

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

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

Смотря что ты считаешь интерфейсом. Если компилятор делает предкомпиляцию интерфейса, то там по факту будет размер класса и его публичные символы (виртуальные методы для простоты оставим в покое). И тут как раз и получим, что предкомпилированное представление не изменится.

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

Модули никаким образом не влияют на время компиляции, жертва пропаганды. Как максимум тем, что у тебя будет pch по дефолту.

Да? А ну возьми для каждого хедера сделай pch. Много из них ты одновременно сможешь заинклудить в один .cpp? Сидел бы лучше и молчал про pch.

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

Модуль - это хедер.

Facepalm.

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

Не работает, т.к. для хедера важен внешний контекст (места, где его заинклудили).

Pavval ★★★★★
()

Модули… модули

Заголовок песни звучит не плохо.

Хотелось бы, чтобы и слова ее были ХОРОШИМИ ...
anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.