C++ 使用 gcc 编译 DLL

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/505567/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 15:43:22  来源:igfitidea点击:

Compiling a DLL with gcc

c++dllgcc

提问by user61721

Sooooo I'm writing a script interpreter. And basically, I want some classes and functions stored in a DLL, but I want the DLL to look for functions within the programs that are linking to it, like,

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

I was wondering basically, how do I compile a DLL with gcc? Well, I'm using a windows port of gcc. Once I compile a .dll containing my classes and functions, how do I link to it with my program? How do I use the classes and functions in the DLL? Can the DLL call functions from the program linking to it? If I make a class { ... } object; in the DLL, then when the DLL is loaded by the program, will object be available to the program? Thanks in advance, I really need to know how to work with DLLs in C++ before I can continue with this project.

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

"Can you add more detail as to why you want the DLL to call functions in the main program?"

“你能更详细地说明为什么你希望 DLL 调用主程序中的函数吗?”

I thought the diagram sort of explained it... the program using the DLL passes a piece of code to the DLL, which parses the code, and if function calls are found in said code then corresponding functions within the DLL are called... for example, if I passed "a = sqrt(100)" then the DLL parser function would find the function call to sqrt(), and within the DLL would be a corresponding sqrt() function which would calculate the square root of the argument passed to it, and then it would take the return value from that function and put it into variable a... just like any other program, but if a corresponding handler for the sqrt() function isn't found within the DLL (there would be a list of natively supported functions) then it would call a similar function which would reside within the program using the DLL to see if there are any user-defined functions by that name.

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

So, say you loaded the DLL into the program giving your program the ability to interpret scripts of this particular language, the program could call the DLLs to process single lines of code or hand it filenames of scripts to process... but if you want to add a command into the script which suits the purpose of your program, you could say set a boolean value in the DLL telling it that you are adding functions to its language and then create a function in your code which would list the functions you are adding (the DLL would call it with the name of the function it wants, if that function is a user-defined one contained within your code, the function would call the corresponding function with the argument passed to it by the DLL, the return the return value of the user-defined function back to the DLL, and if it didn't exist, it would return an error code or NULL or something). I'm starting to see that I'll have to find another way around this to make the function calls go one way only

它会返回错误代码或 NULL 或其他东西)。我开始看到我必须找到另一种方法来使函数调用只以一种方式进行

回答by plinth

This linkexplains how to do it in a basic way.

此链接解释了如何以基本方式进行操作。

In a big picture view, when you make a dll, you are making a library which is loaded at runtime. It contains a number of symbols which are exported. These symbols are typically references to methods or functions, plus compiler/linker goo.

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

When you normally build a static library, there is a minimum of goo and the linker pulls in the code it needs and repackages it for you in your executable.

当您通常构建一个静态库时,最少有一个 goo,链接器会拉入它需要的代码并在您的可执行文件中为您重新打包它。

In a dll, you actually get two end products (three really- just wait): a dll and a stub library. The stub is a static library that looks exactly like your regular static library, except that instead of executing your code, each stub is typically a jump instruction to a common routine. The common routine loads your dll, gets the address of the routine that you want to call, then patches up the original jump instruction to go there so when you call it again, you end up in your dll.

在 dll 中,您实际上会得到两个最终产品(三个真的 - 等等):一个 dll 和一个存根库。存根是一个静态库,它看起来与您的常规静态库完全一样,不同之处在于每个存根不是执行您的代码,而是通常是一条跳转到公共例程的指令。通用例程加载您的 dll,获取您要调用的例程的地址,然后修补原始跳转指令到那里,因此当您再次调用它时,您最终会进入您的 dll。

The third end product is usually a header file that tells you all about the data types in your library.

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

So your steps are: create your headers and code, build a dll, build a stub library from the headers/code/some list of exported functions. End code will link to the stub library which will load up the dll and fix up the jump table.

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

Compiler/linker goo includes things like making sure the runtime libraries are where they're needed, making sure that static constructors are executed, making sure that static destructors are registered for later execution, etc, etc, etc.

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

Now as to your main problem: how do I write extensible code in a dll? There are a number of possible ways - a typical way is to define a pure abstract class (aka interface) that defines a behavior and either pass that in to a processing routine or to create a routine for registering interfaces to do work, then the processing routine asks the registrar for an object to handle a piece of work for it.

