279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
1

Своя библиотека и сборка программ

19.06.2020, 16:28. Показов 3309. Ответов 21
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Приветствую всех. Есть такая система, как IMB i (раннее название AS/400). Она консольная. Я пишу программы для этой системы на С++. Может кто-то скажет, что правильнее для этой системы писать программы на ее "родном" языке программирования - RPG, но я не хочу разводить здесь об этом полемику.

Итак, для создания на С++ программ в системе есть компилятор и стандартная библиотека. Весь этот набор "чуть-чуть" не дотягивает до стандарта С++11 (то есть, что-то из С++11 присутствует, чего-то еще не реализовали).

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

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

Не существует ли способа, который позволяет это автоматизировать? У меня есть варианты, но о них после ваших предложений
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
19.06.2020, 16:28
Ответы с готовыми решениями:

Своя графическая библиотека
Здравствуйте, мне хочется создать свою графическую библиотеку. Проблема в том то что мне нужно...

Своя библиотека Java
У меня, немного странный наверно, вопрос. Как закрыть доступ ко всем классам кроме одного в...

Своя сборка Delphi 7
Привет! При работе с Delphi 7 пользуюсь определенным набором дополнительных компонентов. При...

Библиотека программ
Подскажите, пожалуйста как можно решить проблему: создала библиотеку программ, на форме создала...

21
1486 / 1413 / 240
Регистрация: 19.02.2010
Сообщений: 3,914
19.06.2020, 19:21 2
Цитата Сообщение от d7d1cd Посмотреть сообщение
Но если я сделаю свою библиотеку, то, естественно, один ее класс может начать использовать второй, а тот третий и т. д. При этом, если использовать в программе первый класс, то надо отслеживать, какие классы библиотеки он использует и вручную создавать модули этих классов.
Рядом с С/С++-транслятором и линкером должен валяться и "библиотекарь". Что-то с "lib" в названии (перед расширением екзешника).
Т.е. откомпилированные двоичные коды (объектники), соответствующие модулям с разными классами, можно соединить в одну библиотеку.

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

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

Если в системе есть исходники С/С++-библиотек - то там сделано аналогично:
1) Исходники и заголовочники разных модулей живут по-отдельности друг от друга - но сведены в малое число библиотек (одна для С, одна для всего стандартного в С++ - или как-то похоже).
2) К модулям Вашего проекта подключаются заголовочники отдельных модулей стандартных библиотек - но затем линкер собирает исполняемый файл на основе библиотеки как целого.

Ну а чтобы один модуль заголовочника тащил за собой всё, что нужно для объявлений в этом заголовочнике - надо просто прописывать межмодульные связи именно через заголовочники.
Т.е. если класс Б является потомком класса А - то заголовочник для А должен подключаться не в модуле для Б перед инклюдом заголовочника для Б, а в заголовочнике для Б перед тамошними объявлениями.
Для ликвидации возможности повторных включений - в языке есть #ifndef-#define-#endif.
1
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
20.06.2020, 11:22  [ТС] 3
Цитата Сообщение от VTsaregorodtsev Посмотреть сообщение
Далее линкером (или в написанном make-файле) к рабочему проекту цеплять именно эту библиотеку (всю её целиком, а не отдельными её составляющими модулями).
То есть, Вы предлагаете выполнить компиляцию всей библиотеки в один модуль, а затем в каждую программу линкером включать этот модуль, даже если программа использует из библиотеки одну маленькую независимую ни от чего функцию?
0
1486 / 1413 / 240
Регистрация: 19.02.2010
Сообщений: 3,914
20.06.2020, 14:48 4
Да, именно так.
Ибо это стандартный способ для компилируемых языков.
Бояться последующего роста размера екзешника - не надо. Ибо линкер давно уже настолько умный, что тянет из библиотеки (да и из объектников проекта) только реально используемое (т.е. тянет зависимости даже не помодульно - а может брать только отдельные функции/классы из модулей, включающих >1 функции или класса).
Если не верите в утверждение из предыдущего предложения - статически соберите любой hello world и сравните размер получившегося екзешника с размером библиотеки С/С++, которая линковалась к этому проекту.

