I fail to properly add a dependency to opencv3 in my devs.
The setup is the following:
I’ve got two version of opencv:
2.4 which is the default one for ubuntu 16.04
3.3 which is provided inside ROS kinetic
I’ve got a static library L that depends publicly on OpenCV
I’ve got an application A that depends privately on L and OpenCV
find_package(OpenCV REQUIRED) finds the 3.3 version, which is what I expect.
I require all my dependencies to use namespace for homogeneity but OpenCV does not provide OpenCV::OpenCV.
On CMake 3.19 I do this:
find_package(OpenCV REQUIRED)
add_library(OpenCV::OpenCV UNKNOWN IMPORTED)
set_target_properties(OpenCV::OpenCV PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES “CXX”
IMPORTED_LOCATION “${OpenCV_LIBRARIES}”
INTERFACE_INCLUDE_DIRECTORIES “${OpenCV_INCLUDE_DIRS}”
)
target_link_libraries(${TARGET_NAME} ${Inheritance} OpenCV::OpenCV)
On CMake 3.5 (required by some customers…) I do this:
target_include_directories(${TARGET_NAME} ${Inheritance} ${OpenCV_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${Inheritance} ${OpenCV_LIBRARIES})
${Inheritance} is PUBLIC for L
${Inheritance} is PRIVATE for A
With CMake 3.5 my codes get built and can be executed.
But on CMake 3.19 I’ve got a build error, telling me that there is no rule to build target opencv_calib3d required for my target (actually opencv_calib3d is the first lib in OpenCV_LIBRARIES)
Besides I do it twice:
first in a static library L that publicly depends on OpenCV
then on my application A that depends both on L and on OpenCV
then in the build.make file of A, I see the list of OpenCV libraries twice. The build issues then a warning about an overloaded rule.
What do I miss?
NB1 it seems that all libraries names in ROS/OpenCV are finished by “3”, for instance opencv_calib3d3.so
NB2 I can’t locate the .a files within ROS/OpenCV
NB3 using
target_include_directories(${TARGET_NAME} ${Inheritance} ${OpenCV_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${Inheritance} ${OpenCV_LIBRARIES})
with CMake 3.19 works so it seems to be really an issue with the way I create OpenCV::OpenCV
Which puzzles me is that in both cases (with or without OpenCV::OpenCV wrapping) all environment and cmake variables are the same…
If you depend on an imported target from an installed package (basically grep the generated target information in the generated CMake package files for the imported target name), you need to provide that target as well. So things are probably failing when L mentions OpenCV::OpenCV in its interface and then A needs that same target. So basically, L might need to find_dependency(OpenCV) and then regenerate the same imported target again from find_package(L).
This is the LConfig.cmake
include(CMakeFindDependencyMacro)
foreach(lib IN ITEMS OpenCV;OtherDependencies)
find_dependency(${lib} REQUIRED)
endforeach()
# include the generated target file
include("${CMAKE_CURRENT_LIST_DIR}/LTargets.cmake")
L and A use find_package(OpenCV REQUIRED) and wrap it into OpenCV::OpenCV as described above
If L makes OpenCV::OpenCV in its build, it should make it in the package too. I would recommend naming it L::opencv or something though to avoid conflicting with any OpenCV:: targets which may exist in the future.
Sorry, I will then fall back to the thread mentioned above.
Indeed I feel that I don’t understand the way to package a third-party on the fly and to propagate it through dependencies.
I took inspiration from Daniel Pfeiffer presentation but it seems that I got it wrong.
I don’t understand what’s to be done on the package.
I also read several times the official CMake doc: https://cmake.org/cmake/help/git-stage/guide/importing-exporting/index.html
but, honestly, I could not understand it, especially in the context of third party targets.
I hope that my questions in the other thread may have an answer. I think that it may help a bunch of other peoples to that may otherwise use “workarounds” .
I just leave the imported targets to the packages or custom find modules. Doing it outside of the find_package call is a mess. I recommend that you contribute an IMPORTED target to whatever find_package(OpenCV) is calling.
I tried the FindOpenCV.cmake approach (see joined file) FindOpenCV.cmake (671 Bytes)
L compiles and install
When configuring A, OpenCV is find twice and the second time, all its libraries are listed twice.
On the whole, the OpenCV modules are listed three times…
When building I’ve still got the error “missing rule to build the target opencv_calib3d”…
I can’t see where is the error as the joined file seems pretty close to examples found on the web.
Could you please provide a stripped down, full example of what’s going on here? Speaking in abstract terms makes it hard to make recommendations on what else to do.
It still produces the missing rule error and a warning about rule overload.
But it does not reproduce the multiple finding of OpenCV. I will look into that to find what may be different between my real code and the small example.
Nevertheless, it might be already useful to find why I don’t properly create OpenCV::OpenCV
Regards CMakeDemo.7z (2.3 KB)
PS I provide a small Run.sh script to easily reproduce the error
PPS As a reminder: I’ve got several OpenCV version on my computer. The one found with find_package and NO_MODULE is the one wrapped into ROS
replacing IMPORTED_LOCATION with INTERFACE_LINK_LIBRARIES gives on Ubuntu with CMake 3.19.2:
CMake Error in CMakeLists.txt:
IMPORTED_LOCATION not set for imported target “OpenCV::OpenCV”
(both for L and A)
on windows with CMake 3.17.0 L compiles but A gives:
CMakeFiles\A.dir\build.make(92) : fatal error U1033: syntax error : unexpected ‘::’
Another difference between my windows and my ubuntu machine is that, on windows, I compiled OpenCV myself (a msvc version and a mingw one), while on Ubuntu 16.04 I’ve got the default one plus the one shipped with ROS kinetic (which is the one I locate with find_package).
I don’t understand much of the documentation except that I must avoid to provide absolute path to my package if I want to make them relocatable
To be confirmed, it seems to work on the Linux side.
Still not working on windows/MSVC/CMake 3.17
when calling cmake on L:
INTERFACE_LIBRARY targets may only have whitelisted properties. The
property “IMPORTED_LINK_INTERFACE_LANGUAGES” is not allowed.
Now it works! Thanks.
A bit frustrating though because I don’t understand why (why importing as INTERFACE, why removing the language (the doc tells that it should be ignored at worse, not generating an error), why populating the lib with INTERFACE_LINK_LIBRARIES?..).