在库中使用 CMake "set(XXXX CACHE ...)" 是一个错误吗?
Posted
技术标签:
【中文标题】在库中使用 CMake "set(XXXX CACHE ...)" 是一个错误吗?【英文标题】:Is CMake "set(XXXX CACHE ...)" a bug when used in a library? 【发布时间】:2022-01-05 20:06:25 【问题描述】:我在我的项目中使用 CMake,我的项目的第三方库之一也是如此(为方便起见,包含在 add_subdirectory()
中)。我一直遇到奇怪的构建问题,我想我已经在第三方库的*** CMakeLists.txt
中将它们追踪到以下行:
set(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "")
这会为我的整个项目设置CMAKE_DEBUG_POSTFIX
(明确设置的任何子树除外),这会破坏我的构建。更糟糕的是,构建行为是依赖于顺序和时间的,在我的构建过程中,值会在干净构建之后更改,而不是在重建之后。 (追查很有趣。)
该库设置了许多名称以“XXXX_”开头的缓存变量,其中“XXXX”是库的名称。这对我来说很好,因为这些变量不太可能被其他人的代码使用。但是,当您的代码打算成为其他人项目的组件时,全局设置常用变量似乎是反社会的。它也很脆弱;如果我在***CMakeLists.txt
中使用set(XXXX <aValue>)
,那么库的set(XXXX CACHE...)
语句将被忽略。
相反,库应该只使用set(CMAKE_DEBUG_POSTFIX "d")
,它为库的所有代码树设置变量,而不是其他人的。
这是库的构建代码中的错误吗?旨在成为优秀 CMake 公民的库是否应该避免使用 CACHE 变量,除非它们明确命名的私有变量除外?
【问题讨论】:
为什么不告诉我们那是什么库呢?通知该库的维护者。 "这是库构建代码中的错误吗?" - 要确定某些行为是否是项目的错误,需要了解项目的要求。最有可能的是,图书馆项目不打算作为子项目工作(通过add_subdirectory
)。因此,您以不受支持的方式使用它不是库的错误。
@KamilCuk 我故意不想关注图书馆本身,而是关注实践。如果这里的答案是“是的:这是不好的做法”,我会向他们提交拉取请求。
@Tsyvarev 非常正确。我已经澄清了我在问题中对add_subdirectory()
的使用。 (谢谢。)
"相反,库应该只使用 set(CMAKE_DEBUG_POSTFIX "d"),它为库的所有代码树设置变量,而不是其他人的。"......不,他们不应该,因为那么当项目是***时,后缀不能被外部覆盖。
【参考方案1】:
对于打算用作子项目的库(通过add_subdirectory
或FetchContent
),我会说它是在不检查项目是否存在的情况下设置此类缓存变量的错误顶层。另一方面,在这种情况下,不打算以这种方式使用的项目应该明确检查并发出致命错误(或者可能是作者警告)。因此,无论哪种方式,我都认为存在错误,您应该通知维护人员。
在 CMake 3.21+ 中,变量 PROJECT_IS_TOP_LEVEL
有效。在早期版本中,您可以编写:
string(COMPARE EQUAL "$CMAKE_SOURCE_DIR" "$CMAKE_CURRENT_SOURCE_DIR" PROJECT_IS_TOP_LEVEL)
获取相同的变量。然后检查:
if (PROJECT_IS_TOP_LEVEL)
# Either this: (AUTHOR_WARNING acceptable, too)
message(FATAL_ERROR "Subproject inclusion not supported")
# or:
set(CMAKE_* ... CACHE ...)
endif ()
【讨论】:
正如亚历克斯所说。许多 CMake 库不能很好地与 add_subdirectory 一起使用。许多库希望用户安装它们,然后使用 find_package。以上是关于在库中使用 CMake "set(XXXX CACHE ...)" 是一个错误吗?的主要内容,如果未能解决你的问题,请参考以下文章
在库中使用 React 路由器 - 无法使用 useHistory()