the usage of target_include_directories vs target_link_libraries

anyone know the reason?
why target_include_directories need to set the ${FMT_INCLUDE_DIRS} but not set the ${OpenCV_INCLUDE_DIRS}

target_include_directories(myapp PUBLIC
		${FMT_INCLUDE_DIRS}
	)
target_link_libraries(myapp
		${OpenCV_LIBRARIES}
		${FMT_LIBRARIES}
	)
1 Like

Where does this code comes from? I don’t think it is correct. if myapp doesn’t include ${OpenCV_INCLUDE_DIRS}, the source code won’t be able to find opencv headers.

The only explaination if this code works, it that ${OpenCV_INCLUDE_DIRS} are added globally for all targets by include_directories, or my app doesn’t uses opencv headers at all.

1 Like

thanks

by the way,
do you know how to usage the private and public?

here is the fix by me and the original is on the button of the page .

If I want to generate two exe with different *.cpp (main.cpp and main2.cpp)

Is it right? I am confused on public and private
if there are the example, it is great.

target_include_directories(tensorrt_cpp_api PUBLIC ${OpenCV_INCLUDE_DIRS} ${CUDA_INCLUDE_DIRS} ${TensorRT_INCLUDE_DIRS})
target_link_libraries(tensorrt_cpp_api PUBLIC ${OpenCV_LIBS} ${CUDA_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${TensorRT_LIBRARIES})

add_executable(driver src/main.cpp)
target_link_libraries(driver tensorrt_cpp_api)

add_executable(driver2 src/main2.cpp)
target_link_libraries(driver2 tensorrt_cpp_api)

here is the original:

Your fixed code is correct. tensorrt_cpp_api is a lib, so link publically will always works no matter it is static or shared.

There are three modes for a target to link another lib, or include a directory: PUBLIC, PRIVATE and INTERFACE. For example: we have lib A and B, and a executable C. B links to A, and C links to B.

Pubic link:

target_link_libraries(B PUBLIC A)
target_link_libraries(C PRIVATE B)

B will link to A, and C will be linked to both A and B.

Private link:

target_link_libraries(B PRIVATE A)
target_link_libraries(C PRIVATE B)

B will link to A, and C will link to only B.

Interface link:

target_link_libraries(B INTERFACE A)
target_link_libraries(C PRIVATE B)

B will not link to A, but C will link to both B and A.

In summary, PUBLIC is contagious, and PRIVATE is not contagious. INTERFACE is only used when B doesn’t actually requires A, but most targets that links to B requires A. INTERFACE is rarely used.

In my point of view, a static lib should always links PUBLIC ly to its dependencies, and a shared lib should link PRIVATE ly to its dependencies. For executables, PUBLIC and PRIVATE have no difference, because no targets can link to a executable.

Hi IMHO, I partially agree for the executable part but not for the library one.
First of all it does not depend on the shared/static status.
Let say a lib A depends on a lib B.
If the headers of A that may be included by an application that links A contains symbols from B then target_link_libraries(A PUBLIC B)
otherwise target_link_libraries(A PRIVATE B)
another situation may arise: B symbols are only present in A headers but are not used for A sources.
then target_link_libraries(A INTERFACE B)

for applications I agree that PUBLIC or PRIVATE should not make a difference, yet its cleaner then to use PRIVATE.

I sum up it in the following way (for target_compile_definitions and target_link_libraries):
PRIVATE: the target uses the definition/dependency only to be build, not its clients
PUBLIC: the target uses the definition/dependency when it is built, its clients also use it
INTERFACE: the target does not uses the definition/dependency when it is built, but its clients use it

Not quite. Shared libraries can also link publicly when their header files expose e.g types from the linked library.
For executables, the only use case I know is that loadable modules may link to it on some platforms.

NB there is a scenario that may be confusing:
A uses B privately (no trace of B in its API)
an application C uses A and B

it would be tempting to target_link_libraries(A PUBLIC B) and target_link_libraries(C PRIVATE A) but it would be wrong even if it would work I think.
I would go for:
target_link_libraries(A PRIVATE B)
target_link_libraries(C PRIVATE A)
target_link_libraries(C PRIVATE B)
which describes exactly the nature of the dependencies

At least, it is my understanding.
A.

Other possibility is that OpenCV_LIBRARIES actually contains CMake targets, but FMT_LIBRARIES only contains path(s) to the libraries.

1 Like

As for target_include_directories, it depends on the target nature.
for headers only libraries, I would use INTERFACE for the INSTALL_INTERFACE
For other libraries, I would put headers that may be include by third-party target in a different directory than the one used only by the target.
The first one will be declared PUBLIC for the BUILD_INTERFACE and INSTALL_INTERFACE.
For applications, I would declare only PRIVATE for the BUILD_INTERFACE and INSTALL_INTERFACE.

A.