find_package with specified version in configuration script name - c++

I need to use mangrove (mongo ODM lib over mongo-c-driver and mongo-cxx-driver) and included this into my project as CMake ExternalProject_Add command, with a dependency on mongo-c-driver/mongo-cxx-driver
mongocxx generates CMake configuration scripts with a names like :
libmongocxx-config.cmake
libmongocxx-config-version.cmake
and no issues to find these by mangrove with that script:
set(LIBMONGOCXX_REQUIRED_VERSION 3.1.3)
set(LIBMONGOCXX_REQUIRED_ABI_VERSION v_noabi)
find_package(libmongocxx ${LIBMONGOCXX_REQUIRED_VERSION} REQUIRED)
However mongo-c-driver generates those scripts with a name which incudes ABI version into file names.
libmongoc-1.0-config.cmake
libmongoc-1.0-config-version.cmake
and similar CMake code:
set(LIBMONGOC_REQUIRED_VERSION 1.7.0)
set(LIBMONGOC_REQUIRED_ABI_VERSION 1.0)
find_package(LibMongoC ${LIBMONGOC_REQUIRED_VERSION} REQUIRED)
can't find out the scripts.
Of course, if I manually remove the version from file names, it can find those files, but I'd like to fix the problem in a script and on mangove side.
So the question about CMake techniques :
Is there an ability to specify the version of package which will automatically used by (inside CMake scripts names) find_package command to look for?

According to find_package documentation, the version is embedded inside the libmongocxx-config-version.cmake file.
This means that if you want to get the package libmongoc-1.0-config.cmake, you should use:
find_package(libmongoc-1.0 ${LIBMONGOC_REQUIRED_VERSION} REQUIRED)

Related

find_package() ignores <PackageName>_ROOT

