找回密码
 立即注册
首页 业界区 业界 CMake构建学习笔记20-iconv库的构建

CMake构建学习笔记20-iconv库的构建

驳嗦 昨天 19:50
1. 构建

iconv是一个用于在不同字符编码(如 UTF-8、GBK、ISO-8859-1 等)之间进行转换的开源库。笔者在《c++中utf8字符串和gbk字符串的转换》这篇文章中介绍过如何在Windows下实现utf8字符串和gbk字符串的转换,不过该实现是基于Win32 API的,在其他平台中是无法使用的。如果需要跨平台,那么就需要使用iconv这样的库来统一实现。
不过麻烦的是iconv是GNU/Linux项目提供的库,不提供CMake的构建方式,以及原生的MSCV的构建方式。在Windows下的构建官方推荐使用MSYS2来进行构建。不过MSYS2构建出来的成果不一定能与MSVC构建的成果二进制兼容,而在Windows下还是使用MSVC的情况比较多。所以这就有点僵住了,只能寻求第三方的帮助。
这里笔者的解决方案是直接使用vcpkg。vcpkg是微软开发的C/C++跨平台开源库管理工具,试用了一下,感觉确实比以前进步很多,如果不是像笔者一样有自己的需求,完全可以都使用vcpkg来安装依赖库。
通过以下指令下载并安装iconv:
  1. git clone https://github.com/microsoft/vcpkg
  2. cd vcpkg
  3. .\bootstrap-vcpkg.bat
  4. .\vcpkg install libiconv:x64-windows
复制代码
iconv就会安装在vcpkg的目录下,如下图所示:
1.png

iconv是个底层库,不需要其他依赖库,因此可以直接复制到笔者的仓库中使用,算是满足了笔者的需求。另外,不知道vcpkg的机制是什么,vcpkg确实也使用了cmake来构建,因为生成了cmake的配置文件,可以直接被CMake项目集成使用。最后,默认情况下vcpkg会检测环境内的VS,使用最高版本的VS来编译链接,构建的时候要保证与目标版本一致。
2. 示例

最后就直接给一个CMake项目调用刚才安装好的iconv库的示例吧。因为vcpkg在安装iconv的时候,也安装了相应的cmake的配置文件,所以可以直接在CMakeLists.txt集成,关键配置代码是:
  1. # 项目代码设置为utf-8编码
  2. if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
  3.     message(">> using Clang")
  4. elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
  5.     message(">> using GCC")
  6. elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
  7.     message(">> using Intel C++")
  8. elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
  9.     message(">> using Visual Studio C++")
  10.     add_compile_options("/utf-8")
  11. else()
  12.     message(">> unknow compiler.")
  13. endif()
  14. find_package(Iconv REQUIRED)
  15. # ...
  16. target_link_libraries(${PROJECT_NAME} PRIVATE Iconv::Iconv)
复制代码
注意,find_package要生效,需要保证CMake能够搜索到相应的库。如果是直接使用的vcpkg,那么需要将vcpkg集成到CMake搜索路径中:
  1. vcpkg integrate install
复制代码
如果是像笔者一样,是将iconv复制到自己仓库中使用,那么需要在CMake的内置变量CMAKE_PREFIX_PATH中增加自己的仓库路径(比如修改CMakePresets.json文件中CMAKE_PREFIX_PATH的配置)。
将utf8编码字符串转换成gbk字符串的代码示例如下:
  1. #include <iconv.h>
  2. using namespace std;
  3. int main() {
  4.   // 原始 UTF-8 字符串
  5.   const char *utf8_str = "你好,世界!";
  6.   printf("%s\n", utf8_str);
  7.   size_t in_bytes_left = strlen(utf8_str);
  8.   char in_buf[1024];
  9.   strcpy(in_buf, utf8_str);
  10.   char *in_ptr = in_buf;
  11.   // 输出缓冲区(GBK)
  12.   char out_buf[1024];
  13.   char *out_ptr = out_buf;
  14.   size_t out_bytes_left = sizeof(out_buf);
  15.   // 打开 iconv 转换器:从 UTF-8 转换到 GBK
  16.   iconv_t cd = iconv_open("GBK", "UTF-8");
  17.   if (cd == (iconv_t)-1) {
  18.     perror("iconv_open failed");
  19.     return 1;
  20.   }
  21.   // 执行转换
  22.   if (iconv(cd, &in_ptr, &in_bytes_left, &out_ptr, &out_bytes_left) ==
  23.       (size_t)(-1)) {
  24.     perror("iconv failed");
  25.     iconv_close(cd);
  26.     return 1;
  27.   }
  28.   // 关闭转换器
  29.   iconv_close(cd);
  30.   // 获取实际转换后的长度
  31.   size_t converted_len = sizeof(out_buf) - out_bytes_left;
  32.   // 直接写入二进制字节到 stdout(不经过 printf,防止转码)
  33.   fwrite(out_buf, 1, converted_len, stdout);
  34.   return 0;
  35. }
复制代码
运行结果如下所示:
  1. 浣犲ソ锛屼笘鐣岋紒
  2. 你好,世界!
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册