Т.е. когда я в предыдущем посте писал слова "к рабочему проекту цеплять именно эту библиотеку (всю её целиком, а не отдельными её составляющими модулями)" - то имел в виду указание только одного имени в командной строке линкера, вместо указания кучи имён библиотечных модулей. Ибо проблема-то у Вас в первую очередь - с отслеживанием зависимостей, какие модули библиотеки нужны некоторому проекту и/или просто друг другу. Вот и надо всю библиотеку собрать упихать в единый библиотечный модуль - и затем им пользоваться.
А линкер из такой общей библиотеки просто не будет брать ничего лишнего (ненужного некоторому данному конкретному проекту).

В общем, способ сборки библиотеки аналогичен тому, каким Вы собираете любую свою прогу - просто лишь меняется "формат" итоговой "программы" на втором шаге (несколько ранее (на первом шаге) откомпилированных по-отдельности друг от друга модулей здесь собираются не линкером в единый екзешник - а библиотекарем в единый бинарный файл библиотеки).
А затем полученная библиотека используется аналогично любой стандартной (Вы же не выбираете вручную модулей из стандартной библиотеки) при сборке уже реальной программы.
1
18829 / 9832 / 2403
Регистрация: 30.01.2014
Сообщений: 17,267
20.06.2020, 15:34 5
Цитата Сообщение от VTsaregorodtsev Посмотреть сообщение
Рядом с С/С++-транслятором и линкером должен валяться и "библиотекарь". Что-то с "lib" в названии (перед расширением екзешника).
В unix - это обычно программа ar.
0
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
22.06.2020, 16:49  [ТС] 6
Цитата Сообщение от VTsaregorodtsev Посмотреть сообщение
статически соберите любой hello world и сравните размер получившегося екзешника с размером библиотеки С/С++, которая линковалась к этому проекту.
Вот тут есть "фокус". Стандартные библиотеки С/С++ не попадают внутрь создаваемых программ ни полностью, ни частично. Использование функций и/или классов этих библиотек осуществляется через так называемые сервисные программы. Сервисная программа - это аналог dll в Windows. То есть, все функции и классы стандартных библиотек С/С++ скомпилированы в некоторое количество сервисных программ. При создании программы сборщик "понимает", что данная функция/класс реализованы в стандартной библиотеке и автоматически подключает к создаваемой программе нужную сервисную.

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

Цитата Сообщение от VTsaregorodtsev Посмотреть сообщение
Ибо линкер давно уже настолько умный, что тянет из библиотеки (да и из объектников проекта) только реально используемое (т.е. тянет зависимости даже не помодульно - а может брать только отдельные функции/классы из модулей, включающих >1 функции или класса).
Хочется надеяться, что в сборщике в моей системе эта возможность есть. Но пока я ее не смог найти. Был проведен эксперимент. Я создал модуль с двумя функциями. Затем в главном модуле я вызвал только одну из этих функций. В итоговой программе средствами ОС было определено, что вторая функция сборщиком не была исключена. Она так и осталась в программе, хотя нигде не используется.
Но хочется сказать, что Вы направили меня на путь поиска. Попробую поискать в направлении настроек сборщика, так как вытягивание в готовую программу только реально используемого кода было бы, наверное, идеальным решением. Если вдруг кому-то интересно, то вот ссылка на команду сборки программы, которую я использую.
0
18829 / 9832 / 2403
Регистрация: 30.01.2014
Сообщений: 17,267
22.06.2020, 20:44 7
Цитата Сообщение от d7d1cd Посмотреть сообщение
И если я вдруг в ней поменяю имя какой-то функции, то поставленные до этого программы могут прежнее имя функции не найти и упасть... на проде...
Охо-хо! Для этого есть тесты!

