现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

MinGW使用和创建DLL时应注意的问题

2014-09-18 06:26 工业·编程 ⁄ 共 1442字 ⁄ 字号 暂无评论

MinGW 是 GCC 的 Windows 版本,稳定版已经到了 4.5.2,功能和性能上很好,感觉不比 Microsoft 自家的 VC 差的。但是 MinGW 下使用和创建 DLL 倒是要特别注意,问题主要集中在 g++ 编译器(C++ 的 GNU 版本编译器)对于 DLL 的函数输入以及输出的名称修饰、调用协议上和 VC 编译器是有很大区别的。

1、MinGW 如何使用一个标准的 DLL

这里标准 DLL 指的是采用 __stdcall 调用协议、并且导出函数名称干干净净,没有函数名尾部的 @nn、没有函数名头部的下划线的。MinGW 的 g++ 程序中,对于需要从 DLL 中导入的函数,声明时必须要用 extern "C",但不要用 __declspec(dllimport),虽然 g++ 支持,但是一旦你使用,则 g++ 在链接时会自动强制在需要导入的函数名前加 _imp__ 前缀,导致链接时找不到函数名错误。所以,我们其实完全不需要用 __declspec(dllimport)。另一方面,gcc/g++ 编译器遇到代码中 __stdcall 修饰的函数名,会自动将其函数名在链接时设置为函数名@nn,nn 是函数参数栈字节数。另外,gcc/g++ 编译器/链接器在链接时其实不需要 DLL 的导入库(import lib),因为它们可以直接从 DLL 链接,这样更加方便,省去了很多从 DLL 如何生成符合格式要求的 .a 导入库等问题。

只需要在 gcc/g++ 参数中加入 -Wl,--enable-stdcall-fixup -L../../Bin/ -lDLL文件名(不含.dll)即可直接从 DLL 文件本身完成链接。

这里要注意,-Wl参数指示 g++ 链接器需要采用后面的链接控制参数(以逗号分隔),--enable-stdcall-fixup 告诉 g++ 链接器需要导入的 DLL 函数的名字需要自动在尾部加上 @nn 格式的后缀,以便符合 gcc/g++ 对 __stdcall 函数名的扩展规范。-L 指定 DLL 文件所在目录,-l 指定 DLL 文件名称,不带 .dll。如果不加 --enable-stdcall-fixup,gcc/g++ 总是会报链接错误,因为 gcc/g++ 将代码中需要从 DLL 导入的函数名后面都强制加了 @nn,但是 DLL 中的函数名不带 @nn,没有 --enable-stdcall-fixup,很有可能就会出错。即时不出错,也会有很多警告,很有可能会导致程序 crash!

注,在 NetBeans CDT 中,-Wl,--enable-stdcall-fixup -L -l 这样的参数在链接器参数设置中指定。

2、MinGW 如何创建一个标准的 DLL

MinGW 中创建标准 DLL,应该使用 __declspec(dllexport),包括 extern "C" 等都是和 VC 一样的。但要注意,这样编译链接生成的 DLL,导出的函数名尾部都带有 @nn,为了要去除它们,必须在链接器参数设置中使用 -Wl,--kill-at,它告诉链接器创建 DLL 时导出的函数名尾部不要带有 @nn。

注,在 NetBeans CDT 中,上面这个参数同样是在链接器参数设置中指定。

综上,如果创建一个 DLL,同时这个 DLL 又需要导入其他 DLL 的函数,参数就可以统一为 -Wl,--kill-at,--enable-stdcall-fixup -L -l

这样了,很方便。感觉 MinGW 确实相当强悍,跨平台,可调性很灵活,性能也很强劲,更难能可贵的是,它是一个免费而又强大的编译器!

当然,搭配 NetBeans CDT 更是相当好的一款 C/C++ 开发利器。

作者:小侠数码

给我留言

留言无头像?