查看原文
其他

手把手教你在Windows下编译、使用开源库

ZhengNL 嵌入式大杂烩 2022-09-10

点击上方「嵌入式大杂烩」,选择「置顶公众号」第一时间查看嵌入式笔记!

一、前言

大家好,我是ZhengN。

最近工作中需要把项目嵌入式Linux平台代码移到Windows上做仿真模拟,需要解决三个问题:

  • 搭建工程。
  • 动态库替换为Windows的。
  • 替换掉一些平台相关的代码。

搭建工程上一篇已经分享了:实用 | 使用Cmake快速生成visual studio工程

这篇我们来看看怎么在Windows上编译动态库。我们的项目中用到了几个开源库,下面通过实例来演示怎么编译得到相应的动态库。

二、静态、动态链接?

在实例演示之前,有必要先简单了解一下静态、动态链接,因为有些初学的小伙伴可能不太了解。

编译链接过程如:


1、什么是静态链接?

静态链接是由链接器在链接时将库的内容加入到可执行程序中的做法。

链接器是一个独立程序,将一个或多个库或目标文件(先前由编译器或汇编器生成)链接到一块生成可执行程序。

这里的库指的是静态链接库,Windows下以.lib为后缀,Linux下以.a为后缀。

2、什么是动态链接?

动态链接(Dynamic Linking),把链接这个过程推迟到了运行时再进行,在可执行文件装载时或运行时,由操作系统的装载程序加载库。

这里的库指的是动态链接库,Windows下以.dll为后缀,Linux下以.so为后缀。

需要注意的是,在Windows下的动态库也会提供两个文件:.lib文件与.dll文件。但这里的.lib文件叫做导入库,是由.dll文件生成的。

导入库包含被DLL导出的函数和变量的符号名,DLL包含实际的函数和数据。在编译链接可执行文件时,只需要链接导入库,DLL中的函数代码和数据并不复制到可执行文件中,在运行的时候,再去加载DLL,访问DLL中导出的函数。

3、静态链接与动态链接的优缺点?

(1)静态链接的优缺点:

优点:

  • 代码装载速度快,执行速度略比动态链接库快;
  • 只需保证在开发者的计算机中有正确的.lib文件,在以二进制形式发布程序时不需考虑在用户的计算机上.lib文件是否存在及版本问题。

缺点:

  • 使用静态链接生成的可执行文件体积较大,包含相同的公共代码,造成浪费。

(2)动态链接的优缺点:

优点:

  • 生成的可执行文件较静态链接生成的可执行文件小;
  • 适用于大规模的软件开发,使开发过程独立、耦合度小,便于不同开发者和开发组织之间进行开发和测试;
  • 不同编程语言编写的程序只要按照函数调用约定就可以调用同一个DLL函数;
  • DLL文件与EXE文件独立,只要输出接口不变(即名称、参数、返回值类型和调用约定不变),更换DLL文件不会对EXE文件造成任何影响,因而极大地提高了可维护性和可扩展性;

缺点:

  • 使用动态链接库的应用程序不是自完备的,它依赖的DLL模块也要存在,如果使用载入时动态链接,程序启动时发现DLL不存在,系统将终止程序并给出错误信息;
  • 速度比静态链接慢;

4、动态链接动态链接优缺点类比

我们可以把静态链接与动态链接做一个这样子的比喻:把链接过程看做我们平时学习时做笔记的过程

我们平时学习时准备一本笔记本专门记录我们的学习笔记,比如在某本书的某一页上看到一个很好很有用的知识,这时候我们有两种方法记录在我们的笔记本上。

一种是直接把那一页的内容全部抄写一遍到笔记本上(静态链接);另一种是我们在笔记本上做个简单的记录(动态链接),比如写上:xxx知识点在《xxx》的xxx页。

从这两种方法中我们可以很清楚地知道两种方式的特点。第一种方式的优点就是我们在复习的时候就很方便,不用翻阅其它书籍了,但是缺点也很明显,就是占用笔记本的空间很多,这种方法很快就把我们的笔记本给写满了。

第二种方式的优点就是很省空间,缺点就是每当我们复习的时候,手头上必须备着相关的参考书籍,比如我们去教室复习的时候,就得背着一大摞书去复习,这样我们复习的效率可能就没有那么高了。

这对应到我们的动态链接与静态链接上是不是就很好理解了。