Вы не пишете тесты на свой код?!

Добавлено через 2 минуты
Вообще возьмите за правило никогда не трогать API, которое уже пошло в работу. А чтобы это правило строго соблюдалось - пишите тесты, которые будут автоматически прогоняться после каждой компиляции вашей "сервисной программы".
Даже если API у вас получилось плохенькое и неудобное, вы его засунули в прод, а потом только это осознали - не трогайте. Напишите новое API, старое объявите deprecated и потихоньку переводите новые версии софта на него.
НИКОГДА не ломайте API.
1
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
23.06.2020, 08:08  [ТС] 8
DrOffset, спасибо за совет! Тесты для библиотеки я пишу. Разрешите два вопроса:
1. Тесты должны писаться только для интерфейсных функций и методов или для внутренних тоже (я пока пишу только для интерфейсных)?
2. Какие существую способы объявить функцию или метод deprecated? Только на уровне документации или особой конструкцией кода, приводящей к ошибкам/предупреждениям при компиляции?

Что же, зафиксирую первый вариант реализации библиотеки - реализация в виде сервисной программы.
0
18829 / 9832 / 2403
Регистрация: 30.01.2014
Сообщений: 17,267
23.06.2020, 11:39 9
Цитата Сообщение от d7d1cd Посмотреть сообщение
Тесты должны писаться только для интерфейсных функций и методов или для внутренних тоже (я пока пишу только для интерфейсных)?
В идеале - для всего.
Но чтобы контролировать неизменность API, достаточно только "интерфейсных", если я конечно вас правильно понял.

Цитата Сообщение от d7d1cd Посмотреть сообщение
Какие существую способы объявить функцию или метод deprecated?
В С++14 - штатные: https://en.cppreference.com/w/... deprecated
До С++14 можно использовать специфичные для компилятора прагмы или атрибуты. Например https://gcc.gnu.org/onlinedocs... butes.html
1
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
24.06.2020, 19:02  [ТС] 10
Цитата Сообщение от DrOffset Посмотреть сообщение
В идеале - для всего.
Тогда еще вопрос по этой теме. Как написать тест для private функции класса? Ведь она не видна при создании объекта класса и я не могу ее вызвать.
0
18829 / 9832 / 2403
Регистрация: 30.01.2014
Сообщений: 17,267
24.06.2020, 19:07 11
d7d1cd, Есть два подхода -
1) private вообще не тестировать
2) тестировать с помощью friend-кейсов. testcase для этого класса делается ему friend-ом и все. чтобы это не маячило в финальной версии кода, это можно делать под специальным макросом.

Поищите библиотеки для юнит-тестирования, некоторые предоставляют готовые решения этого вопроса.
1
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
14.08.2020, 08:52  [ТС] 12
Всем привет. Наконец-то нашел время продолжить обсуждение.

Выше было озвучено 2 варианта реализации библиотеки (буду называть ее OLI - Object Library for IBM i):
1. Реализация в виде одного модуля, который будет включаться в каждую программу.
2. Реализация в виде общей сервисной программы, функции которой будут использоваться программами по мере необходимости.

При добавлении функционала в OLI первый вариант более удобен в плане поставки в прод: не требуется обновление сервисной программы, как в случае второго варианта. Однако в случае варианта 1 появляется "функциональная избыточность" - в программе может использоваться один класс из OLI, но в модуле будет вся библиотека (я пока не смог найти опций компилятора и(или) сборщика, позволяющих не включать в программу неиспользуемые функции: может быть их вообще не существует...).


