VCPKG如何支持WASM多线程
工作中遇到的一个问题,如果没有多VCPKG比较深入的理解,处理这个问题还是会比较棘手的。
本身来说,开启多线程在emscripten体系下还比较简单的,开启-pthread即可。详见Pthreads support
问题的关键在于如何在VCPKG的体系下实现:一个工程,可能依赖了N个库,那么每个库其实都要求是多线程的,不然Link会失败。
VCPKG内部的运行流程后面有机会系统说,个人认为:虽然有文档,但比如一个VCPKG_XXXX的变量,到底是作为环境变量配置,还是作为CMAKE的参数传入还是作用portfile.cmake或者triplets/xxx.cmake的一个set配置,其实还是挺模糊不清的。
比如,portfile.cmake里面,其实连CMAKE_BUILD_TYPE都读不到,其原因也只有看过源码才能真正理解。
回到问题,简单分享下自己尝试过的几种可行方法。
方法1:早期直接在CMake中设置,CMAKE_C(XX)_FLAGS,发现所有的port库都还是单线程的,说明port库的构建和宿主工程是有一定隔离的。失败。
方法2:使用CXXFLAGS环境变量,个人感觉过于Hack,可维护性也比较差,风险不可预测(比如被覆写)。放弃。
方法3:直接改下vcpkg.cmake,这个是主工程和port库都要执行这个文件,亲测可行。
方法4:考虑到魔改vcpkg源码不太好,尝试自定义triplets/wasm32-xxx.cmake,一开始尝试在wasm32-xxx.cmake内部设置,发现无论是设置CMAKE_CXX_FLAGS还是VCPKG_CXX_FLAGS都不生效,后来发现是因为:前者任何平台在triplets里面设置都不会处理(tripplet里面的arch-platform-xxx.cmake的处理方式和时机不看源码绝对想不到),后者需要vcpkg内部有对应的TOOLCAHIN_FILE,而emscripten恰好没有,也就是不会处理。构建web时,emscripten的内置toolchain file(位置emsdk/upstream/emscripten内)会被指定为VCPKG_CHAINLOAD_TOOLCHAIN_FILE,而其他平台都是vcpkg内置的(在scripts/toolchains),会处理VCPKG_CXX_FLAGS这样的自定义变量。
原来的wasm32-emscripten.cmake的部分逻辑如下:
.....
set(VCPKG_CMAKE_SYSTEM_NAME Emscripten)
set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE "${EMSCRIPTEN_ROOT}/cmake/Modules/Platform/Emscripten.cmake")
那么其实有2个选择:
- 修改Emscripten.cmake,但这样又侵入了emdk
- 自定义的triplets/wasm32-xxx.cmake在此基础上覆写VCPKG_CHAINLOAD_TOOLCHAIN_FILE,指向自己的toolchain file,这个toolchain file首先include(Emscripten.cmake),然后
set(CMAKE_CXX_FLAGS "-pthread")
对于选择2,toolchain file也通过一个环境变量设置即可。这样虽然麻烦点,但没有任何的侵入性。
但也有一个问题,我们有好几个工程,如果这样,就要每个工程Copy一份triplets/wasm32-xxx.cmake和一个toolchain file。所以长期看,还是要vcpkg内置这个可选项。