Я пишу приложение на C, которое может быть расширено во время выполнения с помощью модулей/общих объектов/библиотек DLL. Эти модули могут использовать API существующей программы, но могут также предоставлять новые функции для использования в более поздних загружаемых модулях, поэтому существует вероятность того, что модули будут иметь зависимости друг от друга.Динамические модули с DLL на Windows
Мой текущий подход под Linux заключается в том, чтобы каждый модуль определял функцию depend(), которая возвращает список других имен модулей, от которых это зависит. Таким образом, я могу скомпилировать и связать каждый модуль для себя, загрузить модуль с помощью dlopen() и RTLD_LAZY
, сначала разрешить его зависимости, а затем полностью загрузить его с помощью RTLD_GLOBAL
. Это прекрасно работает и делает именно то, что я хочу. Он также позволяет мне заменить модуль на другую версию без перекомпиляции всех других модулей в зависимости от нее.
Актуальная проблема возникает при переносе на Windows. Во-первых, я не нашел способа связать DLL, не предоставив ей таблицы символов экспорта всех его зависимостей. Есть ли тот, который я забыл?
Во-вторых, LoadLibraryEx из Windows API, похоже, не может выполнять какую-либо ленивую загрузку, потому что вместо того, чтобы позволить мне обрабатывать зависимости, он идет вперед и загружает все связанные DLL-файлы, прежде чем он вернется. Поскольку я хотел бы также проверить версию, прежде чем загружать модули в будущем, это совсем не то, что я хочу. Есть ли способ обойти это поведение?
Третья особенность заключается в том, что я не могу заменить DLL, не перекомпилируя все остальные модули в зависимости от нее. На самом деле это иногда срабатывает, но обычно происходят дикие вещи или программа segfaults.
Можно ли даже написать такое модульное приложение в Windows? Любые предложения или разные подходы заслуживают высокой оценки!
Обновление: Просто чтобы пояснить, как мои модули используют функции друг друга в Linux (что я хотел бы иметь и в Windows): каждый модуль просто возвращает имя другого модуля, который он хотел бы вызвать выполняет функции из описанной функции depend() и включает ее заголовок, а затем вызывает используемые функции непосредственно в коде без какой-либо обертки. Это работает, потому что Linux не требует, чтобы все символы были разрешены во время соединения для общих объектов.
Хорошо, ваше предложение о 'GetProcAddress' уже немного помогает. Я просто попробовал это и назвал функцию из DLL таким образом, не связавшись с ней.Но это означало бы, что я не мог просто позволить модулю включать заголовки того, от кого он зависит, как в Linux, не так ли? Мне нужно как-то собрать все необходимые указатели функций с помощью 'GetProcAddress', прежде чем вызывать что-либо из родительского модуля. Спасибо также за отзыв с COM, я посмотрю на это. – smf68
Да, но, как я уже сказал, просто сгруппируйте все функции для одного модуля в класс и вызовите это. Это намного проще, и это также уменьшает количество экспортированных символов. Это не COM, поскольку у вас нет наследования, это просто основано на аналогичной идее. Ваши клиенты используют интерфейс, не зная фактической реализации за ним. – Anteru
Интересная тема. Таким образом, нет никакого способа сделать это без того, что разработчик модуля должен иметь знания о WinAPI и/или COM? :-( – Gregor