伸手党可以到?zmqpp库windows编译结果-C++文档类资源-CSDN下载?去下载
zmqpp 是 libzmq 的高级 C++ 封装,不但提供了针对 libzmq C 接口的 C++ 封装,还提供了一些附加功能(Reactor模式, Actor模式 和 ZAP支持),详细见 zmqpp 文档 zmqpp: Main Page。在 ubuntu linux发行版上,可以直接用 apt-get 来安装使用,非常方便,但是在 windows 上如何编译使用却资料甚少。因为没有找到 zmqpp 的 windows 预编译发行版,所以只能自己用源码编译。这篇文章将一步一步实现在 windows 10 操作系统下用 visual studio 2019 来编译 zmqpp。
1. 下载 cmake windows 版
我们需要用到 cmake 来进行编译,Download | CMake?处可以找到最新的发行版(Latest Release),目前的最新发行版是 3.23.2,下载?Windows x64 Installer 文件?cmake-3.23.2-windows-x86_64.msi?并且执行安装。
2. 下载 libzmq 的 windows 预编译版
到地址?Releases · zeromq/libzmq · GitHub?下载?libzmq-v142-x64-4_3_4.zip?文件并且解压缩到自己喜欢的地方。
还有为其它版本 visual studio 准备的预编译版,命名中 libzmq-vXXX-x64-4_3_4.zip 中分别如下对应:
visual studio 2019 对应 v142
visual studio 2017 对应 v141
visual studio 2015 对应 v140
3. 下载 zmqpp 源码
Releases · zeromq/zmqpp · GitHub?链接内下载最新的发布版本,目前是 4.2.0 版,Source code?(zip),下载后解压缩到自己喜欢的地方,我放在 D:\zmqpp-4.2.0 。
4. 用 cmake 生成 visual studio 解决方案
以 zmqpp 源码位置在?D:\zmqpp-4.2.0 为例,创建目录 D:\zmqpp-4.2.0\bin\v142\x64 作为生成目标路径。
开始菜单中去启动 CMake(cmake-gui),如图填写源码路径和生成目标路径,点击 configure

在下图弹出的窗口中指定生成器版本为 Visual Studio 16 2019,生成平台为 x64,点击 Finish。

这时,可以查看到 cmake 的配置结果,黄色框中显示 NOTFOUND 的 3 个东西需要手工指定到之前第 2 步下载的 libzmq windows 预编译版的位置:

手工指定 libzmq windows 预编译版的位置之后的截图,注意黄框内容:

我想将 zmqpp 的例子和测试都编译出来,所以将 ZMQPP_BUILD_CLIENT, ZMQPP_BUILD_EXAMPLES, ZMQPP_BUILD_TESTS 也都打上了勾,如果不打这些勾,等解决方案生成之后,在 visual studio 中是看不到 client、?examples、 tests 这 3 个项目的
手工指定之后需要再次点击 Configure 按钮来更新配置,更新配置之后出现报错,如图:

?报错原因是因为我勾选了编译样例,而编译样例需要 Boost 库,需要下载安装 Boost 库。
5. 下载安装 Boost 库
下载地址?Boost C++ Libraries - Browse /boost-binaries at SourceForge.net?,当前最新版是 1.79.0,进到 1.79.0 目录,同样也有针对不同 visual studio 版本的对应版本,我们需要的是 msvc-14.2 版。
visual studio 2019 对应 msvc-14.2
visual studio 2017 对应 msvc-14.1
visual studio 2015 对应 msvc-14.0
下载?boost_1_79_0-msvc-14.2-64.exe?并且运行安装到自己指定的目录中去,我是安装在 D:\local\boost_1_79_0 目录。
6. 继续 cmake 项目配置,指定 boost 目录
指定 Boost_INCLUDE_DIR 路径到?D:\local\boost_1_79_0 再点击 Configure, 如图:

最终的输出结果如下图,红字部分的告警可以忽略,点击 Generate 以生成 visual studio 2019 的解决方案 sln 文件

