Search order¶
Search order for packages, libs, headers, and programs¶
This has an impact on the following functions:
find_package()find_libary()find_path()find_program()
When the executable hello is looking for the world library,
the world library can be in several places:
- in the same project
src/hello - in a
worldproject insrc/world - in a toolchain with a
worldpackage - in the system, for instance because
libworld-devpackage is installed.
Here is the order CMake will use to find headers and libraries, in this order:
src/hello/path/to/world(if world target is defined when parsinghello‘s CMakeLists)src/world/build/sdk/include(providing there’sdepends=worldinhellomanifest)path/to/toolchain/<name>/world/include(if using a toolchain providing theworldpackage)/usr/include/(ifworldis installed in the system)
Note that it makes no difference whether you are using qi_use_lib
or find_package.
To make this work, we only use the CMAKE_FIND_ROOT_PATH cmake
variable, and qi_use_lib calls find_package without any specific
argument
This means that if you really need to find a library inside a toolchain, and never in the system, (for cross-compiling), you should use something like this for the toolchain file of your cross-toolchain
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
find_package(world)
Why ?¶
Because we treat the CMAKE_FIND_ROOT_PATH variable
very carefully ;)
Here’s what happens when you run qibuild configure hello:
In the main CMakeLists, you have project() before the call to
find_package(qibuild).
So this means you go through the toolchain file first (calling project() makes
cmake include the file passed with -DCMAKE_TOOLCHAIN_FILE.
The toolchain file generated by qitoolchain contains:
list(APPEND CMAKE_FIND_ROOT_PATH /path/to/toolchain/<name>)
(Note that qibuild configure calls cmake with the correct -DCMAKE_TOOLCHAIN_FILE
for you)
Then, you go through qibuild-config.cmake which includes build/dependencies.cmake
The code in dependencies.cmake looks like
list(INSERT CMAKE_FIND_ROOT_PATH 0 /path/to/src/world/build/sdk)
So that sources are searched before the packages from toolchain
Finally, you go through qibuild/general.cmake
Here we do something like
set(CMAKE_FIND_ROOT_PATH "${QI_SDK_DIR}" ${CMAKE_FIND_ROOT_PATH})
so that self build dir is searched first.
Note that we never reset CMAKE_FIND_ROOT_PATH, so that if user set it
from command lines, it exists even before going to the toolchain file,
so it still has the priority.
Search order for packages¶
When we call find_package(bar), we have several possible cases
- We are using a
bar-config.cmakethat was generated by qibuild. - We are using the custom
bar-config.cmakeinqibuild/cmake/modules. This can happen because the upstreamFindBar.cmakedoes not exist or is not usable. (For instance, the upstreamFindGTest.cmakesetsGTEST_BOTH_LIBRARIES,instead ofGTEST_LIBRARIES...) - We are using upstream’s CMake
FindBar.cmake.
Note
Due to strange CMake rules about case sensitivity, for this to work you
it’s best you always use find_package() with an upper-case argument.
find_package(GTest) won’t find gtest-config.cmake, but find_package(GTEST)
will find it. (strange but true)
That’s why when we call find_package from qi_use_lib we always use
the upper-case version of the first argument.
To do this, we have to search for the -config.cmake files generated by qiBuild (or
present in qibuild/cmake/modules, then only for upstream Find-\*.cmake in /usr/share/cmake)
This is not hard because find_package can be call with a special argument to only look
for -config.cmake files.
From the comments in the cmake code:
# find_package in two calls. The first call:
# Uses NO_MODULE - looks for PKGConfig.cmake, not FindPKG.cmake
# Uses QUIET - no warning will be generated
# If Config is found, then PKG_DIR will be set so that the following
# find_package knows where to look
find_package(${_pkg} NO_MODULE QUIET)
# _PACKAGE_FOUND is only set when using qibuild/cmake modules,
# see comments in find.cmake for details.
if(NOT ${_U_PKG}_PACKAGE_FOUND)
find_package(${_pkg} QUIET REQUIRED)
endif()
# Right after find_package_handle_standard_args, ${prefix}_FOUND is
# set correctly.
# For instance, if foo/bar.h is not foud, FOO_FOUND is FALSE.
# But, right after this, since foo-config.cmake HAS been found, CMake
# re-set FOO_FOUND to TRUE.
# So we set ${prefix}_PACKAGE_FOUND in cache...
Search order for cmake specific code¶
This has an impact on the functions:
- include()
And most of all, on find_package(qibuild)
We have several cases here:
- qibuild is installed in the system, so
qibuild/general.cmakeis found in/usr/share/cmake-2.8/Modules/qibuild/general.cmake, andfind_package(qibuild)just works. - we are using a cross toolchain without qibuild, so we have to set
CMAKE_MODULE_PATHtoCTC_DIR/sysroot/usr/share/cmake-2.8/Modules/qibuild(Assuming qibuild is installed in the sysroot of a cross-toolchain) - qibuild is not installed, and we are using a wrapper script using code from
~/src/qibuild.
To find the qibuild cmake files installed in a cross-toolchain, it is enough to do something like:
list(APPEND CMAKE_MODULE_PATH "${sysroot}/usr/share/cmake/Modules/")
To find the qibuild cmake files while using code from src/qibuild, we
do something like:
# in python/qibuild/__init__.py
def get_cmake_qibuild_dir():
""" Try to guess where the qibuild cmake files are
"""
# in project.bootstrap()
cmake_module_path = get_cmake_qibuild_dir()
Then, when we run qibuild configure hello, the dependencies.cmake file is generated
with the correct CMAKE_MODULE_PATH:
set(_qibuild_path "src/qibuild/cmake") # < this line configured by project.bootstrap()
list(FIND CMAKE_MODULE_PATH "${_qibuild_path}" _found)
if(_found STREQUAL "-1")
list(APPEND CMAKE_MODULE_PATH "${_qibuild_path}")
endif()