In my CMake script I append the path to a folder containing <PackageName>Config.cmake to <PackageName>_ROOT and then call find_package(<PackageName> REQUIRED) but it can't find my package.
When I use CMAKE_FIND_DEBUG_MODE I see my folder listed in <PackageName>_ROOT CMake variable [CMAKE_FIND_USE_PACKAGE_ROOT_PATH] (it is actually the only folder there), but it is not listed after find_package considered the following locations for the Config module:.
Why am I getting such behaviour? I use CMake 3.18.1 from Android Studio. The package I'm trying to find is OpenCV.
Relatively to my CMakeLists.txt file OpenCV is installed in ../../build/opencv-build<custom suffix>, so my code for finding it is:
get_filename_component(OPENCV_BUILD_DIRS_ROOT ../../build REALPATH)
file(GLOB OPENCV_BUILD_DIRS ${OPENCV_BUILD_DIRS_ROOT}/opencv-build*)
list(APPEND OpenCV_ROOT ${OPENCV_BUILD_DIRS})
find_package(OpenCV ${OPENCV_VERSION} REQUIRED ${OPENCV_PUBLIC_LIBRARIES} ${OPENCV_PRIVATE_LIBRARIES})
When I run it on Linux (WSL actually), everything works fine and CMake finds OpenCV succesfully in ../../build/opencv-build (or <project path>/build/opencv-build in the form of absolute path).
But when I try to build the project from Android Studio it doesn't, and I get this output from CMAKE_FIND_DEBUG_MODE:
CMake Debug Log at external/opencv/CMakeLists.txt:12 (find_package):
find_package considered the following paths for OpenCV.cmake
C:/Users/<username>/AppData/Local/Android/Sdk/cmake/3.18.1/share/cmake-3.18/Modules/FindOpenCV.cmake
The file was not found.
<PackageName>_ROOT CMake variable [CMAKE_FIND_USE_PACKAGE_ROOT_PATH].
<project path>/build/opencv-build
CMAKE_PREFIX_PATH variable [CMAKE_FIND_USE_CMAKE_PATH].
C:/Users/<username>/AppData/Local/Android/Sdk/ndk/23.1.7779620/toolchains/llvm/prebuilt/windows-x86_64
CMAKE_FRAMEWORK_PATH and CMAKE_APPBUNDLE_PATH variables
[CMAKE_FIND_USE_CMAKE_PATH].
Env variable OpenCV_DIR [CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].
none
CMAKE_PREFIX_PATH env variable [CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].
none
CMAKE_FRAMEWORK_PATH and CMAKE_APPBUNDLE_PATH env variables
[CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].
none
Paths specified by the find_package HINTS option.
none
Standard system environment variables
[CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH].
<a lot of unrelated directories>
CMake User Package Registry [CMAKE_FIND_USE_PACKAGE_REGISTRY].
none
CMake variables defined in the Platform file
[CMAKE_FIND_USE_CMAKE_SYSTEM_PATH].
C:/Users/<username>/AppData/Local/Android/Sdk/cmake/3.18.1
<other unrelated directories>
CMake System Package Registry
[CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY].
none
Paths specified by the find_package PATHS option.
none
find_package considered the following locations for the Config module:
C:/Users/<username>/AppData/Local/Android/Sdk/ndk/23.1.7779620/toolchains/llvm/prebuilt/windows-x86_64/OpenCVConfig.cmake
C:/Users/<username>/AppData/Local/Android/Sdk/ndk/23.1.7779620/toolchains/llvm/prebuilt/windows-x86_64/opencv-config.cmake
C:/Users/<username>/AppData/Local/Android/Sdk/ndk/23.1.7779620/OpenCVConfig.cmake
C:/Users/<username>/AppData/Local/Android/Sdk/ndk/23.1.7779620/opencv-config.cmake
C:/Users/<username>/AppData/Local/Android/Sdk/ndk/23.1.7779620/toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/lib/i686-linux-android/21/OpenCVConfig.cmake
C:/Users/<username>/AppData/Local/Android/Sdk/ndk/23.1.7779620/toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/lib/i686-linux-android/21/opencv-config.cmake
C:/Users/<username>/AppData/Local/Android/Sdk/ndk/23.1.7779620/toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/local/OpenCVConfig.cmake
C:/Users/<username>/AppData/Local/Android/Sdk/ndk/23.1.7779620/toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/local/opencv-config.cmake
C:/Users/<username>/AppData/Local/Android/Sdk/ndk/23.1.7779620/toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/OpenCVConfig.cmake
C:/Users/<username>/AppData/Local/Android/Sdk/ndk/23.1.7779620/toolchains/llvm/prebuilt/windows-x86_64/sysroot/usr/opencv-config.cmake
C:/Users/<username>/AppData/Local/Android/Sdk/ndk/23.1.7779620/toolchains/llvm/prebuilt/windows-x86_64/sysroot/OpenCVConfig.cmake
C:/Users/<username>/AppData/Local/Android/Sdk/ndk/23.1.7779620/toolchains/llvm/prebuilt/windows-x86_64/sysroot/opencv-config.cmake
The file was not found.
So, the problem actually was that for Android (and, probably, iOS) CMake sets CMAKE_FIND_ROOT_PATH_MODE_PACKAGE variable (and other CMAKE_FIND_ROOT_PATH_MODE_* variables) to ONLY which makes find_package (and other find_* functions) prefix paths with what is in CMAKE_FIND_ROOT_PATH list.
To override this, one can do some of the following:
Set CMAKE_FIND_ROOT_PATH_MODE_* to BOTH or NEVER
Use CMAKE_FIND_ROOT_PATH_BOTH or NO_CMAKE_FIND_ROOT_PATH for each find_* call
It should also fix the issues when CMake ignores paths from HINTS, PATHS and other prefix construction steps.

If I find_package in CMakeLists.txt, must I find_dependency in my installed config.cmake?