В первом посте я говорил, что у меня есть свои варианты реализации. На самом деле вариант один. Он заключается в создании программы анализатора-сборщика (буду называть его imake). На вход imake будет подаваться путь к проекту создаваемого приложения. В проекте будет сценарий сборки этого приложения.
На первом этапе imake будет анализировать исходные коды проекта и, в случае нахождения там заголовка из OLI, поместит реализацию этого заголовка в отдельный CPP файл. Так же будет рекурсивно проведен анализ самого заголовка и его реализации на случай, если они используют другие части OLI.
В итоге процесса анализа вышеуказанный CPP файл наполнится используемым в проекте кодом из OLI. Далее этот файл и исходники проекта imake соберет в модули, а модули - в программу. В результате программа проекта будет содержать только то из OLI, что использует. Конечно, в используемом классе может не использоваться какая-то его часть, но эту оптимизацию я делать не планирую (по крайней мере пока).

Прошу вас прокомментировать мой вариант, сделать замечания, дать советы. Заранее признателен!
0
18829 / 9832 / 2403
Регистрация: 30.01.2014
Сообщений: 17,267
14.08.2020, 09:05 13
Цитата Сообщение от d7d1cd Посмотреть сообщение
Однако в случае варианта 1 появляется "функциональная избыточность"
Она как раз есть во втором варианте и никуда не денется. А в первом (если это статическая библиотека) при правильной декомпозиции на модули (объектные файлы), должна быть возможность (у линкера) не включать неиспользуемые модули с неиспользуемыми функциями.

Добавлено через 8 минут
Цитата Сообщение от d7d1cd Посмотреть сообщение
ведь удалять старые версии будет нельзя.
Не понятно почему это так.
Обычно при обновлении софта, если он требует новую версию своих зависимостей (dll\сервисных программ), а старую версию никто не использует, то ее можно удалить - что и делают все вменяемые пакетные менеджеры, например.

Цитата Сообщение от d7d1cd Посмотреть сообщение
Прошу вас прокомментировать мой вариант, сделать замечания, дать советы. Заранее признателен!
Я могу ошибаться, но мне кажется вы недостаточно провели экспертизы стандартных решений и практик, чтобы приступать к разработке своего варианта.
Прикручивание своего собственного препроцессора к сборке, который хитро компонует код, это завышение порога входа в сопровождение вашей программы. Если бы мой подчиненный мне предложил такое, я бы не дал добро до тех пор, пока не удостоверился, что это решение точно оправдано чем-то существенным.
0
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
17.08.2020, 08:30  [ТС] 14
Цитата Сообщение от DrOffset Посмотреть сообщение
Она как раз есть во втором варианте и никуда не денется.
Да, во втором варианте сервисная программа будет содержать в себе все возможности библиотеки. Но так и надо. Ведь сервисная программа - это та же библиотека, только в скомпилированном виде. Она будет одна на всю систему. В Windows же библиотека kernel32.dll одна и содержит в себе много функций, которые каждая конкретная программа не обязана использовать все. Программа использует только нужные ей функции. Так же и у меня во втором варианте.

Цитата Сообщение от DrOffset Посмотреть сообщение
должна быть возможность (у линкера) не включать неиспользуемые модули с неиспользуемыми функциями
К сожалению я не нашел в опциях своего линкера такой возможности. Вероятно, ее просто нет. Линкер принимает на вход список модулей и пакует их все в одну программу. Функции модуля могут вообще не использоваться внутри программы, но он все равно будет включен в ее тело.

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

Цитата Сообщение от DrOffset Посмотреть сообщение
Прикручивание своего собственного препроцессора к сборке, который хитро компонует код, это завышение порога входа в сопровождение вашей программы.
Вы бы видели программы в нашей системе . Одну и ту же по сути вещь все программисты делают по-своему. Час разбираешься с кодом, чтобы в конце понять, что он делает ровно то же, что и код, с которым ты тоже час разбирался в другой программе 2 дня назад... Библиотека, надеюсь, хоть как-то уменьшит количество велосипедов.

