The basic principle and detailed example of cmake find_package (1)

1. Problems that find_package can solve

When building a project that relies on a third library or an external library (that is, the project needs to link to a third-party library or external library), we need to know the following information:

Where to find the header file of the third-party library.h Compare the -I parameter of GCC
Where to find the link files of third-party libraries (.so/.dll/.lib/.dylib/...) Compare the -L parameter of GCC
The name of the file of the linked third-party library Compare the -l parameter of GCC

After knowing the above information, you can easily include the header files of the third-party library and the library files (.a, .so) that are linked to the third-party library in the CMakeLists.txt;

2. Why use find_package

          The installation path of the third-party library may be different on different machines, so it is not realistic to specify the include path, link path and library in CMakeLists.txt, unless you specify that the dependent libraries required by the project are installed in a fixed directory (looks like Not very realistic), otherwise the build succeeds on your machine, and the build may fail on someone else's machine. Or after modifying the installation path or version upgrade of the third-party library, the build may not be successful on your own machine.

          Use cmake's find_package to solve the above problems.

         Give a chestnut:

              For example, if we need a third-party library curl, then our CMakeLists.txt needs to specify the header file directory, which is similar to the library file:

                 include_directiories(/usr/include/curl)
                 target_link_libraries(myprogram path/curl.so)
               What happens if you use the finder provided by cmake? Use FindCURL.cmake in the Modules directory of cmake, the corresponding CMakeList.txt file:
                 find_package(CURL REQUIRED)
                 include_directories(${CURL_INCLUDE_DIR})
                 target_link_libraries(curltest ${CURL_LIBRARY})

                  #Using find_package, don’t care where curl is located, find_package will solve it for us, so how do you find it intelligently?

Three, the principle of find_package

           find_package will first look for Findxxxx.cmake in the module path, which is a typical way to find libraries. The specific search path in turn is all the directories in the CMake variable ${CMAKE_MODULE_PATH}, if not, then look for its own module directory /share/cmake-xy/Modules/ (the specific value of $CMAKE_ROOT can be output by the message command in CMake). If the xxxx module is found, Findxxxx.cmake will generally set the following variables for CMakeLists.txt to use:

          xxxx_FOUND # is true

          xxxx_INCLUDE_DIRS   #include路径

          xxxx_LIBRARY_DIRS #library path

          xxxx_LIBRARIES #library's name

          xxxx_yyyy_VERSION #See Findxxxx.cmake for details

          In order to support various common libraries and packages, CMake comes with many Findxxxx modules. You can get the list of modules supported by your CMake through the command cmake –help-module-list (input cmake –help, and then double-click Tab to get a command prompt), or you can directly view the module path: ls /usr/share/cmake/Modules /

Four, basic grammar and patterns

        According to the cmake official documentation, find_package() has Module mode (basic signature) and Config mode (full signature). Among them, Module mode is the basic, and Config mode is more complex and advanced.

        Basic syntax of Module mode:

find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]
             [REQUIRED] [[COMPONENTS] [components...]]
             [OPTIONAL_COMPONENTS components...]
             [NO_POLICY_SCOPE])

        Basic syntax of Config mode:                                              

find_package(<PackageName> [version] [EXACT] [QUIET]
             [REQUIRED] [[COMPONENTS] [components...]]
             [OPTIONAL_COMPONENTS components...]
             [CONFIG|NO_MODULE]
             [NO_POLICY_SCOPE]
             [NAMES name1 [name2 ...]]
             [CONFIGS config1 [config2 ...]]
             [HINTS path1 [path2 ... ]]
             [PATHS path1 [path2 ... ]]
             [PATH_SUFFIXES suffix1 [suffix2 ...]]
             [NO_DEFAULT_PATH]
             [NO_PACKAGE_ROOT_PATH]
             [NO_CMAKE_PATH]
             [NO_CMAKE_ENVIRONMENT_PATH]
             [NO_SYSTEM_ENVIRONMENT_PATH]
             [NO_CMAKE_PACKAGE_REGISTRY]
             [NO_CMAKE_BUILDS_PATH] # Deprecated; does nothing.
             [NO_CMAKE_SYSTEM_PATH]
             [NO_CMAKE_SYSTEM_PACKAGE_REGISTRY]
             [CMAKE_FIND_ROOT_PATH_BOTH |
              ONLY_CMAKE_FIND_ROOT_PATH |
              NO_CMAKE_FIND_ROOT_PATH])

    For more details, please refer to: https://cmake.org/cmake/help/v3.18/command/find_package.html#find-package

    Config mode is only in the following three cases:

                The CONFIG keyword specified in
                find_package() The NO_MODULE keyword specified in find_package
                 () The keyword “basic signature” (that is, all supported configurations in Module mode) is not used in find_package()
     as long as the keyword “CONFIG” is not specified, do not specify “ NO_MODULE", and do not use the keywords in "full signature", then I am in Module mode. The first step in troubleshooting find_package() is to determine whether it is Module mode or Config mode.