I'm using CMake to build and to install a certain library, foo.
My library depends on some other library, bar, which has a config CMake script, so I have:
find_package(bar REQUIRED)
target_link_libraries(foo PUBLIC bar::bar)
That's as far as building goes. For installation, I have appropriate install() commands, with exports, and version configuration and all that stuff. This generates the package's -config.cmake file (as well as a version config file), so I don't need to keep one in the repository, nor generate one line-by-line within my CMakeLists.txt
Now, CMake has a module named find_dependency(), whose documentation suggests is to be used in package configuration files. But - I don't explicitly add it there. Should I? And more generally: Under which circumstances should I manually ensure a package configuration file has a find_dependency() for various find_package()'s?
First, CMake does not support "Transitive" behavior for find_package() (check this question).
The documentation recommends that "All REQUIRED dependencies of a package should be found in the Config.cmake file":
# <package>Config.cmake file
include(CMakeFindDependencyMacro)
find_dependency(Stats 2.6.4)
include("${CMAKE_CURRENT_LIST_DIR}/ClimbingStatsTargets.cmake") # They depend on Stats
include("${CMAKE_CURRENT_LIST_DIR}/ClimbingStatsMacros.cmake")
So, answering your questions:
"I don't explicitly add it there. Should I?" You actually have to, at least for REQUIRED packages.
"Under which circumstances should I manually ensure a package configuration file has a find_dependency() for various find_package()'s?" For required packages, you must. For optional package, you might want to add it in the configuration file so that optional features will be available.
I am working on a project which depends on an external package (Catch2). In my top level CMakelists.txt I have:
# Top level CMakelists.txt
set(Catch2_DIR "${PATH_TO_CATCH2}/lib/cmake/Catch2/")
find_package(Catch2 ${CATCH2_VERSION} REQUIRED)
Then I added the following to my package configuration file:
# <package>Config.cmake file
include(CMakeFindDependencyMacro)
set(Catch2_DIR "#PATH_TO_CATCH2#/lib/cmake/Catch2/") #be careful, path hard coded
find_dependency(Catch2 REQUIRED)
Just be careful because the find_dependency is a macro and it will change the value of PACKAGE_PREFIX_DIR variable in your package configuration file.

Add a subproject by CMake

Apache Arrow submodule is stored at thirdparty/apache_arrow/cpp, so my main CMakeLists.txt looks like
cmake_minimum_required(VERSION 3.0.0)
project(arrow_parcer VERSION 0.1.0)
add_subdirectory(src)
add_subdirectory(thirdparty/apache_arrow/cpp)
At the thirdparty/apache_arrow stored whole Apache Arrow project.
When I'm trying to build project, last output lines is follow:
[cmake] CMake Error: INSTALL(EXPORT) given unknown export "arrow_targets"
[cmake] Generating done
[cms-driver] Error during CMake configure: [cmake-server] Failed to compute build system.
Apache Arrow can be easily builded by CMakeLists.txt at /cpp folder, but why there is an error if I trying to include it by add_subdirectory?
Apache Arrow C++ is not meant to be built using add_subdirectory, instead you should use CMake's ExternalProject_Add facility to build it:
ExternalProject_Add(arrow_ep
URL "https://www.apache.org/dist/arrow/arrow-0.15.1/apache-arrow-0.15.1.tar.gz"
SOURCE_SUBDIR cpp)
Instead of using URL you can also use different providers like GIT_REPOSITORY, too.
If you don't really need to setup the installation, here is a hack-y way to do this. In the CMakeLists.txt adding arrow's source dir, you define your own install.
function(install)
endfunction()
add_subdirectory(${arrow_SOURCE_DIR}/cpp ${arrow_BINARY_DIR})

How can i fix tbb on CMake

