写点什么

基于 Flutter 实现 Windows 平台离线大模型对话应用实战

作者:轻口味
  • 2023-04-26
    北京
  • 本文字数:2886 字

    阅读完需:约 9 分钟

基于Flutter实现Windows平台离线大模型对话应用实战

1、背景

前面文章《基于 Flutter 实现跨平台离线大模型对话应用》中介绍了基于 Flutter 实现跨平台的离线模型对话应用,跑通了 Android、iOS、Mac 平台,在编译 Windows 平台时由于不熟悉 Windows 平台编译器,踩了一些坑,最终搞了一个晚上加一个上午成功搞定。

2、Windows 编译器介绍

传统的编译器通常分为三个部分,前端(frontEnd),优化器(Optimizer)和后端(backEnd)。在编译过程中:


  • 前端主要负责词法和语法分析,将源代码转化为抽象语法树;

  • 优化器则是在前端的基础上,对得到的中间代码进行优化,使代码更加高效;

  • 后端则是将已经优化的中间代码转化为针对各自平台的机器代码。


作为一个移动端开发,日常用到最多的 C++编译器是 GCC、Clang。


  • GCC(GNU Compiler Collection,GNU 编译器套装),是一套由 GNU 开发的编程语言编译器。GCC 原名为 GNU C 语言编译器,因为它原本只能处理 C 语言。GCC 快速演进,变得可处理 C++、Fortran、Pascal、Objective-C、Java 以及 Ada 等他语言。

  • Clang 是以 LLVM(Low Level Virtual Machine,底层虚拟机)为后端的一款高效易用,并且与 IDE 结合很好的编译前端。Clang 只支持 C,C++ 和 Objective-C 三种语言。


虽然 Windows 上也有 Cygwin、MinGW、TDM-GCC 等 GCC 移植版本,但我们还是选微软官方的 MSVC 系列编译器。它与 Visual Studio 集成发布,微软自己的编译器,VS 是一个基本完整的开发工具集,它包括了整个软件生命周期中所需要的大部分工具,如 UML 工具、代码管控工具、集成开发环境(IDE)等等。所写的目标代码适用于微软支持的所有平台,包括 Microsoft Windows、Windows Mobile、Windows CE、.NET Framework、.NET Compact Framework 和 Microsoft Silverlight 及 Windows Phone。

3、Windows 平台开发 Flutter 桌面应用

3.1 环境安装

Flutter 2.10 开始,对 Windows 的支持已进入 stable 渠道。要开发 Windows 应用除了安装 Flutter SDK,还需要安装微软提供的 Visual Studio22 或者是 Visual Studio 2022 生成工具。在安装时要选择”使用 C++的桌面开发“,它包含了所有默认组件(必要的 C++工具链和 Windows SDK 的头文件)。

3.2 配置 C++编译脚本

直接在 windows 目录下创建 CMakeLists.txt 文件,在 CMakeLists.txt 中直接添加编译信息:


cmake_minimum_required(VERSION 3.10)
# 项目名称set(PROJECT_NAME "libNativeAdd")project(${PROJECT_NAME} LANGUAGES CXX)
# 源文件add_library(${PROJECT_NAME} SHARED "./native_add.cpp")
# 动态库的输出目录set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<$<CONFIG:DEBUG>:Debug>$<$<CONFIG:RELEASE>:Release>")# 安装动态库的目标目录set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")# 安装动态库,到执行目录install(FILES "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${PROJECT_NAME}.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime)
复制代码


也可以添加子目录方式添加对应模块:


add_subdirectory("../libs/native_add" native_add)
复制代码

3.3 遇到问题

  1. 项目里面有几个.cpp文件还有一个.c文件,这样配置后运行flutter run,一直报错,提示连接 C 文件里的函数失败,查看了编译时中间文件,发现 C 文件没有被执行编译,最后发现是 CMakelist.txt 中指定了project(${PROJECT_NAME} LANGUAGES CXX)编译语言导致 C 文件没有执行编译,其他平台都没问题,Windows 上报错。

  2. 运行时 FFI 查找 C 函数时提示找不到,将编译出的 DLL 文件放到指定路径,通过指定路径加载也同样失败,而且 debug 查看,动态库已经成功加载,就是找不到函数。向外暴露的函数通过#define EXPORT_API __attribute__ ((visibility ("default")))定义的 EXPORT 修饰:EXPORT_API void* init(const char* path);,windows 编译时 EXPORT_API 修饰报错,以为这个修饰没有用,直接删除掉了,导致找不到函数。最后通过:


#ifdef WIN32#define EXPORT_API extern "C" __declspec(dllexport)#else#define EXPORT_API extern "C" __attribute__((visibility("default"))) __attribute__((used))#endif
复制代码


来支持不同平台接口。

3.4 应用打包

我们一般安装 windows 程序都提供了一个安装包,我们执行安装,然后释放资源和可执行文件,同时应用程序发布到微软商店前必须要打包。有效的格式是 .msix.msixbundle.msixupload.appx、 .appxbundle.appxupload 和 .xap。Flutter 提供了打包 msix 程序的工具。MSIX 是微软提供的新的 Windows 应用程序包格式,它提供了一种现代的打包格式和安装程序。这种格式既可以用于将应用程序发布到 Windows 上的 Microsoft Store,也可以直接分发应用程序安装程序。


Flutter 提供了 MSIX pub 打包方式。打包时需要配置.pfx 证书:


  1. 请下载 OpenSSL 工具包来生成证书。

  2. 进入 OpenSSL 的安装路径,例如C:\Program Files\ OpenSSL- win64 \bin。为方便使用我们设置一个环境变量,这样可以从任何地方访问 OpenSSL。

  3. 生成私钥:Openssl genrsa -out mykeyname.key 2048

  4. 使用私钥生成证书签名请求(CSR)文件:Openssl req -new -key mykeyname.key -out mycsrname.csr

  5. 使用私钥和 CSR 文件生成已签名的 CRT 文件:openssl x509 -in mycsrname.csr -out mycrtname.crt -req -signkey mykeyname.key -days 10000

  6. 使用私钥和 CRT 文件生成。pfx 文件:openssl pkcs12 -export -out CERTIFICATE.pfx -inkey mykeyname.key -in mycrtname.crt

  7. 在安装应用程序的机器上安装.pfx 证书,配置作为受信任的根证书颁发机构。


Flutter 可执行文件.exe可以在我们的项目build\windows\runner\<build mode>\下找到。除了.exe可执行文件,您还需要以下文件:


  • 统一目录上所有的.dll文件

  • data 目录

  • 拷贝依赖文件:msvcp140.dllvcruntime140.dllvcruntime140_1.dll


最终目录结构:


Release│   flutter_windows.dll│   msvcp140.dll│   my_app.exe│   vcruntime140.dll│   vcruntime140_1.dll└───data│   │   app.so│   │   icudtl.dat
...
复制代码

3.5 Flutter 插件

我们代码里面写死了加载.dll文件路径,打包后解压安装后加载路径不好找,Flutter 提供了插件支持,我们只需要创建 Native 插件即可,不用再考虑加载路径的问题。


  1. flutter create --template=plugin_ffi hello创建插件;

  2. pubspec.yaml 配置 FFI plugins:


  plugin:    platforms:      some_platform:        ffiPlugin: true
复制代码


这样在插件里面实现本地代码,应用工程中调用插件代码即可。


参考:


4、性能优化

运行时效果不是很理想,使用的 thinkpad,2.8G 主频 8 核,24G 内存,SSD,推理速度不是很快,开启编译优化:


  target_compile_options(model_lib PRIVATE                  "$<$<CONFIG:RELEASE>:-O3>"                  "$<$<CONFIG:DEBUG>:-O3>"                  ) 
复制代码


并没有很快的速度提升,具体优化还得持续研究。

5、总结

本文介绍了 Windows 上的 MSVC C++编译器以及 Flutter 创建桌面应用的步骤及应用程序打包方式,并分享了 FFI 集成本地代码遇到的问题和解决办法。

发布于: 2023-04-26阅读数: 21
用户头像

轻口味

关注

🏆2021年InfoQ写作平台-签约作者 🏆 2017-10-17 加入

Android、音视频、AI相关领域从业者。 欢迎加我微信wodekouwei拉您进InfoQ音视频沟通群 邮箱:qingkouwei@gmail.com

评论

发布
暂无评论
基于Flutter实现Windows平台离线大模型对话应用实战_flutter_轻口味_InfoQ写作社区