Компиляция DLL с gcc

Sooooo Я пишу интерпретатор script. И в основном, я хочу, чтобы некоторые классы и функции хранились в DLL, но я хочу, чтобы DLL искала функции в программах, которые связываются с ним, например,

       program                dll
----------------------------------------------------
send code to dll----->    parse code
                              |
                              v
                          code contains a function,
                          that isn't contained in the DLL
                              |
list of functions in   <------/
program
      |
      v
corresponding function,
user-defined in the
program--process the
passed argument here
      |
      \-------------->    return value sent back
                          to the parsing function

Мне было интересно, как мне скомпилировать DLL с gcc? Ну, я использую порт windows gcc. Как только я скомпилирую DLL, содержащую мои классы и функции, как мне связать с ней мою программу? Как использовать классы и функции в DLL? Может ли функция вызова DLL из программы связываться с ней? Если я создаю объект класса {...}; в DLL, тогда, когда DLL загружается программой, объект будет доступен для программы? Заранее спасибо, мне действительно нужно знать, как работать с DLL на С++, прежде чем я смогу продолжить этот проект.

"Можете ли вы добавить более подробную информацию о том, почему вы хотите, чтобы DLL вызывала функции в основной программе?"

Я думал, что вид диаграммы объяснил это... программа, использующая DLL, передает кусок кода в DLL, который анализирует код, и если вызовы функций найдены в указанном коде, тогда соответствующие функции в DLL вызываются... например, если я передал "a = sqrt (100)", то функция парсера DLL найдет вызов функции для sqrt(), а внутри DLL будет соответствующая функция sqrt(), которая будет вычислять квадратный корень аргумента, переданного ему, а затем он примет возвращаемое значение из этой функции и поместит его в переменную a... точно так же, как любая другая программа, но если соответствующий обработчик для функции sqrt() не найден в пределах DLL (там будет список поддерживаемых изначально функций), тогда он будет вызывать аналогичную функцию, которая будет находиться внутри программы, используя DLL, чтобы узнать, есть ли какие-то пользовательские функции этим именем.

Итак, скажем, вы загрузили DLL в программу, предоставляя вашей программе возможность интерпретировать сценарии этого конкретного языка, программа могла вызвать библиотеки DLL для обработки отдельных строк кода или передать им имена файлов сценариев для обработки... но если вы хотите добавить команду в script, которая подходит для вашей программы, вы можете сказать, что в DLL необходимо указать логическое значение, указывающее, что вы добавляете функции на свой язык, а затем создаете функцию в своем коде, которая список функций, которые вы добавляете (DLL будет вызывать его с именем функции, которую она хочет, если эта функция является определяемой пользователем, содержащейся в вашем коде, функция будет вызывать соответствующую функцию с аргументом, переданным ей DLL, вернуть возвращаемое значение пользовательской функции обратно в DLL, а если оно не существует, оно вернет код ошибки или NULL или что-то еще). Я начинаю видеть, что мне придется найти другой способ обойти это, чтобы вызовы функций проходили только в одну сторону.

Ответ 1

Эта ссылка объясняет, как сделать это основным способом.

В представлении большого изображения, когда вы делаете dll, вы создаете библиотеку, которая загружается во время выполнения. Он содержит несколько символов, которые экспортируются. Эти символы обычно относятся к методам или функциям, плюс компилятор/компоновщик goo.

Когда вы обычно создаете статическую библиотеку, существует минимум goo, и компоновщик тянет код, который ему нужен, и переупаковывает его для вас в вашем исполняемом файле.

В dll вы фактически получаете два конечных продукта (три действительно - просто подождите): dll и заглушка. Штук - это статическая библиотека, которая выглядит точно так же, как ваша обычная статическая библиотека, за исключением того, что вместо выполнения вашего кода каждый заглушка обычно является инструкцией перехода к общей процедуре. Обычная подпрограмма загружает вашу DLL, получает адрес подпрограммы, которую вы хотите вызвать, затем добавляет исходную инструкцию перехода, чтобы вернуться туда, и когда вы ее снова вызовете, вы попадете в свою DLL.

Третий конечный продукт - это обычно заголовочный файл, в котором рассказывается о типах данных в вашей библиотеке.

