c++ - Compilando una DLL con gcc
(5)
Estoy escribiendo un intérprete de guiones. Y, básicamente, quiero que se almacenen algunas clases y funciones en una DLL, pero quiero que la DLL busque funciones dentro de los programas que se vinculan a ella, como,
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
Me preguntaba básicamente, ¿cómo compilo una DLL con gcc? Bueno, estoy usando un puerto de Windows de gcc. Una vez que compilo un archivo .dll que contiene mis clases y funciones, ¿cómo puedo vincularlo con mi programa? ¿Cómo uso las clases y funciones en la DLL? ¿Puede el DLL invocar funciones desde el programa que lo enlaza? Si hago un objeto de clase {...}; en la DLL, cuando el programa cargue la DLL, ¿el objeto estará disponible para el programa? Gracias de antemano, realmente necesito saber cómo trabajar con DLL en C ++ antes de poder continuar con este proyecto.
"¿Puedes agregar más detalles sobre por qué quieres que el DLL llame a las funciones en el programa principal?"
Pensé que el diagrama lo explicaba ... el programa que usa el DLL pasa un trozo de código a la DLL, que analiza el código, y si las llamadas a función se encuentran en dicho código, las funciones correspondientes dentro del DLL se llaman ... por ejemplo, si aprobé "a = sqrt (100)", la función del analizador DLL encontraría la llamada de función a sqrt (), y dentro de la DLL sería una función sqrt () correspondiente que calcularía la raíz cuadrada del argumento pasado a él, y luego tomaría el valor de retorno de esa función y lo pondría en la variable a ... como cualquier otro programa, pero si no se encuentra un controlador correspondiente para la función sqrt () dentro de la DLL (allí sería una lista de funciones soportadas nativamente) luego llamaría a una función similar que residiría dentro del programa que usa el DLL para ver si hay funciones definidas por el usuario con ese nombre.
Entonces, digamos que cargó la DLL en el programa, lo que le da a su programa la capacidad de interpretar guiones de este idioma en particular, el programa podría llamar a las DLL para procesar líneas únicas de código o entregar los nombres de archivo de las secuencias de comandos para procesar ... pero si desea para agregar un comando a la secuencia de comandos que se adapte a la finalidad de su programa, podría establecer un valor booleano en la DLL diciéndole que está agregando funciones a su idioma y luego crear una función en su código que enumere las funciones que usted está agregando (el DLL lo llamaría con el nombre de la función que desea, si esa función es una definida por el usuario dentro de su código, la función llamaría a la función correspondiente con el argumento que le pasó el DLL, el retorno del devolver el valor de la función definida por el usuario a la DLL, y si no existiera, devolvería un código de error o NULL o algo así). Estoy empezando a ver que tendré que encontrar otra forma de evitar esto para que las llamadas de función vayan de una sola manera
Con respecto al detalle de lo que planeas resolver, tal vez deberías mirar un analizador extensible como lua en lugar de construir el tuyo propio.
Para su enfoque más específico.
Un archivo DLL (típicamente) está destinado a ser completo en sí mismo, o explícitamente saber qué otras bibliotecas utilizar para completarse.
Lo que quiero decir con eso es que no se puede tener un método implícitamente provisto por la aplicación de llamada para completar la funcionalidad de las DLL.
Sin embargo, puede hacer que parte de su API sea la provisión de métodos de una aplicación de llamada, lo que hace que la DLL esté completamente contenida y el paso del conocimiento sea explícito.
¿Cómo uso las clases y funciones en la DLL?
Incluya los encabezados en su código, cuando el módulo (exe u otro dll) esté vinculado, se verificará si los archivos DLL están completos.
¿Puede el DLL invocar funciones desde el programa que lo enlaza?
Sí, pero se debe contar sobre ellos en tiempo de ejecución.
Si hago un objeto de clase {...}; en la DLL, cuando el programa cargue la DLL, ¿el objeto estará disponible para el programa?
Sí, estará disponible, sin embargo, hay algunas restricciones que debe conocer. Tal como en el área de administración de memoria, es importante:
- Enlace todos los módulos que comparten memoria con el mismo dll de administración de memoria (típicamente c runtime)
- Asegúrese de que la memoria esté asignada y repartida solo en el mismo módulo.
- asignar en la pila
¡Ejemplos!
Aquí hay una idea básica de pasar funciones a la DLL, sin embargo, en su caso puede no ser de gran ayuda, ya que necesita saber por adelantado qué otras funciones desea proporcionar.
// parser.h
struct functions {
void *fred (int );
};
parse( string, functions );
// program.cpp
parse( "a = sqrt(); fred(a);", functions );
Lo que necesita es una forma de registrar funciones (y sus detalles con el dll). El problema más grande aquí es el bit de los detalles. Pero omitiendo eso, puede hacer algo como lo hace wxWidgets con el registro de clases. Cuando la aplicación construye method_fred, llamará al constructor y se registrará con el archivo dll mediante el uso de methodInfo. El analizador puede buscar methodInfo para los métodos disponibles.
// 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);
Esto suena como un trabajo para estructuras de datos.
Crea una estructura que contenga tus palabras clave y la función asociada a cada una.
struct keyword {
const char *keyword;
int (*f)(int arg);
};
struct keyword keywords[max_keywords] = {
"db_connect", &db_connect,
}
A continuación, escriba una función en su DLL para pasar la dirección de esta matriz a:
plugin_register(keywords);
Luego dentro de la DLL puede hacer:
keywords[0].f = &plugin_db_connect;
Con este método, el código para manejar las palabras clave de script permanece en el programa principal mientras que el DLL manipula las estructuras de datos para obtener sus propias funciones.
Llevándolo a C ++, haga de la estructura una clase que contenga un std :: vector o std :: map o cualquiera de las palabras clave y algunas funciones para manipularlas.
Siempre puedes cargar el dll en tiempo de ejecución con la biblioteca de carga
Este enlace explica cómo hacerlo de una manera básica.
En una vista de gran pantalla, cuando hace un dll, está creando una biblioteca que se carga en tiempo de ejecución. Contiene una serie de símbolos que se exportan. Estos símbolos suelen ser referencias a métodos o funciones, además de compilador / linker goo.
Cuando normalmente construyes una biblioteca estática, hay un mínimo de sustancia pegajosa y el vinculador extrae el código que necesita y lo vuelve a empaquetar en tu ejecutable.
En un dll, en realidad obtienes dos productos finales (tres realmente solo esperan): una biblioteca dll y una stub. El resguardo es una biblioteca estática que se ve exactamente como su biblioteca estática normal, excepto que en lugar de ejecutar su código, cada resguardo es típicamente una instrucción de salto a una rutina común. La rutina común carga tu dll, obtiene la dirección de la rutina a la que deseas llamar y luego actualiza la instrucción de salto original para ir allí, de modo que cuando la vuelvas a llamar, termines en tu dll.
El tercer producto final suele ser un archivo de encabezado que le informa todo acerca de los tipos de datos en su biblioteca.
Así que sus pasos son: crear sus encabezados y código, construir un archivo DLL, crear una biblioteca de código auxiliar de los encabezados / código / alguna lista de funciones exportadas. El código de final se vinculará a la biblioteca de stub que cargará el dll y arreglará la tabla de salto.
El compilador / linker goo incluye cosas como asegurarse de que las bibliotecas de tiempo de ejecución estén donde se necesiten, asegurándose de que los constructores estáticos se ejecuten, asegurándose de que los destructores estáticos estén registrados para su posterior ejecución, etc., etc.
Ahora en cuanto a su problema principal: ¿cómo puedo escribir código extensible en un dll? Hay varias formas posibles: una forma típica es definir una clase abstracta pura (también conocida como interfaz) que define un comportamiento y pasarlo a una rutina de procesamiento o crear una rutina para registrar interfaces para hacer el trabajo, luego el procesamiento la rutina le pide al registrador un objeto para manejar una pieza de trabajo para ello.
Winrawr, antes de continuar, lee esto primero :
¿Alguna mejora en el frente GCC / Windows DLL / C ++ STL?
Básicamente, puede tener problemas al pasar cadenas STL alrededor de sus archivos DLL , y también puede tener problemas con las excepciones que sobrepasan los límites de la DLL, aunque no es algo que haya experimentado (todavía).