首页 > 解决方案 > 在 CMake 中包含“私有”标头的错误

问题描述

在我的库中,我将公共标头与源代码分开,方法是将它们放入includesrc. 在使用 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,库的目录不在包含路径中的错误。

标签: c++cmake

解决方案


库的用户直接或传递地包含的所有头文件都应该在 /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来打破接口和实现之间的依赖关系,但这也有其缺点,因此需要权衡取舍。


推荐阅读