Кроме этого, использование моего препроцессора не является обязательным. Можно использовать сборку по старинке - через скрипты сборок. Просто в этом случае в программе будет вся библиотека, что скажется на ее размере и только. Ну и, по сути, это ручная (читай долгая и далеко не безошибочная) сборка.
0
18829 / 9832 / 2403
Регистрация: 30.01.2014
Сообщений: 17,267
19.08.2020, 13:50 15
Цитата Сообщение от d7d1cd Посмотреть сообщение
К сожалению я не нашел в опциях своего линкера такой возможности
Она есть по умолчанию. Если вы правильным образом подготовите объектные файлы внутри библиотеки, то она заработает.
0
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
19.08.2020, 14:25  [ТС] 16
Цитата Сообщение от DrOffset Посмотреть сообщение
Если вы правильным образом подготовите объектные файлы внутри библиотеки
Подскажите, что значит "правильным образом"?

Я пробовал делать следующим образом. Создал 3 исходника: первый содержал функцию main, второй содержал функцию печати строки на экран print, третий - функцию сложения чисел sum. В исходнике с main так же был добавлен прототип print (хедер не делал, так ка это был просто тест) и вызов этой функции. Обращаю внимание, что функцию sum я не вызывал. Далее компилятором из указанных исходников было создано 3 объектных файла (в терминах AS/400 - это модули). Затем модули были собраны в программу (при сборке было указано все 3 модуля).
В AS/400 есть команда, которая показывает из каких модулей состоит программа. Так вот моя программа содержала в себе все 3 модуля. Неиспользуемый модуль с функцией sum был так же включен в тело программы...
0
18829 / 9832 / 2403
Регистрация: 30.01.2014
Сообщений: 17,267
19.08.2020, 14:32 17
Цитата Сообщение от d7d1cd Посмотреть сообщение
Затем модули были собраны в программу
Эта программа - это библиотека? Или исполняемый файл?
0
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
19.08.2020, 15:16  [ТС] 18
Цитата Сообщение от DrOffset Посмотреть сообщение
Эта программа - это библиотека? Или исполняемый файл?
Исполняемый файл.

Просто для справки: программа - это исполняемый файл, сервисная программа - это аналог динамической библиотеки в Windows (не знаю почему ее в AS/400 тоже называют программой).
0
18829 / 9832 / 2403
Регистрация: 30.01.2014
Сообщений: 17,267
19.08.2020, 16:06 19
Цитата Сообщение от d7d1cd Посмотреть сообщение
Исполняемый файл.
Тогда возможно вы действительно правы и ваш линкер не может этого.
Для уверенности я бы конечно не отказался посмотреть своими глазами на него, но похоже это не особо возможно сделать быстро.

Цитата Сообщение от d7d1cd Посмотреть сообщение
не знаю почему ее в AS/400 тоже называют программой
Формально это верно потому что. И библиотека и запускаемый файл - это все программы. Но в повседневной жизни лучше это разделять, с этим можно согласиться.
1
279 / 156 / 52
Регистрация: 30.06.2011
Сообщений: 1,712
19.08.2020, 16:23  [ТС] 20
Цитата Сообщение от DrOffset Посмотреть сообщение
Для уверенности я бы конечно не отказался посмотреть своими глазами на него, но похоже это не особо возможно сделать быстро.
Есть публичный сервер AS/400 - pub400.com. Для получения доступа надо зарегистрироваться.
Для работы в режиме командной строки с ним нужен какой-нибудь терминал 5250.

Ну а так же есть справка по командам компиляции и сборки. Справка по команде компиляции C++ кода (запуск компилятора) здесь, справка по команде сборки (запуск линкера) тут.

Буду очень признателен, если хотя бы посмотрите справку. Может я не выставил нужных опций просто...
0
19.08.2020, 16:23
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
19.08.2020, 16:23
Помогаю со студенческими работами здесь

Не подключается DLL библиотека (не распознается сборка)
Необходимо подключить длл в проект, но при подключении появляется ошибка: "Please make sure that...

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

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

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

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

Инструменты разработчика Access. Библиотека программ, надстроек и справочного материала
Сайты появляются и исчезают. Такова жизнь. Но вместе с ними исчезают материалы и программы, которые...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru