一、简介
大家好,我叫郑N。
最近的工作中,需要将项目的嵌入式Linux平台代码搬到Windows上进行仿真。 需要解决三个问题:
之前搭建项目的文章已经分享过:实用| 使用Cmake快速生成Visual Studio项目
在这篇文章中,我们来看看如何在Windows上编译动态库。 我们的项目中使用了几个开源库。 下面通过例子来演示如何编译并获取相应的动态库。
在实际演示之前编译开源库源码命令,有必要简单了解一下静态链接和动态链接,因为有些初学者可能不太理解。
编译和链接过程如下:
1.什么是静态链接?
静态链接是链接器在链接时将库的内容添加到可执行程序的做法。
链接器是一种独立的程序,它将一个或多个库或目标文件(先前由编译器或汇编器生成)链接成一个片段以生成可执行程序。
这里的库指的是静态链接库编译开源库源码命令,Windows下以.lib为后缀,Linux下以.a为后缀。
2.什么是动态链接?
动态链接将链接过程推迟到运行时。 当可执行文件被加载或运行时,操作系统加载器加载库。
这里的库指的是动态链接库,Windows下后缀为.dll,Linux下后缀为.so。
需要注意的是,Windows下的动态库还提供了两个文件:.lib文件和.dll文件。 但这里的.lib文件称为导出库,是由.dll文件生成的。
导出的库包含DLL导入的函数和变量的符号名称,DLL包含实际的函数和数据。 编译和链接可执行文件时,只需链接导出的库即可。 DLL中的函数代码和数据不会复制到可执行文件中。 运行时,加载DLL并访问DLL中导入的函数。
3、静态链接和动态链接有何异同?
(1)静态链接的异同:
优势:
缺点:
(2)动态链接的异同:
优势:
缺点:
4、动态链接与动态链接的异同类比
我们可以把静态链接和动态链接做个类比:把链接过程想象成我们平时学习时做笔记的过程。
我们平时学习的时候,都会准备一台电脑来记录我们的学习笔记。 例如,当我们在一本书的某一页上看到一条非常有用的知识时,我们有两种方式将其记录在我们的计算机上。
一是直接将该页面的所有内容复制到电脑上(静态链接); 另一种是在电脑上做一个简单的记录(动态链接),例如写:xxx知识点在“xxx”的xxx页面。
从这两种方法中,我们可以清楚地了解两种形式的特点。 第一种方法的好处是我们在备考的时候非常方便,不需要看其他的书。 缺点也很明显,那就是占用电脑很大的空间。 这些方法很快就填满了我们的计算机。
第二种方法的优点是节省空间。 缺点是,每当我们准备考试时,手头必须有相关的参考书。 例如,当我们去宿舍准备考试时,我们必须背着一大摞书来准备考试。 这样一来,我们备考的效率可能就不会那么高了。
这对应了我们的动态链接和静态链接。 是不是很容易理解呢?
3.编译开源库
下面以开源库nanomsg的编译为例,演示如何在Windows下编译开源库。
关于nanomsg的文章:
实用| 高性能通讯库的简单使用分享
Nanomsg下载链接:
1.编译nanomsg动态库
通常开源库会使用CMakeLists.txt来管理项目。 找到库的CMakeLists.txt文件所在路径,如:
下面将使用该路径。 需要注意的是,这个CMakeLists.txt不一定在根目录下。 有些库会创建一个特殊的文件夹来存储CMakeLists.txt。
在nanomsg根目录下新建一个文件夹,用来存放我们编译的库,如nanomsg_x64_lib:
使用cmake-gui生成nanomsg vs2019项目:
如果配置步骤顺利的话,将会出现Configuringdone:
可能会出现一些警告或错误。 我们暂时忽略不重要的警告。 如果出现错误,请按照错误提示进行解决。
可以选择生成动态库还是静态库:
然后点击Generate生成VS项目:
这时可以看到我们的nanomsg_x64_lib文件夹下生成了VS项目文件:
可以双击打开nanomsg.sln,也可以点击cmake-gui的OpenProject打开项目:
nanomsg解决方案中有58个项目,因为它包含一些反例之类的。 我们只使用nanomsg项目,并将该项目设置为启动项目:
按快捷键Ctrl+B生成nanomsg:
如果没有问题,可以看到nanomsg.lib和nanomsg.dll被编译生成。
2.动态库使用验证
上一步编译生成了nanomsg动态库。 本节我们就结合使用来验证一下。
为了验证代码,我们使用 Practical | 一个简单的使用高性能通信库来分享本文的代码来改一下。
nanomsg 可用于多线程、多进程、多机通信。 nanomsg是一个socket库,所以它的应用socket与标准socket套接字类似,只不过多了个nn_前缀,如nn_socket、nn_close、nn_send、nn_recv等。关于socket,可以查看之前的注释:
TCP和UDP通信总结
下面演示一个用于进程间通信的客户端-服务器的反例。 下面的测试代码主要实现客户端-服务器端的发送和接收测试。
nanomsg_server.c:
#include
#include
#include
#include "pair.h"
#include "bus.h"
#include "nn.h"
#pragma comment (lib,"nanomsg.lib") // 链接导入库nanomsg.lib
#define BUF_LEN 100
char *url = "tcp://127.0.0.1:2021";
int main(void)
{
int server_sock = 0;
char buf[BUF_LEN] = {0};
if (server_sock = nn_socket (AF_SP, NN_PAIR) < 0)
{
printf("create server socket failed!n");
return -1;
}
if (nn_bind(server_sock, url) < 0)
{
printf("bind server sock failed!rn");
nn_close(server_sock);
return -1;
}
printf("server init success!n");
while (1)
{
if (nn_recv(server_sock, buf, sizeof(buf), 0) < 0)
{
printf("recv failed!n");
nn_close(server_sock);
exit(EXIT_FAILURE);
}
else
{
printf("recieve client msg: %srn", buf);
if (nn_send(server_sock, buf, sizeof(buf), 0) < 0)
{
printf("send failed!rn");
nn_close(server_sock);
exit(EXIT_FAILURE);
}
}
}
nn_close(server_sock);
return 0;
}
在VS中,有两种引入导出库的方式。 一种方法是在项目属性设置中设置; 另一种方法是使用#pragmacomment形式来引入它。 这里我们使用第二个。 我们的 nanomsg_server 项目包括:
编译没有问题,但是运行时出现错误:
找不到nanomsg动态库。 我们可以将nanomsg.dll加载到与.exe文件相同的目录中:
它再次运行,没有问题:
nanomsg_client.c:
#include
#include
#include
#include "pair.h"
#include "bus.h"
#include "nn.h"
#pragma comment (lib,"nanomsg.lib") // 链接导入库nanomsg.lib
#define BUF_LEN 100
char *url = "tcp://127.0.0.1:2021";
int main(void)
{
int client_sock = 0;
char buf[BUF_LEN] = {0};
if (client_sock = nn_socket (AF_SP, NN_PAIR) < 0)
{
printf("create server socket failed!n");
return -1;
}
if (nn_connect(client_sock, url) < 0)
{
printf("connect server sock failed!rn");
nn_close(client_sock);
return -1;
}
printf("client init success!n");
while (1)
{
scanf_s("%s", buf, BUF_LEN);
if (nn_send(client_sock, buf, sizeof(buf), 0) 0)
{
printf("recieve server msg: %srn", buf);
}
memset(buf, 0, BUF_LEN);
}
nn_close(client_sock);
return 0;
}
nanomsg_client代码和注意事项与nanomsg_server类似,这里不再解释。
运行验证: