Сегодня я хотел бы задать вам вопрос о возможностях C ++ для реализации конкретной архитектуры программного обеспечения.
Конечно, я использовал поиск, но не нашел прямого ответа.
По сути, моя цель - создать программу, которая позволяет пользователю моделировать и моделировать произвольно составленные физические системы, например, вождение автомобиля. Я предполагаю иметь библиотеку физических моделей (функций внутри классов). Каждая функция может иметь несколько входных данных и возвращать некоторые выходные данные в зависимости от базового физического описания, например, модель двигателя внутреннего сгорания, модель аэродинамического сопротивления, модель колеса и т. Д.
Теперь идея состоит в том, чтобы предоставить пользователю структуру, которая позволяет ему составлять любые функции в соответствии с его потребностями, то есть отображать любое физическое поведение. Структура должна обеспечивать функциональные возможности для соединения выходов и входов различных функций. Следовательно, платформа предоставляет контейнерный класс. Я называю это COMPONENT, который может содержать один или несколько объектов модели (FUNCTION). Эти контейнеры также могут содержать другие компоненты (см. Составной шаблон), а также соединения (CONNECTOR) между параметрами функции. Кроме того, класс компонента предоставляет некоторые общие числовые функции, такие как математическое решение и так далее.
Состав функций должен быть сделан во время выполнения. В первом случае пользователь должен иметь возможность настроить композицию путем импорта XML, который определяет структуру композиции. Позже можно подумать о добавлении GUI.
Чтобы дать вам лучшее понимание, вот очень упрощенный пример:
<COMPONENT name="Main">
<COMPONENT name="A">
<FUNCTION name="A1" path="lib/functionA1" />
</COMPONENT>
<COMPONENT name="B">
<FUNCTION name="B1" path="lib/functionB1" />
<FUNCTION name="B2" path="lib/functionB2" />
</COMPONENT>
<CONNECTIONS>
<CONNECTOR source="A1" target="B1" />
<CONNECTOR source="B1" target="B2" />
</CONNECTIONS>
</COMPONENT>
Нет необходимости углубляться в возможности фреймворка, потому что моя проблема гораздо более общая. Когда код / программа платформы компилируется, описание физической проблемы, а также пользовательские функции не известны. Когда пользователь выбирает (через XML или позже через GUI) функцию, платформа должна прочитать информацию о функции, т.е. должна получить информацию о входных и выходных параметрах, чтобы предложить пользователю возможность соединять функции.
Я знаю принципы рефлексии и знаю, что C ++ не предоставляет эту функцию. Тем не менее, я уверен, что понятие «создание объектов во время выполнения» очень часто требуется. Как мне настроить мою программную архитектуру на C ++ для достижения моей цели? Является ли C ++ правильным языком? Что я пропускаю?
Заранее спасибо!
Ура, Оливер
источник
Ответы:
В чистом стандарте C ++ нельзя «разрешить импорт функций во время выполнения»; в соответствии со стандартом, набор функций C ++ статически известен во время сборки (на практике, во время компоновки), так как исправлен из объединения всех блоков перевода, составляющих вашу программу.
На практике большую часть времени (за исключением встроенных систем) ваша программа на C ++ работает над какой-либо операционной системой . Прочитайте Операционные системы: Три Легких Части для хорошего обзора.
Некоторые современные операционные системы позволяют динамическую загрузку из плагинов . POSIX особенно указывает
dlopen
&dlsym
. В Windows есть что-то другоеLoadLibrary
(и более низкая модель компоновки; вам нужно явно аннотировать соответствующие функции, предоставляемые или используемые плагинами). Кстати, на Linux вы можете практическиdlopen
много плагинов (см. Моюmanydl.c
программу , с достаточным терпением она может сгенерировать, а затем загрузить почти миллион плагинов). Таким образом, ваша вещь XML может стимулировать загрузку плагинов. Ваше описание многокомпонентного / многоконтактного соединения напоминает мне о сигналах и слотах Qt (для этого требуетсяmoc
препроцессор ; вам может понадобиться что-то подобное).В большинстве реализаций C ++ используется искажение имен . Из-за этого вам лучше объявить как
extern "C"
функции, связанные с плагинами (и определенные в них и доступныеdlsym
из основной программы). Прочитайте мини- руководство по C ++ dlopen (по крайней мере для Linux).BTW, Qt и POCO - это фреймворки C ++, обеспечивающие переносимый и высокоуровневый подход к плагинам. А libffi позволяет вам вызывать функции, подпись которых известна только во время выполнения.
Другая возможность - встроить некоторый интерпретатор, такой как Lua или Guile , в вашу программу (или написать свой собственный, как это сделал Emacs). Это сильное архитектурно-дизайнерское решение. Вы можете прочитать Lisp In Small Pieces и Прагматику языка программирования для получения дополнительной информации.
Есть варианты или смеси этих подходов. Вы можете использовать некоторую библиотеку компиляции JIT (например, libgccjit или
asmjit
). Вы можете сгенерировать во время выполнения некоторый код C и C ++ во временном файле, скомпилировать его как временный плагин и динамически загрузить этот плагин (я использовал такой подход в GCC MELT ).Во всех этих подходах управление памятью является серьезной проблемой (это свойство «всей программы», и то, что на самом деле является «оболочкой» вашей программы, «меняется»). Вам понадобится хоть какая-то культура в отношении сбора мусора . Прочитайте руководство GC для терминологии. Во многих случаях (произвольные циклические ссылки, где слабые указатели не предсказуемы), схемы подсчета ссылок , близкой к интеллектуальным указателям C ++, может быть недостаточно. Смотрите также это .
Читайте также о динамическом обновлении программного обеспечения .
Обратите внимание, что некоторые языки программирования, в частности Common Lisp (и Smalltalk ), более дружественны к идее импорта функций во время выполнения. SBCL - это свободная программная реализация Common Lisp, которая компилируется в машинный код при каждом взаимодействии REPL (и даже способна собирать машинный код для сбора мусора и может сохранить весь файл образа ядра, который впоследствии можно будет легко перезапустить).
источник
Очевидно, что вы пытаетесь создать свой собственный стиль программного обеспечения типа Simulink или LabVIEW, но с нечестивым компонентом XML.
По сути, вы ищете графически-ориентированную структуру данных. Ваши физические модели состоят из узлов (вы называете их компонентами) и ребер (соединителей в именах).
Для этого не существует никакого механизма с применением языка, даже с отражением, поэтому вместо этого вам нужно будет создать API, и любой компонент, который хочет играть, должен будет реализовать несколько функций и соблюдать правила, установленные вашим API.
Каждый компонент должен будет реализовать набор функций для выполнения таких вещей, как:
И это только для настройки вашего графика. Вам понадобятся дополнительные функции, определенные для организации фактического исполнения вашей модели. Каждая функция будет иметь определенное имя, и все компоненты должны иметь эти функции. Все, что специфично для компонента, должно быть доступно через этот API, идентичным образом от компонента к компоненту.
Ваша программа не должна пытаться вызвать эти «пользовательские функции». Вместо этого он должен вызывать универсальную «вычислительную» функцию или что-то подобное в каждом компоненте, а сам компонент заботится о вызове этой функции и преобразовании ее входных данных в свои выходные. Входные и выходные соединения являются абстракциями для этой функции, это единственное, что должна видеть программа.
Короче говоря, мало что из этого на самом деле относится к C ++, но вам придется реализовать некоторую информацию о типах времени выполнения, адаптированную к вашей конкретной проблемной области. С каждой функцией, определенной API, вы будете знать, какие имена функций вызывать во время выполнения, и будете знать типы данных каждого из этих вызовов, и вы просто используете обычную загрузку старой динамической библиотеки, чтобы выполнить это. Это придет с достаточным количеством шаблонного, но это только часть жизни.
Единственный аспект C ++, который вы должны иметь в виду, это то, что лучше всего, чтобы ваш API был C API, чтобы вы могли использовать разные компиляторы для разных модулей, если пользователи предоставляют свои собственные модули.
DirectShow - это API, который делает все, что я описал, и может быть хорошим примером для просмотра.
источник
Вы можете использовать leadelf library.so, а затем сверять символы с заголовком библиотеки. Вот скрипт php оболочки, который делает это https://github.com/comarius/elf_resolver
источник