C++ REST SDK (cpprestsdk)编译ASIO版本过程

C++ REST SDK (cpprestsdk)编译ASIO版本过程

1. 下载源码

使用git命令下载cpprest代码:

1
git clone -b v2.10.12 https://github.com/microsoft/cpprestsdk.git

2. 修改下载的源码

2.1 修复CMakeLists文件Bug

cpprestsdk的2.10.12版本的CMakeLists是有bug的,asio异步所需要的threadpool.cpp文件只有不排除websocket库的情况下才会链接到项目。显然目前项目是不需要websocket的,所以得强制让threadpool链接到项目里去,否则报无法解析的外部符号。

需要根据GitHub上该开源库的pull request修改:

  • 修改 Release/src/CmakeLists.txt 文件
  • 修改 Release/src/pplx/threadpool.cpp 文件

参考链接:https://github.com/microsoft/cpprestsdk/pull/1466/files

2.2 修改警告设置

Release下的CMakeLists文件的第18行,默认开启将警告视为报错,cmake不会报错,但make的时候会将所有的warning都会作为错误抛出,需要将ON改为OFF。

1
2
3
4
# 原代码
set(WERROR ON CACHE BOOL "Treat Warnings as Errors.")
# 修改为
set(WERROR OFF CACHE BOOL "Treat Warnings as Errors.")

或者可以在cmake命令中将该宏设置为OFF:-DWERROR=OFF

参考链接:https://github.com/microsoft/cpprestsdk/issues/1290

3. 编写cmake命令

3.1 Windows

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
"D:\software\CMake\bin\cmake.exe" ^
-DCMAKE_BUILD_TYPE=Debug ^
-G"Visual Studio 15 2017 Win64" ^
-DOPENSSL_ROOT_DIR="D:/DevThirdpartyLib_2017/Openssl/openssl-1.1.1g/" ^
-DOPENSSL_LIBRARIES="D:/DevThirdpartyLib_2017/Openssl/openssl-1.1.1g/lib64" ^
-DOPENSSL_SSL_LIBRARY="D:/DevThirdpartyLib_2017/Openssl/openssl-1.1.1g/lib64/libssl.lib" ^
-DOPENSSL_CRYPTO_LIBRARY="D:/DevThirdpartyLib_2017/Openssl/openssl-1.1.1g/lib64/libcrypto.lib" ^
-DOPENSSL_INCLUDE_DIR="D:/DevThirdpartyLib_2017/Openssl/openssl-1.1.1g/include" ^
-DZLIB_INCLUDE_DIR="D:/DevThirdpartyLib_2017/Zlib/zlib_1_2_11/include" ^
-DZLIB_LIBRARY="D:/DevThirdpartyLib_2017/Zlib/zlib_1_2_11/lib64/zlibd1.lib" ^
-DCPPREST_EXCLUDE_WEBSOCKETS:BOOL=ON ^
-DBoost_INCLUDE_DIRS="D:/DevThirdpartyLib_2017/boost/boost_1_68" ^
-DBOOST_LIBRARYDIR="D:/DevThirdpartyLib_2017/boost/boost_1_68/lib/x64" ^
-DBOOST_ROOT="D:/DevThirdpartyLib_2017/boost/boost_1_68" ^
-DBoost_SYSTEM_LIBRARY_DEBUG="D:/DevThirdpartyLib_2017/boost/boost_1_68/lib/x64/libboost_system-vc141-mt-gd-x64-1_68.lib" ^
-DBoost_DATE_TIME_LIBRARY_DEBUG="D:/DevThirdpartyLib_2017/boost/boost_1_68/lib/x64/libboost_date_time-vc141-mt-gd-x64-1_68.lib" ^
-DBoost_REGEX_LIBRARY_DEBUG="D:/DevThirdpartyLib_2017/boost/boost_1_68/lib/x64/libboost_regex-vc141-mt-gd-x64-1_68.lib" ^
-DCPPREST_HTTP_CLIENT_IMPL:STRING="asio" ^
-DCPPREST_HTTP_LISTENER_IMPL:STRING="asio" ^
-DBUILD_TESTS:BOOL=OFF ^
-DBUILD_SAMPLES:BOOL=OFF

