使用VS 17.8.6+新版VCPKG编译DLL时遭遇Boost Fibers的C2491编译错误
最近我把开发环境升级到Visual Studio Community 17.8.6,同时更新了VCPKG到最新版本(2023-12-12-1c9ec1978a6b0c2b39c9e9554a96e3e275f7556e)后,编译自己的DLL项目时突然碰到了一个之前没有的编译错误。特意验证了一下,在VS 17.8.5搭配稍旧版VCPKG的环境里完全没问题,VCPKG用的是默认的x64-windows triplet,没做任何特殊配置。
具体错误信息如下:
vcpkg_installed\x64-windows\include\boost\fiber\stack_allocator_wrapper.hpp(85,43): error C2491: 'boost::fibers::make_stack_allocator_wrapper': definition of dllimport function not allowed
查了Boost Fibers的头文件代码才发现问题所在:make_stack_allocator_wrapper这个模板函数被标记了BOOST_FIBERS_DECL宏,但在我们编译DLL的场景下,这个宏会被定义为__declspec(dllimport),而模板函数的定义又直接写在头文件里——Windows编译器不允许给带有具体定义的函数标记dllimport,这就触发了C2491错误。
下面是几个我整理出来的可行解决思路:
临时 workaround 方案
改用Boost静态库
在项目的CMakeLists.txt里添加一行配置,强制使用静态版本的Boost库:set(Boost_USE_STATIC_LIBS ON) find_package(Boost REQUIRED COMPONENTS fibers)这样编译时会链接静态版的Boost Fibers,绕开dllimport/export的宏冲突问题,应该能直接解决错误。
给头文件打本地补丁
找到VCPKG安装目录下的boost/fiber/stack_allocator_wrapper.hpp,把make_stack_allocator_wrapper函数声明里的BOOST_FIBERS_DECL宏去掉。因为模板函数的定义本来就必须在头文件中可见,加这个dllimport标记反而画蛇添足。修改后的代码应该是:template <typename StackAllocator, typename ... Args> stack_allocator_wrapper make_stack_allocator_wrapper(Args && ... args) { return stack_allocator_wrapper( std::unique_ptr<detail::polymorphic_stack_allocator_base>( new detail::polymorphic_stack_allocator_impl<StackAllocator>(std::forward<Args>(args)...))); }不过要注意,后续VCPKG更新Boost时会覆盖这个修改,到时候得重新打补丁。
回退到稳定环境
暂时回退到VS 17.8.5和之前能正常工作的VCPKG版本,等Boost官方或者VCPKG团队修复这个兼容性问题后再升级,这是最稳妥的临时方案。
问题根源总结
这个错误大概率是VS 17.8.6对C++模板函数的dllimport标记检查变得更严格了,或者新版VCPKG编译Boost时的宏定义配置有变化。BOOST_FIBERS_DECL在动态链接场景下,编译Boost自身时是__declspec(dllexport),而我们的项目使用Boost时就变成了__declspec(dllimport),但模板函数的定义必须在头文件里,这就导致编译器看到一个被标记为dllimport的函数却有具体实现,直接触发了C2491错误。
备注:内容来源于stack exchange,提问作者DiB

