使用gcc编译DLL

时间:2009-02-03 00:16:16

标签: c++ dll gcc

Sooooo我正在写一个脚本解释器。基本上,我想要一些存储在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

我基本上想知道,如何用gcc编译DLL?好吧,我正在使用gcc的windows端口。一旦我编译了包含我的类和函数的.dll,我如何用我的程序链接到它?如何使用DLL中的类和函数? DLL可以从链接到它的程序调用函数吗?如果我创建一个类{...}对象;在DLL中,然后当程序加载DLL时,对象是否可用于程序?在此之前,我真的需要知道在继续这个项目之前如何在C ++中使用DLL。

“你能否添加更多关于你希望DLL在主程序中调用函数的细节?”

我认为该图解释了它...使用DLL的程序将一段代码传递给DLL,它解析代码,如果在所述代码中找到函数调用,则调用DLL中的相应函数...例如,如果我传递“a = sqrt(100)”,那么DLL解析器函数将找到对sqrt()的函数调用,并且在DLL中将是相应的sqrt()函数,它将计算平方根传递给它的参数,然后它将获取该函数的返回值并将其放入变量a ...就像任何其他程序一样,但是如果找不到sqrt()函数的相应处理程序DLL(会有一个本机支持的函数列表)然后它将调用一个类似的函数,该函数将驻留在程序中使用DLL来查看该名称是否有任何用户定义的函数。

因此,假设您将DLL加载到程序中,使您的程序能够解释此特定语言的脚本,程序可以调用DLL来处理单行代码或将脚本的文件名交给处理......但是如果你想在脚本中添加一个符合你程序目的的命令,你可以说在DLL中设置一个布尔值,告诉你要在其语言中添加函数,然后在你的代码中创建一个函数列出你正在添加的函数(DLL会用它想要的函数名称来调用它,如果该函数是你的代码中包含的用户定义函数,该函数将使用DLL传递给它的参数调用相应的函数,将用户定义函数的返回值返回给DLL,如果它不存在,则返回错误代码或NULL或其他内容)。我开始看到我必须找到另一种方法来使函数调用只有一种方式

5 个答案:

答案 0 :(得分:8)

This link解释了如何以基本方式完成。

在大图中,当你创建一个dll时,你正在创建一个在运行时加载的库。它包含许多导出的符号。这些符号通常是对方法或函数的引用,加上编译器/链接器goo。

当你正常构建一个静态库时,只有最少的goo,链接器会提取它所需的代码并在你的可执行文件中为你重新打包它。

在一个dll中,你实际上得到了两个最终产品(三个真正 - 只是等待):一个dll和一个存根库。存根是一个静态库,看起来与常规静态库完全相同,除了不是执行代码,每个存根通常是对常规例程的跳转指令。常用例程加载你的dll,获取你想要调用的例程的地址,然后修补原始的跳转指令去那里,所以当你再次调用它时,你最终会进入你的dll。

第三个最终产品通常是一个头文件,它会告诉您库中数据类型的所有信息。

所以你的步骤是:创建你的头文件和代码,构建一个dll,从头文件/代码/一些导出函数列表中构建一个存根库。结束代码将链接到存根库,它将加载dll并修复跳转表。

编译器/链接器goo包括确保运行时库在需要的地方,确保执行静态构造函数,确保静态析构函数注册以供以后执行等等。

现在您的主要问题是:如何在dll中编写可扩展代码?有许多可能的方法 - 一种典型的方法是定义一个纯抽象类(也就是接口)来定义一个行为,并将其传递给一个处理例程,或者创建一个例程来注册接口来做工作,然后处理例程要求注册商提供一个对象来处理它的工作。

答案 1 :(得分:2)

关于你打算解决的问题的细节,也许你应该看一下像lua这样的可扩展解析器而不是构建你自己的解析器。

更具体的焦点。
DLL(通常是?)意味着它本身就是完整的,或者明确地知道用什么来完成它自己。

我的意思是,你不能有一个调用应用程序隐式提供的方法来完成DLL的功能。

然而,您可以通过调用应用程序为您的API提供方法,从而使DLL完全包含并明确传递知识。

如何使用DLL中的类和函数?
在代码中包含标题,当链接模块(exe或其他dll)时,会检查dll的完整性。

DLL可以从链接到它的程序中调用函数吗?
是的,但必须在运行时告诉他们。

如果我创建一个类{...}对象;在DLL中,然后当程序加载DLL时,对象是否可用于程序?
是的,它将可用,但是您需要注意一些限制。例如在内存管理方面,重要的是:

  • 将共享内存的所有模块与相同的内存管理dll(通常为c运行时)链接
  • 确保仅在同一模块中分配和解除分配内存。
  • 在堆栈上分配

实例!
这是将函数传递给dll的基本思路,但在您的情况下可能不是最有用的,因为您需要预先知道您想要提供的其他函数。

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

parse( string, functions );

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

您需要的是一种注册函数的方法(以及它们与dll的详细信息。) 这里更大的问题是细节位。但是跳过那些你可能会像wxWidgets那样做类注册。当您的应用程序构造method_fred时,它将调用构造函数并通过使用off methodInfo注册dll。解析器可以查找methodInfo以获取可用的方法。

// 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);

答案 2 :(得分:0)

这听起来像是数据结构的工作。

创建一个包含关键字和与每个关键字相关联的函数的结构。

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;

使用此方法,处理脚本关键字的代码保留在主程序中,而DLL操纵数据结构以获取其自己的函数。

将它带到C ++,使结构成为一个类,而不是包含std :: vector或std :: map或其他任何关键字和一些操作它们的函数。

答案 3 :(得分:0)

Winrawr,在你继续之前,首先阅读

Any improvements on the GCC/Windows DLLs/C++ STL front?

基本上,在你的DLL周围传递STL字符串时可能会遇到问题,而且你也可能遇到跨越DLL边界的异常问题,虽然这不是我经历过的事情。 / p>

答案 4 :(得分:-1)

您始终可以使用load library

在运行时加载dll