Five, basic usage

    1. The usage of find_package() in Module mode         

find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]
             [REQUIRED] [[COMPONENTS] [components...]]
             [OPTIONAL_COMPONENTS components...]
             [NO_POLICY_SCOPE])

In Module mode, compared with Config mode, there are fewer optional configuration parameters, and if the package is not found according to the user-specified configuration, it will automatically enter Config mode (as shown in the figure above).

Keyword explanation

Both version and EXACT: are optional. version specifies the version. If specified, it must be checked whether the version of the package found is compatible with version. If you specify EXACT, it means that the version must be exactly matched instead of the compatible version.

QUIET is an optional field, which means that if the search fails, it will not be output on the screen (but if the REQUIRED field is specified, QUIET is invalid, and the search failure prompt will still be output).

MODULE Optional field. As mentioned earlier, "If the module mode search fails, return to the Config mode for search", but if the MODULE option is set, then only search in Module mode. If the search fails in Module mode, it does not fall back to Config mode for search.

REQUIRED optional field. Indicates that the package must be found. If it is not found, the entire cmake will be stopped immediately. If REQUIRED is not specified, cmake will continue to execute.

COMPONENTS, components: Optional field, indicating the components that must be found in the searched package. If any of them cannot be found, it will fail, similar to REQUIRED, causing cmake to stop execution.

OPTIONAL_COMPONENTS and components: optional modules, will not cause cmake to stop execution if not found.

Module mode search order In
Module mode, a file named Find<PackageName>.cmake is to be found.

First search in the path corresponding to the CMAKE_MODULE_PATH variable. If the path is empty or the search fails in the path, search in the cmake module directory (the Modules directory during cmake installation, such as /usr/local/share/cmake/Modules).

  2. Usage of find_package() in Config mode

find_package(<PackageName> [version] [EXACT] [QUIET]
             [REQUIRED] [[COMPONENTS] [components...]]
             [OPTIONAL_COMPONENTS components...]
             [CONFIG|NO_MODULE]
             [NO_POLICY_SCOPE]
             [NAMES name1 [name2 ...]]
             [CONFIGS config1 [config2 ...]]
             [HINTS path1 [path2 ... ]]
             [PATHS path1 [path2 ... ]]
             [PATH_SUFFIXES suffix1 [suffix2 ...]]
             [NO_DEFAULT_PATH]
             [NO_PACKAGE_ROOT_PATH]
             [NO_CMAKE_PATH]
             [NO_CMAKE_ENVIRONMENT_PATH]
             [NO_SYSTEM_ENVIRONMENT_PATH]
             [NO_CMAKE_PACKAGE_REGISTRY]
             [NO_CMAKE_BUILDS_PATH] # Deprecated; does nothing.
             [NO_CMAKE_SYSTEM_PATH]
             [NO_CMAKE_SYSTEM_PACKAGE_REGISTRY]
             [CMAKE_FIND_ROOT_PATH_BOTH |
              ONLY_CMAKE_FIND_ROOT_PATH |
              NO_CMAKE_FIND_ROOT_PATH])

Search order in Config mode

Much more than in Module mode. Moreover, the new version of CMake has more search orders than the old version (the new ones are in the first search order). The name of the file it is looking for is also different. For the Config mode, look for <PackageName>Config.cmake or <lower-case-package-name>-config.cmake. The search order is:

The cmake variable or environment variable named <PackageName>_ROOT. CMake3.12 added. Set CMP0074 Policy to disable.
Note: If the <PackageName>_DIR cmake variable is defined, then <PackageName>_ROOT has no effect.

cmake-specific cache variables:

CMAKE_PREFIX_PATH
CMAKE_FRAMEWORK_PATH
CMAKE_APPBUNDLE_PATH
can be set to NO_CMAKE_PATH to turn off this search order

cmake specific environment variables

<PackageName>_DIR
CMAKE_PREFIX_PATH
CMAKE_FRAMEWORK_PATH
CMAKE_APPBUNDLE_PATH
can be skipped by NO_CMAKE_ENVIRONMENT_PATH.

The path specified by the HINT field

Search the standard system environment variable PATH.
If it ends with /bin or /sbin, it will be automatically converted to its parent directory.
Skip by specifying NO_SYSTEM_ENVIRONMENT_PATH.

The path stored in the "User Package Registry" of cmake.
By setting NO_CMAKE_PACKAGE_REGISTRY, or:
setting CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY to true,
to avoid.

Set to the cmake variable defined by the current system:

CMAKE_SYSTEM_PREFIX_PATH
CMAKE_SYSTEM_FRAMEWORK_PATH
CMAKE_SYSTEM_APPBUNDLE_PATH
通过设定NO_CMAKE_SYSTEM_PATH来跳过。

Look in the "System Package Registry" of cmake.
Skip by setting NO_CMAKE_SYSTEM_PACKAGE_REGISTRY.
Or by setting CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY to true.

Search from the path specified in the PATHS field.

 

Guess you like

Origin blog.csdn.net/lianshaohua/article/details/108402470