LINUX.ORG.RU

Разработка архитектуры библиотеки - поддержка модульности?

 ,


0

5

Есть некая библиотека на C++ и питоне. Плюсовая часть состоит из хидеров и нескольких .cpp. В хидерах в основном разнообразные шаблоны, но встречаются и обычные классы/функции определенные в .cpp.

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

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

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

Например, в библиотеке есть модуль A.hpp+A.cpp (с обычными классами и функциями) и модуль T.hpp с шаблонами, частично использующий A.?pp. На некоторых машинах A.?pp может быть не работоспособен, и соответствующую часть T.hpp надо отключать.

Вопросов два:

1) Как это сделать удобно с т.з. юзера?

Мне че то в голову пришло три решения:

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

1.2) Каждый хидер библиотеки смотрит что уже было проинклюдено, т.е. A.hpp был проинклюден до T.hpp, то в T часть связанная с A работает, иначе - не работает. Минусы понятны, надо следить за последовательностью инклюдов, что в сложном проекте бдет затруднительно.

1.3) При помощи банальных дефайнов (в т.ч. задаваемых через аргументы командной строки). Из минусов - для рядового юзера слишком сложно.

А как это делают нормальные люди?;-)

2) Как такую модульность организовать с т.з. сборки библиотеки и последующей линковки модулей? Ну скажекм с линковкой у меня все в итоге собиралось в lib-файл. Но как указать что надо собирать, а что не надо?

Cast tailgunner, true_admin, shty.

★★★★★

Насколько я понял, тебе нужны системы сборки (autoconf, CMake и т.д.).

1.3) При помощи банальных дефайнов

This. По умолчанию (если запускать без аргументов) система сборки ищет, какие зависимости уже установлены на машине юзера, и складирует результаты поиска в файл вроде config.h. Результаты поиска представляют собой дефайны вида #define HAVE_FEATURE_XXX 1. Далее T.hpp обмазывается директивами #if HAVE_FEATURE_XXX, которые вкомпиливают в проект соответствующую функциональность.

Также юзер может вручную включать/выключать определенные зависимости, передавая системе сборки аргументы типа --with-feature-xxx=yes (для configure) или -DENABLE_FEATURE_XXX=ON (для CMake).

Но как указать что надо собирать, а что не надо?

Через ту же самую систему сборки выпилить из списка сорцов ненужные cpp файлы.

archie ()

Задача абстрактная, ответ тоже будет абстрактным. Пользователю удобно, если (варианты в порядке уменьшения удобства): 1) ему не надо делать ничего, кроме стандартной установки пакета; 2) у него есть GUI, в котором можно ткнуть нужные галочки всё соберется или выдаст внятные сообщения об ошибках; 3) ему дается некая стандартная система сборки (autohell или CMake).

А как это делают нормальные люди?;-)

Образцово нормальные люди не заставляют пользователей собирать программы.

tailgunner ★★★★★ ()
Последнее исправление: tailgunner (всего исправлений: 1)

На некоторых машинах A.?pp может быть не работоспособен

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

А как это делают нормальные люди?;-)

Если я правильно понял, примерно это и делает ./configure.sh.

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

Как это определяется? 

Руками при установке библиотеки.

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

Make плохо подходит для конфигурации исходников. Впрочем, можно добавить ворох скриптов и получить систему конфигурации ядра, buildroot-а или crosstool-ng.

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

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

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

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

Так что речь идет не о конфигурации исходников (плюсовых), а о правильной раздаче/передаче дефайнов

Но конфигурация плюсовых исходников - это запись в файл config.h (и/или config.mk) непротиворечивого набора #define-ов.

МОжно конечно это через переменные окружения сделать наверное или еще как то...

Генерировать config.h скриптом на основании параметров, переданных скрипту. Этот скрипт можно даже назвать configure и дать ему опции -with-* и --enable-*, но написать руками.

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

Это типа стандартный, классический подход?

В общем, да. Правда, самописанный скрипт генерации config.{h,mk} - это уж очень классично, но до появления autoconf все так делали.

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