使用minGW创建DLLs
不灵活优雅的方式
首先,我们将创建一个DLL,只导出一个非常基本的函数,该函数将两个整数相加并返回结果。注意到下方代码中的“__declspec(dllexport)”,这是从DLL导出函数的关键。你想从DLL中导出的每个函数都应该用这个标记(任何不构成API一部分的内部函数都应该保持原样)。另外,注意到函数名前面的“__cdecl” 它声明了函数的调用约定(如果你不熟悉,请参阅Wikipedia关于x86调用约定的文章)。MinGW中C函数的默认调用约定是cdecl,但最好总是显式地声明调用约定,以防其他编译器有不同的默认值—如果发生这种情况,您的应用程序很可能会因为调用这些函数之一而出现错误行为或崩溃。请注意,为了准确地显示幕后发生了什么,第一个示例故意显得不灵活和不优雅。在下一节中,我们将使用预处理器定义隐藏这些细节。
1. /* add_basic.c
2. Demonstrates creating a DLL with an exported function, the inflexible way.
3. */
4.
5. __declspec(dllexport) int __cdecl Add(int a, int b)
6. {
7. return (a + b);
8. }
要编译它,只需要添加命令" -shared ":
>gcc -c -o add_basic.o add_basic.c
>gcc -o add_basic.dll -s -shared add_basic.o -Wl,--subsystem,windows
第一条命令生成文件add_basic.o,第二条命令生成add_basic.dll文件
应该不会报告任何错误,你现在应该有一个可用的DLL。在本例中,我将编译器和链接步骤分开。虽然对于这样一个小项目可以将其写在一起
gcc -o add_basic.dll -s -shared add_basic.c -Wl,--subsystem,windows
其中 -Wl,--subsystem,windows 不是必要的参数,因为不是编译窗口程序。注意 -s 选项,它清理导出的 DLL 符号,你可能只会想在发布发行版时需要。
现在可以构建使用此DLL的应用程序。为了使用Add(a, b)函数,需要在使用函数之前用" __declspec(dllimport) "属性对函数进行声明。 (注意它是用于客户端应用程序的dllimport,而不是在我们的DLL中使用的dllexport)。
1. /* addtest_basic.c
2.
3. Demon-strates using the function imported from the DLL, the inelegant way.
4. */
5.
6. #include <stdlib.h>
7. #include <stdio.h>
8.
9. /* Declare imported function so that we can actually use it. */
10. __declspec(dllimport) int __cdecl Add(int a, int b);
11.
12. int main(int argc, char** argv)
13. {
14. printf("%d\n", Add(6, 23));
15.
16. return EXIT_SUCCESS;
17. }
现在,只需在命令行上引用DLL,就可以编译和链接此应用程序。
>gcc -c -o addtest_basic.o addtest_basic.c
>gcc -o addtest_basic.exe -s addtest_basic.o -L. -ladd_basic
>addtest_basic.exe
" -L "选项令gcc搜索DLL的附加文件夹。在这种情况下,我们希望gcc搜索当前目录,所以我们可以只使用句点,但对于一个真正的DLL,我们已经部署到一个系统,我们将使用其目录的完整路径。" -l "选项指定了我们想要从其中导入函数的DLL -这应该是不带文件扩展名的DLL文件名。同样,对于这样一个小项目,可以通过执行“gcc -o addtest_basic.exe -s addtest_basic.c –L. -ladd_basic””来编译和链接应用程序。