Ошибка в том числе "частный" заголовок с CMake - PullRequest
1 голос
/ 11 апреля 2020

В моей библиотеке я отделил заголовки publi c от источника, поместив их в 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-файле был включен заголовок с частным заголовком.

Я поэкспериментировал с некоторыми настройками видимости и выполнил поиск в Google, но я не нашел ответа.
Как другие справляются с разделением заголовков private и publi c.

Конечно, я всегда могу использовать относительный путь в библиотеке, но я бы предпочел не видеть это как:

#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"
)

Полная версия 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 (в пределах include/Thoth) включает IndentData.hpp (в пределах src). Поэтому, когда exe включает #include <Thoth/RenderComponent.hpp>, он ошибается, что src dir библиотеки не находится в пути включения.

Ответы [ 2 ]

2 голосов
/ 11 апреля 2020

@ у Спарика был хороший ответ. Вот еще немного подробностей, чтобы уточнить это.

Если один из ваших заголовков publi c зависит от частного заголовка, этот частный заголовок нужно будет переместить в местоположение publi c. Это потому, что когда вы разверните вашу библиотеку (двоичные + заголовки), пользователь не должен зависеть от доступа к вашему исходному дереву.

Другой способ, о котором я могу подумать, это просто публично включить папку sr c и доверять пользователю не включать частный заголовок, но это может привести к нежелательному загрязнению пути включения.

Это вариант 1. Это самый простой и весьма распространенный вариант. Если вы посмотрите на каталог publi c include такой большой библиотеки, как boost unit_test_framework , вы увидите, что личные вещи (то есть недокументированные, подверженные поломкам API) находятся в <boost/test/detail/...hpp> или <boost/test/impl/...ipp>

Вариант 2 заключается в том, чтобы уменьшить необходимость включения в ваши заголовки publi c ваших личных заголовков. Это может быть сделано путем объявления всего вперед. Хранение ссылок на эти частные классы вместо того, чтобы составлять их, является одним из способов помочь вам в этом.

2 голосов
/ 11 апреля 2020

Все заголовки, включенные пользователем библиотеки, напрямую или транзитивно, должны быть в /include.

Если LibInterface.h включает LibInternal.h, а пользователь включает LibInterface.h, то LibInternal.h также должен быть в / включить, потому что пользователь включает LibInternal.h транзитивно.

Если вы можете избежать включения LibInternal.h в LibInterface.h, сделайте это. Иногда вы не можете, потому что LibInterface.h может зависеть от того, что определено в LibInternal.h.

Если вы хотите отговорить пользователя от прямого включения LibInternal.h, вы можете поместить его в / include / detail или что-то в этом роде.

В некоторых случаях вы можете использовать pimpl idiom , чтобы нарушить зависимость между вашим интерфейсом и реализацией, но это также имеет свои недостатки, так что это компромисс.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...