现在至于您的主要问题:如何在 dll 中编写可扩展代码?有许多可能的方法 - 一个典型的方法是定义一个纯抽象类(又名接口),它定义了一个行为,并将其传递给一个处理例程或创建一个例程来注册接口来完成工作,然后处理例程向注册器请求一个对象来为它处理一项工作。

回答by Greg Domjan

On the detail of what you plan to solve, perhaps you should look at an extendible parser like lua instead of building your own.

关于您计划解决的细节,也许您应该查看像 lua 这样的可扩展解析器,而不是构建自己的解析器。

To your more specific focus.
A DLL is (typically?) meant to be complete in and of itself, or explicitly know what other libraries to use to complete itself.

到您更具体的关注点。
DLL 是(通常?)意味着本身是完整的,或者明确知道要使用哪些其他库来完成自身。

What I mean by that is, you cannot have a method implicitly provided by the calling application to complete the DLLs functionality.

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

You could however make part of your API the provision of methods from a calling app, thus making the DLL fully contained and the passing of knowledge explicit.

但是,您可以使 API 的一部分提供来自调用应用程序的方法,从而使 DLL 完全包含在内并明确传递知识。

How do I use the classes and functions in the DLL?
Include the headers in your code, when the module (exe or another dll) is linked the dlls are checked for completness.

如何使用 DLL 中的类和函数?
在代码中包含头文件,当模块(exe 或另一个 dll)链接时,会检查 dll 的完整性。

Can the DLL call functions from the program linking to it?
Yes, but it has to be told about them at run time.

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

If I make a class { ... } object; in the DLL, then when the DLL is loaded by the program, will object be available to the program?
Yes it will be available, however there are some restrictions you need to be aware about. Such as in the area of memory management it is important to either:

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

  • Link all modules sharing memory with the same memory management dll (typically c runtime)
  • Ensure that the memory is allocated and dealloccated only in the same module.
  • allocate on the stack
  • 使用相同的内存管理 dll(通常是 c 运行时)链接共享内存的所有模块
  • 确保仅在同一模块中分配和释放内存。
  • 在堆栈上分配

Examples!
Here is a basic idea of passing functions to the dll, however in your case may not be most helpfull as you need to know up front what other functions you want provided.

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

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

parse( string, functions );

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

What you need is a way of registering functions(and their details with the dll.) The bigger problem here is the details bit. But skipping over that you might do something like wxWidgets does with class registration. When method_fred is contructed by your app it will call the constructor and register with the dll through usage off methodInfo. Parser can lookup methodInfo for methods available.

您需要的是一种注册函数(以及它们与 dll 的详细信息)的方法。这里更大的问题是细节位。但是跳过你可能会做一些类似 wxWidgets 的类注册。当你的应用程序构造 method_fred 时,它会调用构造函数并通过使用 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);

回答by Zan Lynx

This sounds like a job for data structures.

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

Create a struct containing your keywords and the function associated with each one.

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

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

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

Then write a function in your DLL that you pass the address of this array to:

然后在您的 DLL 中编写一个函数,将该数组的地址传递给:

plugin_register(keywords);

Then inside the DLL it can do:

然后在 DLL 中它可以执行以下操作:

keywords[0].f = &plugin_db_connect;

With this method, the code to handle script keywords remains in the main program while the DLL manipulates the data structures to get its own functions called.

使用这种方法,处理脚本关键字的代码保留在主程序中,而 DLL 操作数据结构以调用自己的函数。

Taking it to C++, make the struct a class instead that contains a std::vector or std::map or whatever of keywords and some functions to manipulate them.

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

回答by Carl Seleborg

Winrawr, before you go on, read this first:

Winrawr,在继续之前,请先阅读以下内容

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

GCC/Windows DLLs/C++ STL 前端有什么改进吗?

Basically, you may run into problems when passing STL strings around your DLLs, and you may also have trouble with exceptions flying across DLL boundaries, although it's not something I have experienced (yet).

基本上,在围绕 DLL 传递 STL 字符串时可能会遇到问题,并且您也可能会遇到跨越 DLL 边界的异常,尽管这不是我(还)经历过的。

回答by cbrulak

You could always load the dll at runtime with load library

您始终可以在运行时使用加载库加载 dll