# CMake: find\_package()

## What You Should Know & Your Actions

When we need to add an external project as the dependency, we will use command `find_package` in `CMakeLists.txt` to let CMake know where the header files and libraries are located, such that they can be found and linked properly later on.&#x20;

It is ideal that the developer of the external project provides a `<package>Config.cmake` file (or a `<lower-case-name>-config.cmake` file) for us/users, and this file will be cached into database (in the default installation path) after we `sudo make install` this external project. You can check if they are available by the `locate` command.&#x20;

```bash
# example commands
locate OpenCVConfig.cmake
locate gflags-config.cmake

# the results (if available)
/usr/share/OpenCV/OpenCVConfig.cmake
/usr/lib/x86_64-linux-gnu/cmake/gflags/gflags-config.cmake
```

If they are available, you only need to write one single line in the `CMakeLists.txt` file. For example,&#x20;

```bash
find_package(PCL)   # it will work given that PCLConfig.cmake is available
```

Unfortunately, there are certain packages that do not provide (they should!) this CMake configuration file (or the files are not adopted by Ubuntu/apt). In this case, we need to use `Find<package>.cmake` file instead to locate this external project. We can write it on our own, but it is often the case that someone has done it before. So go ahead and find an available one to use.&#x20;

After you find a good `Find<package>.cmake` file, we often place it under a folder named `cmake` or `cmake-modules` in the root directory of the current project (in parallel to `include`, `src`, etc.), and then add the path to this folder to a CMake variable `CMAKE_MODULE_PATH` (which is empty by default). With this setup, CMake will be able to look for your customized `Find<package>.cmake` file according to this CMake module path. What you need to do in `CMakeLists.txt` file is the following two lines of code.&#x20;

```bash
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake-modules")
find_package(Glog) # works given that FindGlog.cmake is placed under cmake-modules
```

#### Summary

* The CMake command `find_package` has two modes (Config mode and Module mode) to find and load the CMake configuration of an external project.
* In Config mode, it will look for a `<package>Config.cmake` or`<lower-case-name>-config.cmake` file in the default install path in Ubuntu system.&#x20;
* In Module mode, it will look for a `Find<package>.cmake` file in the path specified by variable `CMAKE_MODULE_PATH` ; this variable is empty unless set by user.
* Module mode has higher priority than Config mode, which means that you can overwrite the default Config file by providing your own FindXXX file.&#x20;

## More Technical Details

According to [the official documentation](https://cmake.org/cmake/help/v3.0/command/find_package.html) and [this stackoverflow answer](https://stackoverflow.com/questions/20746936/what-use-is-find-package-if-you-need-to-specify-cmake-module-path-anyway), find\_package() has two modes: "Module" mode and "Config" mode. If no module is found and the MODULE option is not given, the command proceeds to Config mode.

### Module mode

* It will look for a file called `Find<package>.cmake`, first in CMAKE\_MODULE\_PATH (empty by default), and then under cmake installation path `<CMAKE_ROOT>/Modules` (e.g., `/usr/share/cmake-3.5/Modules`). Some example default modules include `FindCUDA.cmake` or `FindOpenGL.cmake`.&#x20;
* Therefore, to add our own cmake modules or overwrite system cmake modules, we can add `Find<package>.cmake` files in a folder called `cmake` and do the following in CMakeLists.txt, to make the best use of CMAKE\_MODULE\_PATH.
* ```
  list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
  ```

### Config mode

* It will look for a file called `<package>Config.cmake` or `<lower-case-name>-config.cmake` under CMAKE\_INSTALL\_PREFIX (default to `/usr/local`). These cmake files are installed when we do `sudo make install` for 3rd party libraries. Examples are as follows (excerpts from command output).&#x20;
* ```
  -- Installing: /usr/local/share/OpenCV/OpenCVConfig.cmake
  -- Up-to-date: /usr/local/share/sophus/cmake/SophusConfig.cmake
  -- Up-to-date: /usr/local/lib/cmake/Ceres/CeresConfig.cmake
  -- Up-to-date: /usr/local/lib/cmake/g2o/g2oConfig.cmake
  -- Up-to-date: /usr/local/lib/cmake/GTest/GTestConfig.cmake
  -- Up-to-date: /usr/local/lib/cmake/DBoW3/DBoW3Config.cmake
  -- Up-to-date: /usr/local/lib/cmake/Pangolin/PangolinConfig.cmake
  ```

### References

* [stackoverflow: two modes in find\_package](https://stackoverflow.com/a/20857070/13980439)
* [stackoverflow: could not find a package configuration error](https://stackoverflow.com/a/65046283/13980439)

## Commands

Commonly used commands to figure out where packages are installed.

* `dpkg -L <package-name>`
* `apt list <package-name>`
* `locate <package>Config.cmake`

To set flags

* `set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")`&#x20;
* `set(CMAKE_BUILD_TYPE RelWithDebInfo)`&#x20;
* `cmake -DCMAKE_BUILD_TYPE=Debug`

Note that all names marked by \<xxx> should be replaced by their actual file names or package names. Case sensitive!

## Actions Needed After A Package Is Found

In general, once a package is found, a new variable `<package>_FOUND` will be generated and set to true. Also, there will be a few more variables loaded into the compilation process, such as `<package>_INCLUDE_DIR` , `<package>_INCLUDE_DIRS`, `<package>_LIBRARIES`, `<package>_LIBS`. Then you can use them to let CMake know where to look for header files and libraries. For example,&#x20;

```bash
find_package(Glog REQUIRED) # REQUIRED: will stop compilation if package is missing
include_directories(${GLOG_INCLUDE_DIRS})

add_executable (main src/main.cpp)
target_link_libraries (main ${GLOG_LIBRARIES})
```

Note that different projects may adopt different variable names. You need to make sure the spelling is completely correct. (Should it be `LIBRARIES` or `LIBS`?)

Typically, the variable names are expected to be documented in the official documentation of this external project. (They should!) If not, you will need to dig into `<lower-case-name>-config.cmake`  or `<package>Config.cmake` or `Find<package>.cmake` files, which is where they are defined.
