使用FetchContent添加依赖目标至项目时遇安装/导出错误
你遇到的错误核心是FetchContent拉取的CvPlot源码位于构建目录(build/_deps/),而CvPlot的CMake配置中用绝对路径设置了INTERFACE_SOURCES属性。当你尝试安装导出CvPlot目标时,CMake会检查到这些路径是临时构建目录下的路径,无法在安装后或第三方使用时存在,因此抛出错误。而外部目录的add_subdirectory因为源码路径固定,不会触发这个检查。
解决方案1:修改CvPlot的CMake配置(推荐,若能修改依赖)
CvPlot的CMakeLists.txt中,target_sources没有区分构建和安装阶段的路径,导致安装时路径无效。需要用CMake的生成器表达式$<BUILD_INTERFACE:...>和$<INSTALL_INTERFACE:...>分别指定构建时和安装后的路径:
找到CvPlot的target_sources代码段,将:
target_sources(CvPlot INTERFACE inc/CvPlot/Internal/<header>.h # 其他头文件... )
修改为:
target_sources(CvPlot INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/inc/CvPlot/Internal/<header>.h> $<INSTALL_INTERFACE:include/CvPlot/Internal/<header>.h> # 其他文件同理修改 )
同时确保CvPlot的CMake配置中包含头文件安装指令:
install(DIRECTORY inc/CvPlot DESTINATION include )
这样CMake在构建时使用源码目录的路径,安装时使用安装后的标准路径,导出时就不会报错。
解决方案2:仅安装系统已有的CvPlot,FetchContent版本仅本地使用
如果不想修改依赖的CMake配置,可以调整你的项目逻辑:只在本地找到系统安装的CvPlot时才导出它,FetchContent拉取的版本仅用于本地开发,不参与安装导出:
find_package(CvPlot QUIET) if (CvPlot_FOUND) message(STATUS "Found cv-plot [${CvPlot_VERSION}]") # 仅当找到系统安装的CvPlot时才安装导出 install(TARGETS CvPlot EXPORT ${PROJECT_NAME}Targets) else() message(STATUS "CvPlot not found, fetching for local build only...") FetchContent_Declare(CvPlot GIT_REPOSITORY https://github.com/Profactor/cv-plot GIT_TAG master SOURCE_SUBDIR CvPlot ) FetchContent_MakeAvailable(CvPlot) # 不安装FetchContent拉取的临时版本 endif() target_link_libraries(${PROJECT_NAME} PUBLIC CvPlot)
这种方式符合CMake依赖管理的常规流程,第三方用户使用你的项目时需要自行安装CvPlot,而你本地开发时可以自动拉取依赖。
解决方案3:将FetchContent拉取的源码放到项目源码目录
通过指定SOURCE_DIR,让FetchContent把CvPlot源码下载到项目的源码目录而非构建目录,这样路径是固定的,安装导出时不会被判定为临时路径:
find_package(CvPlot QUIET) if (CvPlot_FOUND) message(STATUS "Found cv-plot [${CvPlot_VERSION}]") else() message(STATUS "CvPlot not found, fetching to source directory...") FetchContent_Declare(CvPlot GIT_REPOSITORY https://github.com/Profactor/cv-plot GIT_TAG master SOURCE_SUBDIR CvPlot SOURCE_DIR ${PROJECT_SOURCE_DIR}/deps/cv-plot ) FetchContent_Populate(CvPlot) add_subdirectory(${cvplot_SOURCE_DIR}/CvPlot ${cvplot_BINARY_DIR}) endif() target_link_libraries(${PROJECT_NAME} PUBLIC CvPlot) install(TARGETS CvPlot EXPORT ${PROJECT_NAME}Targets)
注意:需要把deps/cv-plot加入项目的.gitignore,避免把依赖源码提交到仓库。
内容的提问来源于stack exchange,提问作者joaocandre