Итак, ваши шаги: создайте заголовки и код, создайте dll, создайте библиотеку заглушек из заголовков/кода/некоторого списка экспортируемых функций. Конец кода будет связан с библиотекой-заглушкой, которая будет загружать DLL и фиксировать таблицу перехода.

Компилятор/компоновщик goo включает в себя такие вещи, как проверка наличия библиотек времени выполнения, где они нужны, следя за тем, чтобы выполнялись статические конструкторы, убедившись, что статические деструкторы зарегистрированы для последующего выполнения и т.д. и т.д. и т.д.

Теперь о вашей основной проблеме: как написать расширяемый код в dll? Существует несколько возможных способов - типичным способом является определение чистого абстрактного класса (aka interface), который определяет поведение и либо передают это в процедуру обработки, либо создает процедуру для регистрации интерфейсов для выполнения работы, а затем обработку подпрограмма просит регистратора для объекта обрабатывать часть работы для него.

Ответ 2

В деталях того, что вы планируете решить, возможно, вам стоит рассмотреть расширяемый парсер, например lua, вместо того, чтобы создавать свои собственные.

К вашему более конкретному фокусу.
DLL (обычно?) Должна быть полной сама по себе или явно знать, какие другие библиотеки использовать для завершения.

Я имею в виду, что вы не можете иметь метод, неявно предоставляемый вызывающим приложением для выполнения функций DLL.

Однако вы могли бы сделать часть вашего API предоставлением методов из вызывающего приложения, таким образом сделав DLL полностью содержащейся и передав знание явным.

Как использовать классы и функции в DLL?
Включите заголовки в свой код, когда модуль (exe или другая dll) связан, dll проверяются на завершение.

Может ли функция вызова DLL из программы связываться с ней?
Да, но о них нужно рассказывать во время выполнения.

Если я создаю объект класса {...}; в DLL, тогда, когда DLL загружается программой, объект будет доступен для программы?
Да, он будет доступен, однако есть некоторые ограничения, о которых вам нужно знать. Например, в области управления памятью важно либо:

  • Свяжите все модули, совместно использующие память, с одной и той же DLL-памятью управления (обычно c runtime)
  • Убедитесь, что память выделена и освобождена только в том же модуле.
  • выделить в стек

Примеры!
Вот основная идея передачи функций в dll, однако в вашем случае это может быть не очень полезно, поскольку вам нужно знать, какие другие функции вы хотите предоставить.

// parser.h
struct functions {
  void *fred (int );
};

parse( string, functions );

// program.cpp
parse( "a = sqrt(); fred(a);", functions );

Что вам нужно - это способ регистрации функций (и их данных с помощью dll.) Большей проблемой здесь является бит детали. Но пропуская это, вы можете сделать что-то вроде wxWidgets с регистрацией классов. Когда method_fred будет обработан вашим приложением, он вызовет конструктор и зарегистрируется в DLL через использование off methodInfo. Parser может искать метод infoInfo для доступных методов.

// parser.h
class method_base { };
class methodInfo {
   static void register(factory);
   static map<string,factory> m_methods;
}

// program.cpp
class method_fred : public method_base {
   static method* factory(string args);
   static methodInfo _methoinfo;
}
methodInfo method_fred::_methoinfo("fred",method_fred::factory);

Ответ 3

Это похоже на работу для структур данных.

Создайте структуру, содержащую ваши ключевые слова и функцию, связанную с каждой из них.

struct keyword {
    const char *keyword;
    int (*f)(int arg);
};

struct keyword keywords[max_keywords] = {
    "db_connect", &db_connect,
}

Затем напишите функцию в вашей DLL, в которой вы передаете адрес этого массива:

plugin_register(keywords);

Затем внутри DLL он может делать:

keywords[0].f = &plugin_db_connect;

С помощью этого метода код для обработки script ключевых слов остается в основной программе, тогда как DLL манипулирует структурами данных для вызова своих собственных функций.

Взяв его на С++, создайте вместо него класс class, который содержит карту std::vector или std:: или какие-либо ключевые слова и некоторые функции для их управления.

Ответ 4

Winrawr, прежде чем продолжить, прочитайте это сначала:

Любые улучшения в интерфейсе GCC/Windows DLL/С++ STL?

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