点击 Generate 之后,在我们指定的生成目标路径 D:\zmqpp-4.2.0\bin\v142\x64 中,会生成一个 visual studio 的解决方案文件 Project.sln
7. 打开解决方案,生成 zmqpp 项目
直接在生成目标路径?D:\zmqpp-4.2.0\bin\v142\x64 中打开 Project.sln,或者在 CMake 窗口中点击 Open Project 按钮,都可以打开 visual studio 2019。

?我们先试一下生成 zmqpp 库,右击 zmqpp 选取生成选项。

生成的结果是 成功 1 个,失败 1 个。上图红框内为失败原因,双击红框中两行的任何一行,打开源码 compatibility.hpp,其中第 132 行有错,原因是 SOCKET 没有定义,需要包含?winsock2.h?头文件。

?在这个文件的第 37 行插入一行?#include <winsock2.h> 保存后再次生成

?再次生成 zmqpp 项目仍旧有错,这次是下图这里的错误

?双击这 3 行中的任一行,打开源码 socket.cpp 中 344 行,显示 std::min 有问题。查资料得,因为 windows.h 包含的 windef.h 中有宏定义 min 和 max,导致此处 min 被展开宏。

?查到一个简单的方法,使用项目范围的?/D "NOMINMAX" 选项就可以避免这个干扰。
右击打开 zmqpp 项目属性,在配置属性>C/C++>命令行页面中的其它选项内,加上??/D "NOMINMAX", 如下图:
再次生成 zmqpp 项目,编译成功,已经生成 zmqpp 库的 dll 文件和 lib 文件。如下图所示:

8. 生成 zmqpp-client
这是基于 libzmqpp 编写的命令行客户端程序,可以用来测试或者桥接 zmq 连接。具体用法请见?https://github.com/zeromq/zmqpp/blob/develop/README.md#usage
右击 zmqpp-client 选取生成菜单。此项目顺利生成。

?打开 cmd 窗口运行 zmqpp-client 报错找不到 libzmq-v142-mt-4_3_4.dll 文件

到第 2 步下载的 libzmq 的 windows 预编译版目录中将?libzmq-v142-mt-4_3_4.dll 文件复制到 zmqpp-client.exe 相同目录内,再次运行 zmqpp-client,又报错找不到 libsodium.dll 文件

仍旧是到第 2 步下载的 libzmq 的 windows 预编译版目录中将 libsodium.dll 文件复制到 zmqpp-client.exe 相同目录内

?再次运行 zmqpp-client,又报错,这次是 “zmqpp-client.exe” 已停止工作 错误。再查资料!stack over flow on windows x64 · Issue #2876 · zeromq/libzmq · GitHub?这里有个人报告了类似问题,虽然不是 zmqpp-client 的问题,而是 libzmq 中 inproc_thr.exe 的问题,我感觉应该是相同的问题,按照下面这个答案所说,在 libzmq/INSTALL 说明文件中已经提醒,要将栈的大小从默认的 1MB 增加到 2MB。

我们干脆增加到 40MB,右击 zmqpp-client 项目,找到 链接器 > 系统 > 堆栈保留大小,设置这个项为 41943040,再重新生成 zmqpp-client 项目

?再次运行 zmqpp-client ,发现它终于能够正常运行了!

9. 编译 example
一共有 7 个例子,我们逐个来编译
9.1 编译 zmqpp-example-grasslands
编译这个例子没有遇到问题,直接成功了,真是难得!

?运行也是正常。

9.2 编译 zmqpp-example-ironhouse
这个例子编译失败了,报了一堆 LNK2019 错误:

应该是 zmqpp 库的代码中有关 auth 部分的符号都没有导出,需要修改源代码。因为这个例子是涉及消息加密的,可能用的人比较少,开源社区里没有人提这个问题,也没有人修复。
下载依赖分析工具?Dependency Walker (depends.exe) Home Page?对我们在第 7 步生成 zmqpp 时产生的 zmqpp.dll 文件进行分析,如下图:

并没有找到 7 个 LNK2019 错误所指的符号,zmqpp::auth::auth、zmqpp::auth::~auth、zmqpp::auth::allow、zmqpp::auth::configure_domain、zmqpp::auth::configure_curve、zmqpp::auth::set_verbose、zmqpp::curve::generate_keypair 等,这个证实了之前猜想,这些符号并没有导出到 zmqpp.dll。所以问题出在 zmqpp 项目中,需要找个办法使 zmqpp 库编译时将 auth 类的相关函数导出到 zmqpp.dll 中。
打开 zmqpp 项目的 auth.hpp 文件,如下图在类定义中添加?ZMQPP_EXPORT 宏
打开 curve.hpp, 在 keypair generate_keypair() 前加上?ZMQPP_EXPORT 宏

再打开 curve.cpp?(注意这次是cpp文件不是hpp)文件,在 keypair 前添加 ZMQPP_EXPORT 宏

重新编译 zmqpp 项目,然后再重新编译?zmqpp-example-ironhouse 项目,这次编译成功了。

?运行 zmqpp-example-ironhouse 发现退出程序时报错?Assertion failed: Successful WSASTARTUP not yet performed [10093] (C:\projects\libzmq\src\signaler.cpp:190)?如下:

根据资料?c++ - ZeroMQ context singleton, provided in a DLL, crashes when program exits (VS2010 win7 x64 zmq 4.0x) - Stack Overflow
所说,这是个 windows 特定问题,解决办法就是一定要在程序开始时调用一次?WSAStartup(),结束前调用一次?WSAShutdown()。
没有找到特定于 zmqpp 库的资料,实际上这个问题源头是 libzmq,根据?[4.1.3] Assertion failed: Successful WSASTARTUP not yet performed (..\..\..\..\src\signaler.cpp:181) · Issue #1708 · zeromq/libzmq · GitHub 的说法,如果是在 DLL 内创建 context(现在遇到的情况恰好就是 zmqpp 在 zmqpp.dll 中调用 zmq_ctx_new() 创建了 zmq::ctx_t),libzmq 程序在 windows 上退出时就会报这个错误,而在 main 中创建再传递给程序其它部分就不会报这个错误,Assertion failed: Successful WSASTARTUP not yet performed (..\..\..\..\src\signaler.cpp:192) · Issue #1788 · zeromq/czmq · GitHub?内 czmq 用户解释的原因是
It's a Windows problem in CZMQ, and it's because Windows lacks a usable way to do the equivalent of atexit() when built as DLL.
You need to manually call zsys_shutdown() before your Windows program exits.
但我们用的不是 czmq,没有 zsys_shutdown() 可以用。
这个是 windows 操作系统底层的问题,只影响程序退出部分的功能,就不管它了。
9.3 编译 zmqpp-example-ironhouse2
经过 9.2 节的修改之后,此例子程序可以顺利编译成功。也可以运行,只是退出时和 9.2 一样,也会有报错?Assertion failed: Successful WSASTARTUP not yet performed [10093] (C:\projects\libzmq\src\signaler.cpp:190)??

9.4 生成 zmqpp-example-simple_client 和 zmqpp-example-simple_server
这两个例子都可以顺利生成。这两个程序是一对,client 发消息,server 收消息的。运行结果如下:

?和通常理解的客户服务器程序不同,zmq的客户端和服务器程序可以按任意顺序运行,而不是非得要先启动服务器再启动客户端的。
9.5 生成 zmqpp-example-strawhouse 和 zmqpp-example-woodhouse
情况与 9.3 和 9.2 相同,正常生成,可以运行,但程序退出时有报错。

10 结果
至此,已经得到 zmqpp.dll 和一些例子的编译结果,生成目录内容如下:

所有结果文件,包括 Release 版的,都已经打包在?zmqpp库windows编译结果-C++文档类资源-CSDN下载
其中的 zmqpp-static 库是没有修改过的,应该是不包含 auth 那几个符号的。
|