From 671a630f47635ee8e44daf5ae6e94969ac4b8e0f Mon Sep 17 00:00:00 2001 From: Samuel Martin Date: Fri, 3 Oct 2014 00:32:40 +0200 Subject: [PATCH 1/2] cmake/OpenCVGenPkgconfig.cmake: rework opencv.pc generation Using absolute path to locate the components in the "Libs:" field of the *.pc can badly break cross-compilation, especially when building statically linked objects. Indeed, pkg-config automatically replaces the '-I...' and '-L...' paths when the PKG_CONFIG_SYSROOT_DIR and PKG_CONFIG_LIBDIR environment variables are set [1]. This feature is very helpful and common in cross-compilation framework like Buildroot [2,3]. When there are absolute paths in the *.pc files, pkg-config won't be able to do the path substitutions for these paths when the aforementioned environment variables are set. In such case, since the prefix is the target one, not the sysroot one, these libraries' absolute paths will point to: - in the best case: a non-existing file (i.e. these files do not exists on the host system; - at worst: the host system's libraries. This will make the linking failed because these host system's libraries will most likely not be build for the target architecture [4]. So, this patch replace the components' absolute paths by the form: -L -l This way, the linker will be able to resolve each dependency path, whatever the kind of objects/build (shared object or static build) it is dealing with. Note that for static link, the library order does matter [5]. The order of the opencv components has been carefully chosen to comply with this requirement. Fixes #3931 This patch is a port of [6] on the master branch. [1] http://linux.die.net/man/1/pkg-config [2] http://buildroot.org/ [3] http://git.buildroot.net/buildroot/tree/package/pkgconf/pkg-config.in [4] http://autobuild.buildroot.net/results/e8a/e8a859276db34aff87ef181b0cce98916b0afc90/build-end.log [5] http://stackoverflow.com/questions/45135/linker-order-gcc [6] https://github.com/Itseez/opencv/commit/eceada586bbf18fc267e437522ec4f1f23ddc656 Signed-off-by: Samuel Martin --- cmake/OpenCVGenPkgconfig.cmake | 71 ++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 24 deletions(-) diff --git a/cmake/OpenCVGenPkgconfig.cmake b/cmake/OpenCVGenPkgconfig.cmake index a8686e89cd..eebd760bbe 100644 --- a/cmake/OpenCVGenPkgconfig.cmake +++ b/cmake/OpenCVGenPkgconfig.cmake @@ -8,10 +8,6 @@ # # ${BIN_DIR}/unix-install/opencv.pc -> For use *with* "make install" # ------------------------------------------------------------------------------------------- -set(prefix "${CMAKE_INSTALL_PREFIX}") -set(exec_prefix "\${prefix}") -set(libdir "") #TODO: need link paths for OpenCV_EXTRA_COMPONENTS -set(includedir "\${prefix}/${OPENCV_INCLUDE_INSTALL_PATH}") if(CMAKE_BUILD_TYPE MATCHES "Release") set(ocv_optkind OPT) @@ -35,44 +31,71 @@ ocv_list_reverse(OpenCV_LIB_COMPONENTS) ocv_list_reverse(OpenCV_EXTRA_COMPONENTS) #build the list of components -set(OpenCV_LIB_COMPONENTS_ "") + +# Note: +# when linking against static libraries, if libfoo depends on libbar, then +# libfoo must come first in the linker flags. + +# world and contrib_world are special targets whose library should come first, +# especially for static link. +if(OpenCV_LIB_COMPONENTS MATCHES "opencv_world") + list(REMOVE_ITEM OpenCV_LIB_COMPONENTS "opencv_world") + list(INSERT OpenCV_LIB_COMPONENTS 0 "opencv_world") +endif() + +if(OpenCV_LIB_COMPONENTS MATCHES "opencv_contrib_world") + list(REMOVE_ITEM OpenCV_LIB_COMPONENTS "opencv_contrib_world") + list(INSERT OpenCV_LIB_COMPONENTS 0 "opencv_contrib_world") +endif() + +set(OpenCV_LIB_COMPONENTS_) foreach(CVLib ${OpenCV_LIB_COMPONENTS}) - if (TARGET ${CVLib}) - get_target_property(libpath ${CVLib} LOCATION_${CMAKE_BUILD_TYPE}) - get_filename_component(libname "${libpath}" NAME) - if(INSTALL_TO_MANGLED_PATHS) - set(libname "${libname}.${OPENCV_VERSION}") - endif() - - #need better solution.... - if(libpath MATCHES "3rdparty") - set(installDir "share/OpenCV/3rdparty/${OPENCV_LIB_INSTALL_PATH}") + get_target_property(libloc ${CVLib} LOCATION_${CMAKE_BUILD_TYPE}) + if(libloc MATCHES "3rdparty") + set(libpath "\${exec_prefix}/share/OpenCV/3rdparty/${OPENCV_LIB_INSTALL_PATH}") else() - set(installDir "${OPENCV_LIB_INSTALL_PATH}") + set(libpath "\${exec_prefix}/${OPENCV_LIB_INSTALL_PATH}") endif() + list(APPEND OpenCV_LIB_COMPONENTS_ "-L${libpath}") + + get_filename_component(libname ${CVLib} NAME_WE) + string(REGEX REPLACE "^lib" "" libname "${libname}") + list(APPEND OpenCV_LIB_COMPONENTS_ "-l${libname}") - set(OpenCV_LIB_COMPONENTS_ "${OpenCV_LIB_COMPONENTS_} \${exec_prefix}/${installDir}/${libname}") - endif() endforeach() # add extra dependencies required for OpenCV -set(OpenCV_LIB_COMPONENTS ${OpenCV_LIB_COMPONENTS_}) if(OpenCV_EXTRA_COMPONENTS) foreach(extra_component ${OpenCV_EXTRA_COMPONENTS}) - if(extra_component MATCHES "^-[lL]" OR extra_component MATCHES "[\\/]") - set(maybe_l_prefix "") + if(extra_component MATCHES "^-[lL]") + set(libprefix "") + set(libname "${extra_component}") + elseif(extra_component MATCHES "[\\/]") + get_filename_component(libdir "${extra_component}" PATH) + list(APPEND OpenCV_LIB_COMPONENTS_ "-L${libdir}") + get_filename_component(libname "${extra_component}" NAME_WE) + string(REGEX REPLACE "^lib" "" libname "${libname}") + set(libprefix "-l") else() - set(maybe_l_prefix "-l") + set(libprefix "-l") + set(libname "${extra_component}") endif() - - set(OpenCV_LIB_COMPONENTS "${OpenCV_LIB_COMPONENTS} ${maybe_l_prefix}${extra_component}") + list(APPEND OpenCV_LIB_COMPONENTS_ "${libprefix}${libname}") endforeach() endif() +list(REMOVE_DUPLICATES OpenCV_LIB_COMPONENTS_) +string(REPLACE ";" " " OpenCV_LIB_COMPONENTS "${OpenCV_LIB_COMPONENTS_}") + #generate the .pc file +set(prefix "${CMAKE_INSTALL_PREFIX}") +set(exec_prefix "\${prefix}") +set(libdir "\${exec_prefix}/${OPENCV_LIB_INSTALL_PATH}") +set(includedir "\${prefix}/${OPENCV_INCLUDE_INSTALL_PATH}") + if(INSTALL_TO_MANGLED_PATHS) set(OPENCV_PC_FILE_NAME "opencv-${OPENCV_VERSION}.pc") else() From 3863dc5b2b53028b9c7e70f2cdf8ef5d01c2b423 Mon Sep 17 00:00:00 2001 From: Maksim Shabunin Date: Tue, 19 May 2015 16:15:54 +0300 Subject: [PATCH 2/2] Updated pkg-config generation, added sample makefile --- CMakeLists.txt | 7 +- cmake/OpenCVGenPkgconfig.cmake | 114 +++++++++++++---------------- cmake/OpenCVUtils.cmake | 17 ++++- cmake/templates/opencv-XXX.pc.in | 3 +- modules/highgui/CMakeLists.txt | 2 +- modules/ts/CMakeLists.txt | 2 +- samples/cpp/example_cmake/Makefile | 12 +++ 7 files changed, 89 insertions(+), 68 deletions(-) create mode 100644 samples/cpp/example_cmake/Makefile diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d8718f6ae..939ee12674 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -769,6 +769,11 @@ else() endif() status(" Precompiled headers:" PCHSupport_FOUND AND ENABLE_PRECOMPILED_HEADERS THEN YES ELSE NO) +# ========================== Dependencies ============================ +ocv_get_all_libs(deps_modules deps_extra deps_3rdparty) +status(" Extra dependencies:" ${deps_extra}) +status(" 3rdparty dependencies:" ${deps_3rdparty}) + # ========================== OpenCV modules ========================== status("") status(" OpenCV modules:") @@ -909,7 +914,7 @@ else() endif() if( WITH_GDAL ) - status(" GDAL:" GDAL_FOUND THEN "${GDAL_LIBRARY}") + status(" GDAL:" GDAL_FOUND THEN "${GDAL_LIBRARY}" ELSE "NO") else() status(" GDAL:" "NO") endif() diff --git a/cmake/OpenCVGenPkgconfig.cmake b/cmake/OpenCVGenPkgconfig.cmake index eebd760bbe..28a6da686e 100644 --- a/cmake/OpenCVGenPkgconfig.cmake +++ b/cmake/OpenCVGenPkgconfig.cmake @@ -9,26 +9,33 @@ # ${BIN_DIR}/unix-install/opencv.pc -> For use *with* "make install" # ------------------------------------------------------------------------------------------- -if(CMAKE_BUILD_TYPE MATCHES "Release") - set(ocv_optkind OPT) -else() - set(ocv_optkind DBG) -endif() +macro(fix_prefix lst isown) + set(_lst) + foreach(item ${${lst}}) + if(TARGET ${item}) + get_target_property(item "${item}" LOCATION_${CMAKE_BUILD_TYPE}) + if("${isown}") + get_filename_component(item "${item}" NAME_WE) + string(REGEX REPLACE "^lib(.*)" "\\1" item "${item}") + endif() + endif() + if(item MATCHES "^-l") + list(APPEND _lst "${item}") + elseif(item MATCHES "[\\/]") + get_filename_component(libdir "${item}" PATH) + get_filename_component(libname "${item}" NAME_WE) + string(REGEX REPLACE "^lib(.*)" "\\1" libname "${libname}") + list(APPEND _lst "-L${libdir}" "-l${libname}") + else() + list(APPEND _lst "-l${item}") + endif() + endforeach() + set(${lst} ${_lst}) + unset(_lst) +endmacro() -#build the list of opencv libs and dependencies for all modules -set(OpenCV_LIB_COMPONENTS "") -set(OpenCV_EXTRA_COMPONENTS "") -foreach(m ${OPENCV_MODULES_PUBLIC}) - list(INSERT OpenCV_LIB_COMPONENTS 0 ${${m}_MODULE_DEPS_${ocv_optkind}} ${m}) - if(${m}_EXTRA_DEPS_${ocv_optkind}) - list(INSERT OpenCV_EXTRA_COMPONENTS 0 ${${m}_EXTRA_DEPS_${ocv_optkind}}) - endif() -endforeach() - -ocv_list_unique(OpenCV_LIB_COMPONENTS) -ocv_list_unique(OpenCV_EXTRA_COMPONENTS) -ocv_list_reverse(OpenCV_LIB_COMPONENTS) -ocv_list_reverse(OpenCV_EXTRA_COMPONENTS) +# build the list of opencv libs and dependencies for all modules +ocv_get_all_libs(_modules _extra _3rdparty) #build the list of components @@ -38,57 +45,38 @@ ocv_list_reverse(OpenCV_EXTRA_COMPONENTS) # world and contrib_world are special targets whose library should come first, # especially for static link. -if(OpenCV_LIB_COMPONENTS MATCHES "opencv_world") - list(REMOVE_ITEM OpenCV_LIB_COMPONENTS "opencv_world") - list(INSERT OpenCV_LIB_COMPONENTS 0 "opencv_world") +if(_modules MATCHES "opencv_world") + set(_modules "opencv_world") endif() -if(OpenCV_LIB_COMPONENTS MATCHES "opencv_contrib_world") - list(REMOVE_ITEM OpenCV_LIB_COMPONENTS "opencv_contrib_world") - list(INSERT OpenCV_LIB_COMPONENTS 0 "opencv_contrib_world") +if(_modules MATCHES "opencv_contrib_world") + list(REMOVE_ITEM _modules "opencv_contrib_world") + list(INSERT _modules 0 "opencv_contrib_world") endif() -set(OpenCV_LIB_COMPONENTS_) -foreach(CVLib ${OpenCV_LIB_COMPONENTS}) +fix_prefix(_modules TRUE) +fix_prefix(_extra FALSE) +fix_prefix(_3rdparty TRUE) - get_target_property(libloc ${CVLib} LOCATION_${CMAKE_BUILD_TYPE}) - if(libloc MATCHES "3rdparty") - set(libpath "\${exec_prefix}/share/OpenCV/3rdparty/${OPENCV_LIB_INSTALL_PATH}") - else() - set(libpath "\${exec_prefix}/${OPENCV_LIB_INSTALL_PATH}") - endif() - list(APPEND OpenCV_LIB_COMPONENTS_ "-L${libpath}") +ocv_list_unique(_modules) +ocv_list_unique(_extra) +ocv_list_unique(_3rdparty) - get_filename_component(libname ${CVLib} NAME_WE) - string(REGEX REPLACE "^lib" "" libname "${libname}") - list(APPEND OpenCV_LIB_COMPONENTS_ "-l${libname}") - -endforeach() - -# add extra dependencies required for OpenCV -if(OpenCV_EXTRA_COMPONENTS) - foreach(extra_component ${OpenCV_EXTRA_COMPONENTS}) - - if(extra_component MATCHES "^-[lL]") - set(libprefix "") - set(libname "${extra_component}") - elseif(extra_component MATCHES "[\\/]") - get_filename_component(libdir "${extra_component}" PATH) - list(APPEND OpenCV_LIB_COMPONENTS_ "-L${libdir}") - get_filename_component(libname "${extra_component}" NAME_WE) - string(REGEX REPLACE "^lib" "" libname "${libname}") - set(libprefix "-l") - else() - set(libprefix "-l") - set(libname "${extra_component}") - endif() - list(APPEND OpenCV_LIB_COMPONENTS_ "${libprefix}${libname}") - - endforeach() +set(OPENCV_PC_LIBS + "-L\${exec_prefix}/${OPENCV_LIB_INSTALL_PATH}" + "${_modules}" +) +if (BUILD_SHARED_LIBS) + set(OPENCV_PC_LIBS_PRIVATE "${_extra}") +else() + set(OPENCV_PC_LIBS_PRIVATE + "-L\${exec_prefix}/${OPENCV_3P_LIB_INSTALL_PATH}" + "${_3rdparty}" + "${_extra}" + ) endif() - -list(REMOVE_DUPLICATES OpenCV_LIB_COMPONENTS_) -string(REPLACE ";" " " OpenCV_LIB_COMPONENTS "${OpenCV_LIB_COMPONENTS_}") +string(REPLACE ";" " " OPENCV_PC_LIBS "${OPENCV_PC_LIBS}") +string(REPLACE ";" " " OPENCV_PC_LIBS_PRIVATE "${OPENCV_PC_LIBS_PRIVATE}") #generate the .pc file set(prefix "${CMAKE_INSTALL_PREFIX}") diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake index e7d60beb9b..3e2ea8a7a4 100644 --- a/cmake/OpenCVUtils.cmake +++ b/cmake/OpenCVUtils.cmake @@ -796,11 +796,19 @@ macro(ocv_get_all_libs _modules _extra _3rdparty) set(${_3rdparty} "") foreach(m ${OPENCV_MODULES_PUBLIC}) get_target_property(deps ${m} INTERFACE_LINK_LIBRARIES) + if(NOT deps) + set(deps "") + endif() list(INSERT ${_modules} 0 ${deps} ${m}) foreach (dep ${deps} ${OPENCV_LINKER_LIBS}) if (NOT DEFINED OPENCV_MODULE_${dep}_LOCATION) if (TARGET ${dep}) - list(INSERT ${_3rdparty} 0 ${dep}) + get_target_property(_output ${dep} ARCHIVE_OUTPUT_DIRECTORY) + if ("${_output}" STREQUAL "${3P_LIBRARY_OUTPUT_PATH}") + list(INSERT ${_3rdparty} 0 ${dep}) + else() + list(INSERT ${_extra} 0 ${dep}) + endif() else() list(INSERT ${_extra} 0 ${dep}) endif() @@ -808,6 +816,13 @@ macro(ocv_get_all_libs _modules _extra _3rdparty) endforeach() endforeach() + # ippicv specific handling + list(FIND ${_extra} "ippicv" ippicv_idx) + if (${ippicv_idx} GREATER -1) + list(REMOVE_ITEM ${_extra} "ippicv") + list(INSERT ${_3rdparty} 0 "ippicv") + endif() + # split 3rdparty libs and modules list(REMOVE_ITEM ${_modules} ${${_3rdparty}} ${${_extra}}) diff --git a/cmake/templates/opencv-XXX.pc.in b/cmake/templates/opencv-XXX.pc.in index 5b94e4d6c3..04d675af16 100644 --- a/cmake/templates/opencv-XXX.pc.in +++ b/cmake/templates/opencv-XXX.pc.in @@ -9,5 +9,6 @@ includedir_new=@includedir@ Name: OpenCV Description: Open Source Computer Vision Library Version: @OPENCV_VERSION_PLAIN@ -Libs: @OpenCV_LIB_COMPONENTS@ +Libs: @OPENCV_PC_LIBS@ +Libs.private: @OPENCV_PC_LIBS_PRIVATE@ Cflags: -I${includedir_old} -I${includedir_new} diff --git a/modules/highgui/CMakeLists.txt b/modules/highgui/CMakeLists.txt index 2a6f0b1d8c..0b7f8fe526 100644 --- a/modules/highgui/CMakeLists.txt +++ b/modules/highgui/CMakeLists.txt @@ -3,7 +3,7 @@ if (WINRT) endif() set(the_description "High-level GUI and Media I/O") -ocv_add_module(highgui opencv_imgproc opencv_imgcodecs opencv_videoio OPTIONAL opencv_androidcamera WRAP python) +ocv_add_module(highgui opencv_imgproc opencv_imgcodecs opencv_videoio WRAP python) # ---------------------------------------------------------------------------- # CMake file for highgui. See root CMakeLists.txt diff --git a/modules/ts/CMakeLists.txt b/modules/ts/CMakeLists.txt index 9d1e40c9c3..c0158ba416 100644 --- a/modules/ts/CMakeLists.txt +++ b/modules/ts/CMakeLists.txt @@ -9,7 +9,7 @@ set(OPENCV_MODULE_IS_PART_OF_WORLD FALSE) ocv_warnings_disable(CMAKE_CXX_FLAGS -Wundef) -ocv_add_module(ts opencv_core opencv_imgproc opencv_imgcodecs opencv_videoio opencv_highgui) +ocv_add_module(ts INTERNAL opencv_core opencv_imgproc opencv_imgcodecs opencv_videoio opencv_highgui) ocv_glob_module_sources() ocv_module_include_directories() diff --git a/samples/cpp/example_cmake/Makefile b/samples/cpp/example_cmake/Makefile new file mode 100644 index 0000000000..f72911571f --- /dev/null +++ b/samples/cpp/example_cmake/Makefile @@ -0,0 +1,12 @@ +CXX ?= g++ + +CXXFLAGS += -c -Wall $(shell pkg-config --cflags opencv) +LDFLAGS += $(shell pkg-config --libs --static opencv) + +all: opencv_example + +opencv_example: example.o; $(CXX) $< -o $@ $(LDFLAGS) + +%.o: %.cpp; $(CXX) $< -o $@ $(CXXFLAGS) + +clean: ; rm -f example.o opencv_example