1. 新建 C/C++ Project >> shared library
之前配置了mingw-gcc 这里的 cross gcc 默认指向的就是 mingw path,若没有配置环境变量,也可以手动添加
2. 工程属性配置
C/C++ Build
3. 头文件 条件编译
小生也是初学乍练,场景是这样的,因为使用mingw-gcc 编出的库,可以直接提供给qt 使用,但是vs上就是不能使用,加载后依然无法找到执行函数。
原因是导出函数机制的问题。QT 中报错如:
error: undefined reference to `_imp__glClearColor@16'
/* on MS environments, the inline keyword is available in C++ only */
#if !defined(__cplusplus)
#define inline __inline
#endif
/* on windows with mingw32 */
#if defined(__GNUC__)
# define PRE_CDECL
# define POST_CDECL __attribute__((cdecl))
# define PRE_STDCALL
# define POST_STDCALL __attribute__((stdcall))
# define PRE_FASTCALL
# define POST_FASTCALL __attribute__((fastcall))
#else
# define PRE_CDECL __cdecl
# define POST_CDECL
# define PRE_STDCALL __stdcall
# define POST_STDCALL
# define PRE_FASTCALL __fastcall
# define POST_FASTCALL
#endif /* __GNUC__ */
函数声明:
#if defined(LIBUSP_BPM22_EXPORTS)
#define LIBUSP_BPM22_API __declspec(dllexport)
#else
#define LIBUSP_BPM22_API __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C"
{
#endif
LIBUSP_BPM22_API int PRE_CDECL dll_test(int aa) POST_CDECL;
#ifdef __cplusplus
}
#endif
#endif /* LIBUSP_BPM22_H_ */
4. 生成对应导入库 dll lib
-- 使用 pexports 导出 def 文件
导出 C++ 文件中的函数,必须将修饰名放到 .def 文件中,或者通过使用外部“C”定义具有标准 C 链接的导出函数。如果需要将修饰名放到 .def 文件中,则可以通过使用 DUMPBIN 工具或 /MAP 链接器选项来获取修饰名。请注意,编译器产生的修饰名是编译器特定的。如果将 Visual C++ 编译器产生的修饰名放到 .def 文件中,则链接到 DLL 的应用程序必须也是用相同版本的 Visual C++ 生成的,这样调用应用程序中的修饰名才能与 DLL 的 .def 文件中的导出名相匹配。
当生成 DLL 时,链接器使用 .def 文件创建导出 (.exp) 文件和导入库 (.lib) 文件。然后,链接器使用导出文件生成 DLL 文件。隐式链接到 DLL 的可执行文件在生成时链接到导入库。在VC++中,如果生成DLL可以不使用.def文件。你只需要在VC++的函数定义前要加 __declspec(dllexport)修饰就可以了。但是使用__declspec(dllexport)和使用.def文件是有区别的。如果你的 DLL是提供给VC++用户使用的,你只需要把编译DLL时产生的.lib提供给用户,它可以很轻松地调用你的DLL。但是如果你的DLL是供VB、 PB、Delphi用户使用的,那么会产生一个小麻烦。因为VC++对于__declspec(dllexport)声明的函数会进行名称转换,如下面的函数:
__declspec(dllexport) int __stdcall IsWinNT()
会转换为IsWinNT@0,这样你在VB中必须这样声明:
Declare Function IsWinNT Lib "my.dll" Alias "IsWinNT@0" () As Long
@的后面的数由于参数类型不同而可能不同。这显然不太方便。所以如果要想避免这种转换,就要使用.def文件方式。
EXPORTS后面的数可以不给,系统会自动分配一个数。对于VB、PB、Delphi用户,通常使用按名称进行调用的方式,这个数关系不大,但是对于使用.lib链接的VC程序来说,不是按名称进行调用,而是按照这个数进行调用的,所以最好给出。
== == == ==
针对最简单的Dll,Win32 Application的方式稍有不同,定义导出函数接口的方法有两种:
1.使用__declspce宏
extern "C" __declspec(dllexport) void display(void);
extern "C" __declspec(dllexport) void test(int aa);
这里的extern "C" 表示我们要按照C语言的方式编译该函数,防止在C++工程中编译出现函数名错误,因为C中没有重载而C++中允许重载,所以C++中函数编译后会出现display@1的形式;让编译器以C语言的编译方式编译可以保证C可以调用C++的动态链接库。__declspec(dllexport)表示下来的函数是dll的导出函数接口。没有导出的接口是不可使用的,这里和静态lib库有所区别,静态lib库中的所有函数、宏定义等都是可以使用的。
2.使用def文件,该文件的功能类似于__declspec(dllexport)的功能。
== == == ==
使用lib pexports 工具导出导入库:
1 pexports libusp_BPM22.dll > libusp_BPM22.def 2 lib.exe /machine:i386 /def:libusp_BPM22.def /out:libusp_bpm22.lib
pexports 是msys 提供的工具 lib 是vs 提供的工具
** 到此,已经得到dll 和对应的导入库 .lib 文件,可以提供给 vs 使用。
参见博文:
GCC编译过程与动态链接库和静态链接库 - 三年一梦 - 博客园