.. _qibuild-search-order: 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 ``world`` project in ``src/world`` * in a toolchain with a ``world`` package * in the system, for instance because ``libworld-dev`` package 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 parsing ``hello``'s CMakeLists) * ``src/world/build/sdk/include`` (providing there's ``depends=world`` in ``hello`` manifest) * ``path/to/toolchain//world/include`` (if using a toolchain providing the ``world`` package) * ``/usr/include/`` (if ``world`` is installed in the system) Note that it makes no difference whether you are using :ref:`qi_use_lib` or ``find_package``. To make this work, we only use the ``CMAKE_FIND_ROOT_PATH`` cmake variable, and :ref:`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 .. code-block:: cmake 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 ``include(qibuild.cmake)``. 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: .. code-block:: cmake list(APPEND CMAKE_FIND_ROOT_PATH /path/to/toolchain/) (Note that ``qibuild configure`` calls cmake with the correct ``-DCMAKE_TOOLCHAIN_FILE`` for you) Then, you go through ``qibuild.cmake`` which includes ``build/dependencies.cmake`` The code in ``dependencies.cmake`` looks like .. code-block:: cmake 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 .. code-block:: cmake 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.cmake`` that was generated by qibuild. * We are using the custom ``bar-config.cmake`` in ``qibuild/cmake/modules``. This can happen because the upstream ``FindBar.cmake`` does not exist or is not usable. (For instance, the upstream ``FindGTest.cmake`` sets ``GTEST_BOTH_LIBRARIES,`` instead fo ``GTEST_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 alwayws 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 ni ``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: .. code-block:: cmake # 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 ``include(qibuild.cmake)`` We have several cases here: * qibuild is installed in the system, so ``qibuild/general.cmake`` is found in ``/usr/share/cmake-2.8/Modules/qibuild/general.cmake``, and ``include(qibuild.cmake)`` just works. * we are using a cross toolchain **without** qibuild, so we have to set ``CMAKE_MODULE_PATH`` to ``CTC_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: .. code-block:: cmake 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: .. code-block:: python # in python/qibuild/__init__.py def get_cmake_qibuild_dir(): """ Try to guess where the qibuild cmake files are """ CMAKE_QIBUILD_DIR = get_cmake_qibuild_dir() # in project.bootstrap() cmake_module_path = os.path.join(qibuild.CMAKE_QIBUILD_DIR, "..") Then, when we run ``qibuild configure hello``, the ``dependencies.cmake`` file is generated with the correct CMAKE_MODULE_PATH: .. code-block:: cmake 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()