如何在Windows平台通过CMake将C++库迁移至Flutter可执行程序
解决Windows下Flutter + Dart FFI + CMake的DLL路径与目录结构问题
针对你遇到的Windows平台DLL路径不对、Debug/Release目录分离,以及作为包被引用时的适配问题,提供以下几种可行方案:
一、修正CMake输出目录配置
Windows下DLL属于RUNTIME目标而非LIBRARY,你之前用CMAKE_LIBRARY_OUTPUT_DIRECTORY是无效的,需要改用RUNTIME_OUTPUT_DIRECTORY,同时结合Debug/Release的生成器表达式区分目录。另外,Flutter构建时会自动设置FLUTTER_BUILD_DIR变量,可适配项目作为包被引用的场景:
在你的C++库的CMakeLists.txt中添加:
if(WIN32) # 直接指定输出到Flutter runner的对应目录 set_target_properties(你的C++库目标名称 PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_LIST_DIR}/../build/windows/runner/Debug" RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_LIST_DIR}/../build/windows/runner/Release" ) # 适配项目作为包被引用的情况,使用Flutter提供的构建目录变量 if(DEFINED FLUTTER_BUILD_DIR) set_target_properties(你的C++库目标名称 PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG "${FLUTTER_BUILD_DIR}/runner/Debug" RUNTIME_OUTPUT_DIRECTORY_RELEASE "${FLUTTER_BUILD_DIR}/runner/Release" ) endif() endif()
二、用CMake POST_BUILD事件自动复制DLL
如果输出目录设置不生效,可以通过构建后命令强制将DLL复制到Flutter runner目录,自动区分Debug/Release:
if(WIN32) add_custom_command(TARGET 你的C++库目标名称 POST_BUILD # 复制当前构建的DLL到runner的对应配置目录 COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:你的C++库目标名称> $<TARGET_FILE_DIR:${BINARY_NAME}>/$<CONFIG>/$<TARGET_FILE_NAME:你的C++库目标名称> # 可选:复制依赖的第三方DLL(如果你的库依赖其他DLL) COMMAND ${CMAKE_COMMAND} -E copy_directory $<TARGET_FILE_DIR:你的C++库目标名称> $<TARGET_FILE_DIR:${BINARY_NAME}>/$<CONFIG> COMMENT "Copying DLLs to Flutter runner directory" ) endif()
其中$<TARGET_FILE_DIR:${BINARY_NAME}>会自动解析为Flutter runner可执行文件的目录,$<CONFIG>会根据构建模式自动替换为Debug或Release,无需硬编码路径。
三、批处理脚本方案
如果CMake的配置仍有问题,可以写一个批处理脚本手动复制DLL,然后绑定到构建流程中:
- 创建
windows/copy_dlls.bat脚本:
@echo off :: 替换为你的C++库构建目录和Flutter runner目录 set "CPP_DEBUG_DIR=../your_cpp_lib/build/Debug" set "CPP_RELEASE_DIR=../your_cpp_lib/build/Release" set "FLUTTER_DEBUG_DIR=./runner/Debug" set "FLUTTER_RELEASE_DIR=./runner/Release" :: 复制Debug版本DLL if exist "%CPP_DEBUG_DIR%\*.dll" ( xcopy "%CPP_DEBUG_DIR%\*.dll" "%FLUTTER_DEBUG_DIR%\" /Y /Q ) :: 复制Release版本DLL if exist "%CPP_RELEASE_DIR%\*.dll" ( xcopy "%CPP_RELEASE_DIR%\*.dll" "%FLUTTER_RELEASE_DIR%\" /Y /Q )
- 在Flutter项目的
pubspec.yaml中添加构建后钩子,自动执行脚本:
scripts: post-build-windows: "windows/copy_dlls.bat"
或者在CMake中添加自定义目标调用脚本:
if(WIN32) add_custom_target(copy_dlls ALL COMMAND cmd /C "${CMAKE_CURRENT_LIST_DIR}/copy_dlls.bat" DEPENDS 你的C++库目标名称 COMMENT "Running DLL copy script" ) endif()
四、Dart代码中动态获取运行时目录
如果需要在Dart层面动态适配路径,可以通过dart:io的Platform类获取当前可执行文件的目录(即Flutter runner的目录),然后拼接DLL路径:
import 'dart:io'; import 'package:path/path.dart' as path; void loadCppLib() { // 获取Flutter runner的运行时目录 final runtimeDir = path.dirname(Platform.resolvedExecutable); // 拼接DLL路径 final dllPath = path.join(runtimeDir, 'your_lib.dll'); final dylib = DynamicLibrary.open(dllPath); // 后续调用FFI方法... }
这种方式不管项目是直接运行还是作为包被引用,都能正确定位到DLL所在的runner目录。
内容的提问来源于stack exchange,提问作者itsLeatch
相关产品推荐
相关产品推荐