I have this problem.
CMake Error at CMakeLists.txt:14 (find_package): By not providing
"FindTBB.cmake" in CMAKE_MODULE_PATH this project has asked CMake to
find a package configuration file provided by "TBB", but CMake did
not find one.
I could not find a package configuration file provided by "TBB" with any of the following names:
TBBConfig.cmake
tbb-config.cmake
Add the installation prefix of "TBB" to CMAKE_PREFIX_PATH or set
"TBB_DIR" to a directory containing one of the above files. If
"TBB" provides a separate development package or SDK, be sure it has
been installed.
how can i fix this?
Here is my CMakeLists.txt
cmake_minimum_required(VERSION 3.9)
project(deneme)
set(CMAKE_CXX_STANDARD 11)
include("C:/yunus/Git/inteltbb/tbb/cmake/TBBBuild.cmake")
tbb_build(TBB_ROOT "C:/yunus/Git/inteltbb/tbb" CONFIG_DIR TBB_DIR)
find_package(TBB REQUIRED tbb)
add_executable(deneme main.cpp ToDo.cpp ToDo.h)
TBB does not come by default with a FindTBB.cmake module so the guidelines in the error message are a bit misleading.
If your project provides the corresponding FindTBB.cmake module you need to add the path to it and the path to the TBB installation to your CMake call, i.e.
cmake . -G "<your generator here>" -DTBB_DIR=<path to TBB installation> -DCMAKE_PREFIX_PATH=<path to FindTBB.cmake>
Otherwise you need to download a suitable FindTBB.cmake module e.g. https://github.com/schuhschuh/cmake-basis-modules/blob/develop/FindTBB.cmake
This one uses TBB_ROOT instead of TBB_DIR.
Edit:
Try the binary package integration of TBB first.
Comment the include(...) and the tbb_build(...) command and add
target_link_libraries(deneme ${TBB_IMPORTED_TARGETS})
to your CMakeLists.txt after the add_executable call. Then call
cmake . -G "<your generator here>" -DCMAKE_PREFIX_PATH=<path to your TBB installation>

Cap'n Proto CMake support: CAPNP_LIB_CAPNP-JSON is NOTFOUND

Why do I have to set
set(CAPNP_LIB_CAPNP-JSON "")
in my CMakeLists.txt in order to not get an error? Error as follows:
CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
CAPNP_LIB_CAPNP-JSON (ADVANCED)
linked by target "client" in directory <...>
linked by target "server" in directory <...>
The way I'm using capnproto CMake support is by copying the cmake file included in the capnproto source into my project and including it manually. (Is there a better / standard way to do this? Feels hackish.) The rest is just taken from the CMake file's instructions.
CMake snippet:
# so capnp cmake plugin is found
set(CapnProto_DIR "${CMAKE_CURRENT_SOURCE_DIR}/etc/cmake")
# for some reason there is some json lib or something that isn't found?
#set(CAPNP_LIB_CAPNP-JSON "")
find_package(CapnProto REQUIRED)
include_directories(${CAPNP_INCLUDE_DIRS})
add_definitions(${CAPNP_DEFINITIONS})
set(CAPNPC_SRC_PREFIX "src/capnp")
# capnp out of source config
set(CAPNPC_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CAPNPC_OUTPUT_DIR})
# gen cpp
capnp_generate_cpp(CAPNP_SRCS CAPNP_HDRS
src/capnp/schema.capnp
)
CMake 3.6.2, building using CLion's integrated build commands. capnp is installed via homebrew, latest version.
Why am I getting the error about the JSON bit? What is that about?
Also, is there a better way for including the official Cap'n Proto CMake file? It seemed to not get distributed with the header and library files when installing via homebrew.
It turns out json encoding/decoding support is an as yet (Oct 2016) unreleased feature of Cap'n Proto and trying to use the .cmake file from the master branch with the last released version produces this conflict.
Possible solutions:
1) Use workaround posted in the question, i.e.
set(CAPNP_LIB_CAPNP-JSON "") # add this before next line
find_package(CapnProto REQUIRED)
2) Use the released version of the .cmake script here: FindCapnProto.cmake
3) Build and install Cap'n Proto from source, use with latest .cmake script.