c++ - 在 CMake 中包含“私有”标头的错误
问题描述
在我的库中,我将公共标头与源代码分开,方法是将它们放入include
和src
. 在使用 Cmake 时,我的库中有这个:
target_include_directories(${PROJECT_NAME}
PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/include/Thoth"
"${CMAKE_CURRENT_SOURCE_DIR}/src"
INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/include"
)
这背后的想法是我希望最终用户(使用库)只有include
目录,以便他们必须像这样包含:
#include <Thoth/file.h>
但在图书馆内我可以省略Thoth
.
现在我还在src
库中包含了该目录,因为那里有一些私有头文件。
这很好用,我可以将每个文件都包含在预期的路径中。
编译使用该库的 exe 时,该库会成功编译,但会在 exe 本身上失败。
这是由于src
未找到在库中找到的标头。现在该文件未包含在 exe 中,因为它是私有的。但它来自这样一个事实,即 exe 包含一个包含私有标头的标头。
我已经玩过一些可见性设置并进行了谷歌搜索,但我还没有找到答案。
其他人如何处理分离私有和公共标头。
当然,我总是可以在库中使用相对路径,但我宁愿避免这种情况:
#include "../src/private.h"
很丑。
当然,如果这是唯一的方法,那就这样吧。虽然我认为其他人会遇到这个并想要一个解决方案。
我能想到的另一种方法是只src
公开包含文件夹并相信用户不包含私有标头,但这会污染包含路径并且是不可取的。
完整的库 CMake:
cmake_minimum_required(VERSION 3.13)
project(Thoth)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
add_library(${PROJECT_NAME}
src/IndentData.cpp
src/RenderComponent.cpp
src/RenderElement.cpp
src/RenderManager.cpp
)
target_include_directories(${PROJECT_NAME}
PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/include/Thoth"
"${CMAKE_CURRENT_SOURCE_DIR}/src"
INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/include"
)
完整的 exe CMake :
cmake_minimum_required(VERSION 3.13)
project(myExe)
add_subdirectory(lib/Thoth)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(${PROJECT_NAME} src/main.cpp)
target_link_libraries(${PROJECT_NAME} PUBLIC Thoth)
至于文件,这有点难以显示,但问题是RenderComponent.hpp
(within include/Thoth
) 包含IndentData.hpp
(within src
)。因此,当 exe 包含#include <Thoth/RenderComponent.hpp>
它时src
,库的目录不在包含路径中的错误。
解决方案
库的用户直接或传递地包含的所有头文件都应该在 /include 中。
如果LibInterface.h
包含LibInternal.h
和用户包含LibInterface.h
,那么LibInternal.h
也应该在/include中,因为用户包含是LibInternal.h
传递性的。
如果您可以避免LibInternal.h
被包含在 中LibInterface.h
,请执行此操作。有时你不能,因为LibInterface.h
可能取决于LibInternal.h
.
如果你想阻止用户直接包含LibInternal.h
,你可以把它放在 /include/detail 或类似的东西中。
在某些情况下,您可以使用pimpl idiom来打破接口和实现之间的依赖关系,但这也有其缺点,因此需要权衡取舍。
推荐阅读
- java - 尝试暂停时 ObjectAnimator 的奇怪行为
- c# - RavenDB:如何同时正确更新文档?(对同一端点的两个同时 API 请求)
- javascript - 如何在角组件中使用的chartist.js中的栏旁边附加信息数据?
- flutter - VerticalCardPager 未占用全宽
- c# - 将参数传递给 UserControl viewmodel
- python - 将数据从 pandas 数据框导入 SQL Server 时忽略错误的最佳方法是什么?
- emacs - 如何在 org (emacs) 内部的 4 个议程中使用有组织的日程安排
- git - 将文件更改分发到最后一次提交以使用 Git 修改每个文件(修复更改文件的最后一次提交)
- python - AWS Lambda - Python 3.8 如何写入包含多列和多行的 CSV 文件?
- ruby-on-rails - 覆盖重新索引 searchkick 方法错误:NoMethodError (super: no superclass method `reindex' for #
我们正在尝试覆盖 Searchkick 的重新索引方法,以避免在本地环境中重新索引。
所以我们创建了一个 initializers/record_indexer.rb :
class Searchk