使用 CMake FetchContent/add_subdirectory 时如何避免目标名称冲突?

Coo*_*k21 7 c++ dependencies build cmake fetchcontent

当我使用 CMake FetchContent 导入 OpenCV 时,它工作正常:

include(FetchContent)

# Fetch OpenCV
FetchContent_Declare(
        opencv
        GIT_REPOSITORY https://gitee.com/aiproach/opencv.git
        GIT_TAG        4.4.0
)
FetchContent_MakeAvailable(opencv)

set(OpenCV_DIR ${CMAKE_CURRENT_BINARY_DIR})
find_package(OpenCV REQUIRED)
Run Code Online (Sandbox Code Playgroud)

但在我添加特征之后:

# Fetch Eigen
FetchContent_Declare(
        eigen
        GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git
        GIT_TAG        3.3.9
)
FetchContent_MakeAvailable(eigen)
find_package(eigen3 REQUIRED)
Run Code Online (Sandbox Code Playgroud)

它会发出错误:

include(FetchContent)

# Fetch OpenCV
FetchContent_Declare(
        opencv
        GIT_REPOSITORY https://gitee.com/aiproach/opencv.git
        GIT_TAG        4.4.0
)
FetchContent_MakeAvailable(opencv)

set(OpenCV_DIR ${CMAKE_CURRENT_BINARY_DIR})
find_package(OpenCV REQUIRED)
Run Code Online (Sandbox Code Playgroud)

有人告诉我这是由命名空间冲突引起的,但我不知道如何解决该问题。我在 GitHub 上搜索了“FetchContent”,但似乎每个人都和我一样使用它。是否有一种通用方法可以使用 FetchContent 获取所有内容,只需插入项目名称和 URL?

sta*_*all 0

当来自不同项目依赖项的目标之间发生冲突时,除了礼貌地要求项目维护者考虑将其非导入/导出目标名称修改为类似命名空间之外,您现在无能为力。

您可以尝试通过在下载后修补其 CMake 文件来解决该问题。如果您正在使用该ExternalProject模块或该FetchContent模块(构建在ExternalProject之上),您也许可以使用参数来执行此PATCH_COMMAND操作(请参阅文档),该参数“指定在更新后修补源的自定义命令。 ”。但我自己从未尝试过,这听起来很痛苦。使用ExternalProject 的另一种方法是安装目标,然后将它们作为导入的库目标添加到项目配置中,这将允许您控制它们的目标名称。

例如,对于库目标,可能如下所示:

add_library(projectname_targetnamepart)
add_library("importexportnamespacename::targetnamepart" ALIAS projectname_targetnamepart)
set_target_properties(projectname_targetnamepart PROPERTIES EXPORT_NAME targetnamepart)
set_target_properties(projectname_targetnamepart PROPERTIES OUTPUT_NAME targetnamepart)
install(TARGETS projectname_targetnamepart EXPORT projectname_targets ...)
install(EXPORT projectname_targets NAMESPACE "importexportnamespacename::" ...)
Run Code Online (Sandbox Code Playgroud)

Craig Scott提出了一个 Kitware 问题单,提出了针对项目级命名空间的 CMake 功能。这是摘录:

使用拉入子项目时的一个常见问题add_subdirectory()是目标名称必须是唯一的,但不同的子项目可能会尝试使用相同的目标名称,这会导致名称冲突。本期建议引入项目命名空间的概念来解决这个问题以及相关的名称唯一性问题(这是本期的主要目标)。

有时上游维护者会拒绝支持add_subdirectory/FetchContent用例。OpenCV 就是这种情况,如本问题单 (#16896)所示。至于 eigen,有一个已经有一段时间没有任何活动的开放票证 (#1892)

其他人也有类似的问题:Isolating gitsubmoduleprojects in CMake,并在评论中指出他们能够通过使用 Hunter 包管理器解决问题,所以也许你可以尝试一下。