如何在应用程序清单中正确引用私有Windows程序集并解决并行配置错误
问题描述
我的环境与目标
项目使用CMake构建,Ninja作为生成器,MSVC作为编译器。包含一个可执行目标A.exe和两个共享库目标(B.dll和C.dll)。在Windows系统上通过链接对应的静态库B.lib和C.lib实现加载时链接,依赖关系:A.exe -> B.dll -> C.dll("->"表示依赖)。
项目编译构建成功,但运行程序时出现错误:
The Application has failed to start because its side to side configuration is incorrect
项目基础文件夹结构:
\ | - A.cpp | - B.cpp | - C.cpp | - A.manifest | - B.manifest | - C.manifest | - CMakeLists.txt
代码
CMakeLists.txt:
cmake_minimum_required(VERSION 3.22.0) project(test VERSION 0.1.0) add_executable( A "A.cpp" "A.manifest" ) add_library( B SHARED "B.cpp" "B.manifest" ) add_library( C SHARED "C.cpp" "C.manifest" ) target_link_libraries(B C) # B -> C target_link_libraries(A B) # A -> B
CPP文件
A.cpp:
__declspec(dllimport) void B_test(); int main() { B_test(); return 0; }
B.cpp:
__declspec(dllimport) void C_test(); __declspec(dllexport) void B_test() { C_test(); }
C.cpp:
#include <iostream> __declspec(dllexport) void C_test() { std::cout << "Success" << std::endl; }
清单文件
A.manifest:
<?xml version="1.0" encoding="UTF-8"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" > <assemblyIdentity type="win32" name="A" language="*" processorArchitecture="amd64" version="1.0.0.0" /> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="B" language="*" processorArchitecture="amd64" version="1.0.0.0" /> </dependentAssembly> </dependency> </assembly>
B.manifest:
<?xml version="1.0" encoding="UTF-8"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" > <assemblyIdentity type="win32" name="B" language="*" processorArchitecture="amd64" version="1.0.0.0" /> <dependency> <dependentAssembly> <assemblyIdentity type="win32" name="C" language="*" processorArchitecture="amd64" version="1.0.0.0" /> </dependentAssembly> </dependency> <file name="B.dll" /> </assembly>
C.manifest:
<?xml version="1.0" encoding="UTF-8"?> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" > <!-- details about our side-by-side assembly--> <assemblyIdentity type="win32" name="C" language="*" processorArchitecture="amd64" version="1.0.0.0" /> <file name="C.dll" /> </assembly>
已尝试方案
- 根据微软文档,
C.manifest并非必需,所有.dll应在B.manifest中引用,但此方法无效。 - 尝试不使用清单文件,仍出现相同错误。
需求:实现A.exe依赖B.dll、B.dll依赖C.dll的正确配置,明确问题所在及解决方法。
解决方法
问题根源
- 手动清单与自动生成清单冲突:MSVC会自动生成包含CRT(C运行时库)依赖的清单文件,手动添加的清单会和自动生成的清单冲突,导致side-by-side配置错误。
- DLL部署路径问题:即使依赖关系正确,Windows无法找到
B.dll和C.dll时,也会触发该错误。 - CMake处理清单的方式错误:直接将
.manifest文件添加为目标源文件,会导致编译器错误地嵌入重复或不完整的清单信息。
具体修复步骤
1. 移除手动编写的清单文件,让MSVC自动生成
删除所有.manifest文件,同时修改CMakeLists.txt,移除对这些文件的引用:
cmake_minimum_required(VERSION 3.22.0) project(test VERSION 0.1.0) add_executable( A "A.cpp" ) add_library( B SHARED "B.cpp" ) add_library( C SHARED "C.cpp" ) target_link_libraries(B C) # B -> C target_link_libraries(A B) # A -> B
2. 确保所有输出文件在同一目录
CMake默认会将不同目标的输出放在不同子目录,需要统一输出目录,在CMakeLists.txt中添加以下配置:
# 设置所有目标的输出目录为同一位置 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) # 针对多配置生成器(如MSVC),确保Debug/Release等目录下的输出也统一 foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_BINARY_DIR}/bin/${OUTPUTCONFIG}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_BINARY_DIR}/bin/${OUTPUTCONFIG}) endforeach()
3. 确认MSVC运行时库配置
确保项目使用的运行时库一致,避免CRT依赖冲突,在CMakeLists.txt中添加:
# 设置MSVC运行时库为多线程DLL模式 if(MSVC) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd") endif()
4. 运行程序
重新构建项目后,A.exe、B.dll、C.dll会被输出到bin/Debug或bin/Release目录下,直接运行该目录下的A.exe即可。
自定义清单的正确姿势(如果确实需要)
如果必须使用自定义清单,不要直接将其添加为源文件,而是通过CMake的set_target_properties指定:
set_target_properties(A PROPERTIES LINK_FLAGS "/MANIFEST:NO") # 禁用自动生成的清单 set_target_properties(A PROPERTIES MANIFEST "${CMAKE_CURRENT_SOURCE_DIR}/A.manifest")
但这种方式需要确保自定义清单包含所有必要的依赖(包括CRT),否则仍会出现配置错误。
内容的提问来源于stack exchange,提问作者bub1ick
相关产品推荐
相关产品推荐