三、编译、使用开源库

下面以实例来演示Windows在下编译开源库,以编译开源库nanomsg为例。

关于nanomsg的文章:

实用 | 一个高性能通信库的简单使用分享

nanomsg下载链接:

https://github.com/gaobaoru/nanomsg/

1、编译nanomsg的动态库

一般开源库都会用CMakeLists.txt来管理工程,找到库的CMakeLists.txt文件所在路径,如:


这个路径下面会用到。需要注意的是,这个CMakeLists.txt不一定在根目录下,有些库会专门建一个文件夹来存放CMakeLists.txt。

在nanomsg根目录新建一个文件夹存储我们编译得到的库,如nanomsg_x64_lib


使用cmake-gui生成nanomsg的vs2019工程:


如果Configure这一步顺利的话,会出现Configuring done:


可能会出现一些警告或错误,不重要的警告我们就先不用管,如果有错误的话根据错误提示进行解决。

生成动态库还是静态库,可以进行选择:


然后点击Generate就生成VS工程:


这时候可以看到我们的nanomsg_x64_lib文件夹下有生成VS工程文件了:


可以双击打开nanomsg.sln,也可以点击cmake-gui的Open Project打开工程:


nanomsg解决方案中有58个项目,因为包含有一些例子之类的。我们只用到nanomsg项目,把这个项目设置为启动项目:


按快捷键Ctrl+B生成nanomsg:


没问题的话就可以看到编译生成nanomsg.lib与nanomsg.dll了。

2、动态库使用验证

上一步编译生成了nanomsg动态库,这一节我们来一起使用验证一下。

验证代码我们拿实用 | 一个高性能通信库的简单使用分享这篇文章的代码来修改。

nanomsg可用于多线程、多进程、多机通信。nanomsg是一个socket library,所以其应用接口与标准的socket接口差不多,只是多了前缀nn_,如nn_socket、nn_close、nn_send、nn_recv等。

关于socket可查阅往期笔记:

【socket笔记】TCP、UDP通信总结

下面演示进程间通信的client-server的例子,以下测试代码主要实现的是client-server进行收发测试。

nanomsg_server.c:

// 微信公众号:嵌入式大杂烩
// 作者:ZhengN
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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!\r\n");
  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: %s\r\n", buf);
   if (nn_send(server_sock, buf, sizeof(buf), 0) < 0)
   {
    printf("send failed!\r\n");
    nn_close(server_sock);
    exit(EXIT_FAILURE);
   }
  }
 }
 nn_close(server_sock);
 
 return 0;
}

在VS中,引入导入库有两种方式,一种方式是在工程属性设置中设置;另一种方式是使用#pragma comment的方式引入。这里我们用的是第二种。我们的nanomsg_server工程下有:


编译没问题,运行会出错:


找不到nanomsg动态库。我们把nanomsg.dll放入到与.exe文件同目录即可:


再次运行没问题:


nanomsg_client.c:

// 微信公众号:嵌入式大杂烩
// 作者:ZhengN
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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!\r\n");
  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("send failed!\r\n");
   nn_close(client_sock);
  }
        memset(buf, 0, BUF_LEN);   

  if (nn_recv(client_sock, buf, sizeof(buf), 0) > 0
  {
   printf("recieve server msg: %s\r\n", buf);
  }
        memset(buf, 0, BUF_LEN);   
 }
 nn_close(client_sock);
 
 return 0;
}

nanomsg_client代码及注意事项与nanomsg_server类似,这里不再说明。

运行验证:


以上就是本次的分享,如有错误,欢迎指出,谢谢!

原创不易,码字不易,如果文章对你有帮助,麻烦帮忙点赞/在看/转发,谢谢!

四、资源下载

本篇笔记用到的资源、包括代码例子工程可以分享给大家,在本公众号后台回复关键词:制作动态库,即可获取。

五、温馨提示

由于微信公众号近期改变了推送规则,如果您想经常看到我们的文章,可以在每次阅读后,在页面下方点一个「赞」或「在看」,这样每次推送的文章才会第一时间出现在您的订阅列表里。

猜你喜欢:

实例分析静态链接与动态链接(Linux)

分享一些可以快速入门的嵌入式相关教程

2020年精选原创笔记汇总

在公众号聊天界面回复1024,可获取嵌入式资源;回复 ,可查看文章汇总。

文章都看完了不点个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存