使用vcpkg+Emscripten编译WASM时find_package(spdlog)失败
问题场景
项目基于以下配置开发:
CMakeLists.txt:
cmake_minimum_required(VERSION 3.14) include(FetchContent) FetchContent_Declare(vcpkg GIT_REPOSITORY https://github.com/microsoft/vcpkg/ GIT_TAG 2022.09.27) FetchContent_MakeAvailable(vcpkg) set(CMAKE_TOOLCHAIN_FILE "${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake" CACHE FILEPATH "") project(MyProject) set(CMAKE_CXX_STANDARD 20) find_package(spdlog CONFIG REQUIRED) add_executable(${CMAKE_PROJECT_NAME} src/main.cpp) target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE spdlog::spdlog)
vcpkg.json:
{ "name": "main", "version-string": "latest", "dependencies": [ "spdlog" ] }
原生环境下项目可正常构建运行,但添加-DVCPKG_TARGET_TRIPLET=wasm32-emscripten参数(已正确配置EMSDK环境变量)进行WASM交叉编译时,构建配置失败,报错如下:
CMake Error at cmake-build-release-wasm/_deps/vcpkg-src/scripts/buildsystems/vcpkg.cmake:829 (_find_package): Could not find a configuration file for package "spdlog" that is compatible with requested version "". The following configuration files were considered but not accepted: C:/Users/kiv/Projects/MyProject/cmake-build-release-wasm/vcpkg_installed/wasm32-emscripten/share/spdlog/spdlogConfig.cmake, version: 1.10.0 (32bit)
排查过程
网上资料显示这类错误通常是库版本不兼容(比如交叉编译误用系统库),但本次案例并非如此。
检查cmake-build-release-wasm\vcpkg_installed\wasm32-emscripten\lib\libspdlog.a,解压出spdlog.cpp.o后用Linuxfile工具查看:
$ file spdlog.cpp.o spdlog.cpp.o: WebAssembly (wasm) binary module version 0x1 (MVP)
确认该库确实是针对WASM目标编译的,理论上可以正常使用。尝试在find_package中指定版本参数(如1.10.0 (32bit)或1.10.0),均无法解决问题。
问题根源
定位到兼容性检查的代码位于vcpkg_installed/wasm32-emscripten/share/spdlog/spdlogConfigVersion.cmake:
... # if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it: if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "4" STREQUAL "") return() endif() # check that the installed version has the same 32/64bit-ness as the one which is currently searching: if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "4") math(EXPR installedBits "4 * 8") set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)") set(PACKAGE_VERSION_UNSUITABLE TRUE) endif()
在find_package前添加message("${CMAKE_SIZEOF_VOID_P}"),CMake输出为8,说明CMAKE_SIZEOF_VOID_P取的是主机系统(64位)的值,而非目标WASM平台(32位)的值,导致兼容性检查不通过。
解决方案
方案1:提前设置目标平台指针大小
在project指令前,针对wasm32-emscripten triplet强制设置CMAKE_SIZEOF_VOID_P为4,确保CMake使用目标平台的指针大小进行兼容性检查:
cmake_minimum_required(VERSION 3.14) include(FetchContent) FetchContent_Declare(vcpkg GIT_REPOSITORY https://github.com/microsoft/vcpkg/ GIT_TAG 2022.09.27) FetchContent_MakeAvailable(vcpkg) set(CMAKE_TOOLCHAIN_FILE "${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake" CACHE FILEPATH "") # 针对wasm32平台强制设置指针大小 if(VCPKG_TARGET_TRIPLET STREQUAL "wasm32-emscripten") set(CMAKE_SIZEOF_VOID_P 4 CACHE INTERNAL "Size of void* for wasm32 architecture") endif() project(MyProject) set(CMAKE_CXX_STANDARD 20) find_package(spdlog CONFIG REQUIRED) add_executable(${CMAKE_PROJECT_NAME} src/main.cpp) target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE spdlog::spdlog)
方案2:调整工具链加载顺序
确保Emscripten工具链优先于vcpkg工具链加载,让Emscripten的工具链文件自动设置正确的CMAKE_SIZEOF_VOID_P:
cmake_minimum_required(VERSION 3.14) # 先加载Emscripten原生工具链 set(CMAKE_TOOLCHAIN_FILE "${EMSDK}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake" CACHE FILEPATH "") include(FetchContent) FetchContent_Declare(vcpkg GIT_REPOSITORY https://github.com/microsoft/vcpkg/ GIT_TAG 2022.09.27) FetchContent_MakeAvailable(vcpkg) # 再加载vcpkg工具链 set(CMAKE_TOOLCHAIN_FILE "${vcpkg_SOURCE_DIR}/scripts/buildsystems/vcpkg.cmake" CACHE FILEPATH "") project(MyProject) set(CMAKE_CXX_STANDARD 20) find_package(spdlog CONFIG REQUIRED) add_executable(${CMAKE_PROJECT_NAME} src/main.cpp) target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE spdlog::spdlog)
方案3:临时跳过兼容性检查(不推荐)
临时注释掉spdlogConfigVersion.cmake中关于指针大小的检查逻辑,但此方案会跳过平台兼容性验证,仅适合临时测试:
... # if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it: # if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "4" STREQUAL "") # return() # endif() # check that the installed version has the same 32/64bit-ness as the one which is currently searching: # if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "4") # math(EXPR installedBits "4 * 8") # set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)") # set(PACKAGE_VERSION_UNSUITABLE TRUE) # endif()
内容的提问来源于stack exchange,提问作者kiv_apple

