Importing OpenCV, versions conflicts

Hi,

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…

Many thanks in advance

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).

Hi

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

is it not the proper way to go?
(by the way in this thread proper way to wrap an imported target around a third-party target - #8 by adaldev, I described several generic use cases for which I failed to find a clear and correct procedure).

thanks

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.

Hi,

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” :wink:.

Regards
A.

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.

Hello

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.

Regards.

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.

Ouch,

It took me some work to provide a small example.

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

Hello,

Would it be possible to have a feedback on the above example?

Regards

I took a look. It seems that the issue is (word wrapped for ease of reading):

/builds/opencv/CMakeDemo/MyPackages/FindOpenCV.cmake(21):
set_target_properties(OpenCV::OpenCV
  PROPERTIES
    IMPORTED_LINK_INTERFACE_LANGUAGES CXX
    IMPORTED_LOCATION opencv_calib3d;opencv_core;opencv_dnn;opencv_features2d;opencv_flann;opencv_gapi;opencv_highgui;opencv_imgcodecs;opencv_imgproc;opencv_ml;opencv_objdetect;opencv_photo;opencv_stitching;opencv_video;opencv_videoio;opencv_alphamat;opencv_aruco;opencv_bgsegm;opencv_bioinspired;opencv_ccalib;opencv_cvv;opencv_datasets;opencv_dnn_objdetect;opencv_dnn_superres;opencv_dpm;opencv_face;opencv_freetype;opencv_fuzzy;opencv_hdf;opencv_hfs;opencv_img_hash;opencv_intensity_transform;opencv_line_descriptor;opencv_mcc;opencv_optflow;opencv_phase_unwrapping;opencv_plot;opencv_quality;opencv_rapid;opencv_reg;opencv_rgbd;opencv_saliency;opencv_shape;opencv_stereo;opencv_structured_light;opencv_superres;opencv_surface_matching;opencv_text;opencv_tracking;opencv_videostab;opencv_viz;opencv_wechat_qrcode;opencv_ximgproc;opencv_xobjdetect;opencv_xphoto
    INTERFACE_INCLUDE_DIRECTORIES /usr/include/opencv4)

IMPORTED_LOCATION is the full path to the library that is being represented. I think you want INTERFACE_LINK_LIBRARIES instead here.

Hi,

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

regards

Make it an INTERFACE library rather than UNKNOWN.

Thx,

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.

Strange that is platform specific, but that properly can be removed. The OpenCV imported targets should already have the link language set.

Hi,

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?..).

regards
A.

Because the target represents multiple libraries, it has to be. Non-interface targets need to be a single library import.

This sounds like a bug

Because you’re saying “if you use OpenCV::OpenCV, you need these libraries”. That’s what the INTERFACE_LINK_LIBRARIES target is for.