Reputation: 1008
In my library I have seperated the public headers from the source by putting them into include
and src
. While using Cmake I have this for my library :
target_include_directories(${PROJECT_NAME}
PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/include/Thoth"
"${CMAKE_CURRENT_SOURCE_DIR}/src"
INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/include"
)
The idea behind this is that I want the end-user (using the library) to only have the include
directory so that they must include like so :
#include <Thoth/file.h>
But within the library I can omit the Thoth
.
Now I've also including the src
directory within the library because there are some private headers that live there.
This worked alright and I could include every file with the intended path.
When compiling an exe that used the library the library would compile successfully but it would fail on the exe itself.
This was due to the header found within the libraries src
not being found. Now that file is not being included in the exe as it is private. But it came from the fact that the exe included a header that had the private header included.
I've played around with some of the settings of visibility and done my googling but I have not found the answer.
How do others deal with separating private and public headers.
Of course I could always use a relative path within the library but I'd rather avoid this seeing as :
#include "../src/private.h"
Is ugly.
Of course if that is the only way, so be it. Though I'd think others would have run into this and wanted a solution.
The other way I could think of is to just include the src
folder publicly and trust the user to not include the private header but that would pollute the include path and is undesirably.
Full library 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"
)
Full 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)
As for the files, that's a little harder to show but the problem is that RenderComponent.hpp
(within include/Thoth
) includes IndentData.hpp
(within src
). So when the exe includes #include <Thoth/RenderComponent.hpp>
it errors that the src
dir of the library is not in the include path.
Upvotes: 3
Views: 2748
Reputation: 5022
@sparik had a good answer. Here's a little more detail to elaborate on that.
If one of your public headers depends on a private header, that private header will need to be moved to the public location That's because when you deploy your library (binary + headers), the user shouldn't depend on having access to your source tree.
The other way I could think of is to just include the src folder publicly and trust the user to not include the private header but that would pollute the include path and is undesirably.
This is option 1. It's the simplest and not uncommon. If you look at the public include directory of a massive library like boost unit_test_framework, you'll see that things which are private (i.e. undocumented, subject to api breakages) are located in <boost/test/detail/...hpp>
or <boost/test/impl/...ipp>
Option 2 would be to reduce the need for your public headers to include your private headers. That might be done by forward declaring everything. Storing references to those private classes instead of being composed of those private classes is one way to help you do that.
Upvotes: 3
Reputation: 1201
All the headers included by the user of the library, either directly or transitively, should be in /include.
If LibInterface.h
includes LibInternal.h
and the user includes LibInterface.h
, then LibInternal.h
should also be in /include, because the user includes LibInternal.h
transitively.
If you can avoid including LibInternal.h
being included in LibInterface.h
, do it. Sometimes you cannot, because LibInterface.h
may depend on something defined in LibInternal.h
.
If you want to discourage the user from directly including LibInternal.h
, you could put it in a /include/detail or something like that.
In some cases, you can use pimpl idiom to break dependency between your interface and implementation, but that has also its disadvantages, so it's a tradeoff.
Upvotes: 3