参数说明:

  • D:\software\CMake\bin\cmake.exe 替换为实际的cmake安装路径
  • -DCMAKE_BUILD_TYPEWin64 根据所需Debug还是Release替换
  • 在Windows上指定boost的根目录路径没生效,可能是由于boost的lib命名过于复杂,所以直接指定了所需要的库
  • -DCPPREST_EXCLUDE_WEBSOCKETS:BOOL=ON 这个宏是为了排除websocket模块
  • -DCPPREST_HTTP_CLIENT_IMPL:STRING="asio" -DCPPREST_HTTP_LISTENER_IMPL:STRING="asio" 是为了让cmake将cpprest的请求和监听底层实现指定为使用boost.asio
  • -DBUILD_TESTS:BOOL=OFF -DBUILD_SAMPLES:BOOL=OFF 不要生成不必要的sample项目解决方案

注意: 生成的sln的配置可能还不完善,一些库的路径可能是不对的,有问题的还需要配置一下。

3.2 Linux

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
cmake \
-DCMAKE_INSTALL_PREFIX=/root/oqs/cpprestsdk_build/cpprestsdk \
-DCMAKE_BUILD_TYPE=Release \
-DCPPREST_EXCLUDE_WEBSOCKETS=ON \
-DZLIB_INCLUDE_DIR=/root/oqs/cpprestsdk_build/zlib/include \
-DZLIB_LIBRARY=/root/oqs/cpprestsdk_build/zlib/lib/libz.so \
-DZLIB_ROOT_DIR=/root/oqs/cpprestsdk_build/zlib/ \
-DOPENSSL_ROOT_DIR=/root/oqs/cpprestsdk_build/openssl/ \
-DOPENSSL_INCLUDE_DIR=/root/oqs/cpprestsdk_build/openssl/include \
-DBOOST_LIBRARYDIR=/root/oqs/cpprestsdk_build/boost/lib \
-DBOOST_ROOT=/root/oqs/cpprestsdk_build/boost/include \
-DCPPREST_HTTP_CLIENT_IMPL:STRING="asio" \
-DCPPREST_HTTP_LISTENER_IMPL:STRING="asio" \
-DBUILD_TESTS:BOOL=OFF \
-DBUILD_SAMPLES:BOOL=OFF

宏的作用跟Windows上的大差不差。

4. 编译

4.1 Windows

直接用Visual Studio

4.2 Linux

使用make命令或者 make -j8(多线程编译)

5. 使用

5.1 Linux和Windows都需要修改的地方

CPPRest配置:

cpprest的ssl_context函数是根据这个宏决定是否打开的,在Windows上使用asio版本的cpprest,需要在项目上根据需要在代码或者预处理器上加上这两个宏:

1
2
CPPREST_FORCE_HTTP_CLIENT_ASIO
CPPREST_FORCE_HTTP_LISTENER_ASIO

gSOAP配置:

1
2
WITH_IPV6 
WITH_NO_IPV6_V6ONLY

5.2 Windows特定配置

在Windows上使用boost,由于boost自身有文件引用了winsock.h头文件,且我们的项目中stdafx.h中可能已经通过某些宏或者直接添加了该头文件,导致编译过程会报:

1
WinSock.h has already been included

解决方案:

  1. 将stdafx.h中引入该头文件的代码注释掉
  2. 在项目方案加上该宏:WIN32_LEAN_AND_MEAN

参考链接:https://stackoverflow.com/questions/30731173/error-winsock-h-has-already-been-included-boost-windows-qt

IPv6地址格式: IPv6地址注意要带上中括号 []

5.3 Linux特定配置

IPv6地址格式: 在Linux上,IPv6地址是不需要添加中括号的,否则会解析失败。

双栈支持配置:

在Linux上使用PF_UNSPEC在getaddrinfo后会得到INET(IPv4),这不是期望的结果。期望的效果是得到PF_INET6+WITH_NO_IPV6_V6ONLY(也就是WITH_IPV6 WITH_NO_IPV6_V6ONLY)从而达到双栈的效果。

原因是PF_UNSPEC在Linux上通过getaddrinfo获取协议族过程中,找到协议后(无论是IPv4还是IPv6)就直接返回了。

修改方法:

stdsoap.cpp 的第5714行将:

1
hints.ai_family = PF_UNSPEC

改为:

1
hints.ai_family = PF_INET6

注意: 在Windows上同样修改也没发现同样的问题,所以应该可以不区分平台。