问题由来
前段时间实习,遇到了一个很有意思的现象,使用cmake的link_libraries()在Windows下调用动态库(win下的动态库为dll)时,会出现如下错误:
fatal error LNK1107: 文件无效或损坏
由于之前一直是在Linux下开发程序,用此方法调用Linux的动态库(Linux下的动态库为so)时,从未出现过此问题,所以做了一下探究。
探究过程
由于不能使用cmake的link_libraries()链接动态库,所以换成target_link_libraries()+绝对路径的方法链接,但是仍然会报相同的错误。但在换成link_directories()+target_link_libraries()+动态库名称时,发现cmake会提示找不到(动态库名称).lib。这就很奇怪,明明链接的文件夹下就只有一个动态库,而且叫(动态库名称).dll,怎么cmake会需要(动态库名称).lib,难道Windows下的cmake只能链接静态库?
探究结果
这里要先介绍一下Windows和Linux的动态库和静态库的区别:
在Windows下的动态库分为动态库本身.dll文件和动态库导入文件.lib,其中dll文件不参与编译参与运行,lib导入文件参与编译不参与运行,所以Windows下的cmake在想要调用dll动态库时,要链接dll动态库的导入文件.lib,而不是dll本身。Windows下的静态库则只有.lib。Linux的动态库和静态库则只有.os和.a。而Windows下的动态库的lib导入文件,需要在代码中加入__declspec(dlliexport)才可以生成,如下所示:
__declspec(dllexport) void HelloWorld();
示例工程
工程介绍
内容
1、hwlib为helloworld打印测试库,可以生成动态库和静态库,让下面的demo测试工程调用。
2、demo为调用hwlib库的测试工程,会生成基于动态库的可执行程序和基于静态库的可执行程序。
编译
1、hwlib
cd hwlib
mkdir build && cd build
cmake ..
cmake --build .
cmake --install .
会在C:\Program Files\下生成hwlib库文件夹,将其移动到demo目录下(demo目录已经包含hwlib库此步骤也可以忽略)。
2、demo
cd demo
mkdir build && cd build
cmake ..
cmake --build .
运行
编译后,在demo/build/下有两个可执行程序,main_static和main_shared,其功能都是在终端打印HelloWorld字符串,但是main_static可以直接执行,main_shared则需要依赖hwlib.dll动态库,如运行main_shared出现找不到动态库的错误,则可以将hwlib.dll放在和main_shared同一个文件夹下。