Доброго.
Задача классическая и, насколько я знаю, до сих пор не решённая.
Есть фабрика, есть куча классов, разбросанных по статическим библиотекам. В финальной сборке могут присутствовать разные наборы статических библиотек. Хочется, чтобы классики умели автоматом себя регистрировать в фабрике, на манер динамической библиотеки: создал статический объект, в нём вызвал код регистрации — профит.
Насколько я знаю, проблема эта не решаема изза особенностей линковки статических библиотек. Однако этот тред подарил мне надежду, что всё может получиться: http://www.rsdn.ru/forum/cpp/3089286.1
Однако подобный подход в статической библиотеке к никакому положительному результату не привёл — всё по-прежнему.
Я что-то не так понял? Может, есть ещё какое-то решение? Пробовал на 10й студии.
Re: авторегистрация типов в статической библиотеке
самое интересное, что, ежели обратиться к какому-нибудь символу из статической библиотеки — авторегистраторы начинают работать со всеми типами из этой библиотеки, даже с теми, к которым не обращались
Re[2]: авторегистрация типов в статической библиотеке
Здравствуйте, cheqa, Вы писали:
C>самое интересное, что, ежели обратиться к какому-нибудь символу из статической библиотеки — авторегистраторы начинают работать со всеми типами из этой библиотеки, даже с теми, к которым не обращались
Я больше скажу, если к библиотеке не обращаться, ее кода в программе вообще не будет — линкер повыкидывает.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re: авторегистрация типов в статической библиотеке
Здравствуйте, cheqa, Вы писали:
C>В финальной сборке могут присутствовать разные наборы статических библиотек.
Ты как-то не написал, как конкретно ты хочешь определяь набор библиотек, используемых в сборке.
Что это? Список символов в .DEF файле? Опция линкера? Набор включаемых куда-то хедеров, в которых прописаны соответствующие #pragma comment? Что-то ещё?
Каждый из этих механизмов по умолчанию предполагает, что статическая библиотека линкуется только если на неё есть какие-то ссылки извне, но линковку библиотеки можно сделать и обязательной.
Например, если подключение библиотеки происходит через использование хедера, что часто удобно, так как программа должна где-то взять какие-то параметры для вызова фабрики, обычно это какие-то константы например строки с именами интерфейсов. Их удобно определить в отдельном хедере для каждого интерфейса, там же можно разместить и прагму коммент, и там же можно разместить код, которы породит ссылку на библиотеку.
Если через перечисление библиотек в параметрах линкера, то можно, например, в каждую из статических библиотек поместить символ, помеченный, как экспортируемый. Удобно им сделать как раз тот статический регистратор, кстати. Его даже можно нагрузить дополнительной полезной нагрузкой -- в имени символа отразить имя и версию класса, который используется. Тогда по собранной dll/exe-ке всегда можно будет узнать какие версии компонент она использует, просто посмотрев на список экспортируемых символов и т. д.
Короче расскажм подробнее, как у тея всё устроено, а то твоя "неразрешимая задача", как минмум для MSVC давно решена
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: авторегистрация типов в статической библиотеке
Здравствуйте, Erop, Вы писали:
E>Короче расскажм подробнее, как у тея всё устроено, а то твоя "неразрешимая задача", как минмум для MSVC давно решена
Хотите подробностей? Их есть у меня
Собственно, проект кроссплатформенный, система сборки — cmake. Набор линкумых библиотек на данный момент определяется параметрами .cmake файла. Далее на основе выставленных параметров определяются дефайны, на основе которых потом в коде есть длинный свитч, который делает нужные инклуды и регистрирует в фабрике нужные типы. Весь остальной код кроме этого свитча вообще ничего не знает о многообразии и типов — он создаёт сущности через фабрики с разной степенью успешности.
Схема дурная и неудобная. При добавлении нового статического плагина надо не забыть поменять в 3-4 местах. Если забыл — всё будет работать, до поры. Хотелось бы причесать, сделать красиво.
Как бы хотелось, чтобы оно жило:
— точно так же — в симейке список подключаемых либ
— они просто передаются линкеру
— в коде ничего менять не надо, классы сами регистрируются путём какого-то трюка
я очень надеялся, что приведённый мною тред даст решение — не получилось.
Спасибо.
Re[3]: авторегистрация типов в статической библиотеке
Здравствуйте, cheqa, Вы писали:
C>я очень надеялся, что приведённый мною тред даст решение — не получилось.
А у gcc нет разве спосоа пометить объект, как однозначно нужный при линковке, например, как экспортируемый? У MSVC есть и даже работает...
C>Спасибо.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: авторегистрация типов в статической библиотеке
Здравствуйте, Erop, Вы писали:
E>А у gcc нет разве спосоа пометить объект, как однозначно нужный при линковке, например, как экспортируемый? У MSVC есть и даже работает...
У гцц — не нашёл. А у msvs какой? Чтобы желаемая схема заработала
Re[5]: авторегистрация типов в статической библиотеке
Здравствуйте, cheqa, Вы писали:
C>У гцц — не нашёл. А у msvs какой? Чтобы желаемая схема заработала
Я же тебе написал. Например, сделай регистраторы экспортируемыми...
А вообще можно же это всё автоматизировать.
Завести какое-то пространство имён, типа LinkStaticRegistrarEnforcers, и в каждой либе заводить одноимённую с либой переменную в этом пространстве.
Переменную сделать такого типа, что бы она ссылалась на все нужные регистраторы, а в твоей cmake-магии написать машинку, которая по списку нужных либо генерит статическое данное в том же пространстве, которое ссылается на все имена по списку.
Так что тебе останется не забыть дёрнуть за это статическое данное и всё...
В результате надо будет не забыть зарегать статические регистраторы в объекте, одноимённом с библой, а дальше всё само будет работать.
Ну и проверять полноту можно.
Например, можно из main дёргать у того самого ссылающегося на всех объекта метод "пометить тех, кого посчитали", он передёргает загененные в себе коллекци регистраторов, а коллекции передёргают сами регистраторы.
А в деструкторе регистратора, если его не дёрнули, подавать какой-то сигнал, например писать файл куда-то с именем регистрируемого класса, а внутри файла текст с описанием проблемы...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: авторегистрация типов в статической библиотеке
Здравствуйте, Erop, Вы писали:
E>Так что тебе останется не забыть дёрнуть за это статическое данное и всё...
Собственно, этого и хотелось избежать. Т.е. мне всё равно придётся проверять по дефайнам, что что-то в сборку входит, и дёргать оттуда символ. Принципиально ничем не отличается от варианта со свитчём.
Поэтому я и говорил — проблема до сих пор не решена
Re[7]: авторегистрация типов в статической библиотеке
Здравствуйте, cheqa, Вы писали:
C>Собственно, этого и хотелось избежать. Т.е. мне всё равно придётся проверять по дефайнам, что что-то в сборку входит, и дёргать оттуда символ. Принципиально ничем не отличается от варианта со свитчём.
Не прийдётся.
Ты просто явно генеришь один исходник по списку играющих в эту игру билиотек прямо в своём билдовом скрипте. И всё. Типа списко вида lib1, lib2, lib3 у тебя уже должен же быть?
Исходник генеришь вида:
LinkStaticRegistrarEnforcers::CheckAll дёргаешь всегда, даже если он пустой. Фабрику же ты всё равно линкуешь? Вот делаешь у этой фабрики статический метод init( bool checkUnusedRegistrars = false ), а из него уже дёргаешь, если передали true...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[8]: авторегистрация типов в статической библиотеке
Здравствуйте, Erop, Вы писали:
E>LinkStaticRegistrarEnforcers::CheckAll дёргаешь всегда, даже если он пустой. Фабрику же ты всё равно линкуешь? Вот делаешь у этой фабрики статический метод init( bool checkUnusedRegistrars = false ), а из него уже дёргаешь, если передали true...
Ну, получается, за меня свитч генерит компилятор. Удобно, да — но принципиально не отличается.
Когда-то давно использовалась динамическая сборка. Там была очень удобная фишка: все плагины грузились по строковомоу идентификатору в конфиге, в момент dlopen вызывались конструкторы статических объектов — которые то и регистрировали типы в фабрике
Все испытывают ностальгию по тем прекрасным временам...
Re[9]: авторегистрация типов в статической библиотеке
Здравствуйте, cheqa, Вы писали:
C>Когда-то давно использовалась динамическая сборка. Там была очень удобная фишка: все плагины грузились по строковомоу идентификатору в конфиге, в момент dlopen вызывались конструкторы статических объектов — которые то и регистрировали типы в фабрике C>Все испытывают ностальгию по тем прекрасным временам...
Я тебе предлагаю воспроизвести ровно ту же схему, в CT+LT...
По текстовым ID сервисом получаем список линкуемых либов + строим код, вызывающий их инициализацию. Всё будет работать само собой...
но гна самом деле, попробуй почитать таки спеки на линкер от gcc, неужели никак нельзя пометить символ из либы, как нужный в конечном модуле? Скажем как они экспортируемые символы поддерживают, например?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: авторегистрация типов в статической библиотеке
Как вариант — распилить статическую библиотеку на object file'ы, и использовать их (насколько я помню, в либе нет никакой доп инфы, просто коллекция объектных файлов).
На Windows — lib.exe, на Linux — какой-нибудь ar.
Можно не распиливать, а сразу производить object file'ы, либо вытаскивать их из build папки cmake.
Вариации:
1) Использовать Unity Build, тогда всё будет в одном obj.
2) Не распиливать либу, поставлять как есть + один маленький obj который должен быть тоже слинкован.
Работает и на Windows, и на Linux. Преимущество по сравнению с автогенерацией в том, что не надо ничего перекомпилировать при изменении конфигурации — всё разруливается линкером.
Re[10]: авторегистрация типов в статической библиотеке
Здравствуйте, Erop, Вы писали:
E>Я тебе предлагаю воспроизвести ровно ту же схему, в CT+LT... E>По текстовым ID сервисом получаем список линкуемых либов + строим код, вызывающий их инициализацию. Всё будет работать само собой...
Нет, есть разница, и весьма существенная. Список статических плагинов нельзя изменить на продакшне, в конфиге. Хотя при нашем подходе — это совершенно не важно, да. Абсолютно.
Спасибо за идею, я подумаю над ней.