# qiBuild documentation

# 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/<name>/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 `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.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 of `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 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.cmake` is found in `/usr/share/cmake-2.8/Modules/qibuild/general.cmake`, and `find_package(qibuild)` 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:

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

Changelog CMake index Python index Index