| Importing and Exporting Guide |
| ***************************** |
| |
| .. only:: html |
| |
| .. contents:: |
| |
| Introduction |
| ============ |
| |
| In this guide, we will present the concept of :prop_tgt:`IMPORTED` targets |
| and demonstrate how to import existing executable or library files from disk |
| into a CMake project. We will then show how CMake supports exporting targets |
| from one CMake-based project and importing them into another. Finally, we |
| will demonstrate how to package a project with a configuration file to allow |
| for easy integration into other CMake projects. This guide and the complete |
| example source code can be found in the ``Help/guide/importing-exporting`` |
| directory of the CMake source code tree. |
| |
| |
| Importing Targets |
| ================= |
| |
| :prop_tgt:`IMPORTED` targets are used to convert files outside of a CMake |
| project into logical targets inside of the project. :prop_tgt:`IMPORTED` |
| targets are created using the ``IMPORTED`` option of the |
| :command:`add_executable` and :command:`add_library` commands. No build |
| files are generated for :prop_tgt:`IMPORTED` targets. Once imported, |
| :prop_tgt:`IMPORTED` targets may be referenced like any other target within |
| the project and provide a convenient, flexible reference to outside |
| executables and libraries. |
| |
| By default, the :prop_tgt:`IMPORTED` target name has scope in the directory in |
| which it is created and below. We can use the ``GLOBAL`` option to extended |
| visibility so that the target is accessible globally in the build system. |
| |
| Details about the :prop_tgt:`IMPORTED` target are specified by setting |
| properties whose names begin in ``IMPORTED_`` and ``INTERFACE_``. For example, |
| :prop_tgt:`IMPORTED_LOCATION` contains the full path to the target on |
| disk. |
| |
| Importing Executables |
| --------------------- |
| |
| To start, we will walk through a simple example that creates an |
| :prop_tgt:`IMPORTED` executable target and then references it from the |
| :command:`add_custom_command` command. |
| |
| We'll need to do some setup to get started. We want to create an executable |
| that when run creates a basic ``main.cc`` file in the current directory. The |
| details of this project are not important. Navigate to |
| ``Help/guide/importing-exporting/MyExe``, create a build directory, run |
| :manual:`cmake <cmake(1)>` and build and install the project. |
| |
| .. code-block:: console |
| |
| $ cd Help/guide/importing-exporting/MyExe |
| $ mkdir build |
| $ cd build |
| $ cmake .. |
| $ cmake --build . |
| $ cmake --install . --prefix <install location> |
| $ <install location>/myexe |
| $ ls |
| [...] main.cc [...] |
| |
| Now we can import this executable into another CMake project. The source code |
| for this section is available in ``Help/guide/importing-exporting/Importing``. |
| In the CMakeLists file, use the :command:`add_executable` command to create a |
| new target called ``myexe``. Use the ``IMPORTED`` option to tell CMake that |
| this target references an executable file located outside of the project. No |
| rules will be generated to build it and the :prop_tgt:`IMPORTED` target |
| property will be set to ``true``. |
| |
| .. literalinclude:: Importing/CMakeLists.txt |
| :language: cmake |
| :start-after: # Add executable |
| :end-before: # Set imported location |
| |
| Next, set the :prop_tgt:`IMPORTED_LOCATION` property of the target using |
| the :command:`set_property` command. This will tell CMake the location of the |
| target on disk. The location may need to be adjusted to the |
| ``<install location>`` specified in the previous step. |
| |
| .. literalinclude:: Importing/CMakeLists.txt |
| :language: cmake |
| :start-after: # Set imported location |
| :end-before: # Add custom command |
| |
| We can now reference this :prop_tgt:`IMPORTED` target just like any target |
| built within the project. In this instance, let's imagine that we want to use |
| the generated source file in our project. Use the :prop_tgt:`IMPORTED` |
| target in the :command:`add_custom_command` command: |
| |
| .. literalinclude:: Importing/CMakeLists.txt |
| :language: cmake |
| :start-after: # Add custom command |
| :end-before: # Use source file |
| |
| As ``COMMAND`` specifies an executable target name, it will automatically be |
| replaced by the location of the executable given by the |
| :prop_tgt:`IMPORTED_LOCATION` property above. |
| |
| Finally, use the output from :command:`add_custom_command`: |
| |
| .. literalinclude:: Importing/CMakeLists.txt |
| :language: cmake |
| :start-after: # Use source file |
| |
| Importing Libraries |
| ------------------- |
| |
| In a similar manner, libraries from other projects may be accessed through |
| :prop_tgt:`IMPORTED` targets. |
| |
| Note: The full source code for the examples in this section is not provided |
| and is left as an exercise for the reader. |
| |
| In the CMakeLists file, add an :prop_tgt:`IMPORTED` library and specify its |
| location on disk: |
| |
| .. code-block:: cmake |
| |
| add_library(foo STATIC IMPORTED) |
| set_property(TARGET foo PROPERTY |
| IMPORTED_LOCATION "/path/to/libfoo.a") |
| |
| Then use the :prop_tgt:`IMPORTED` library inside of our project: |
| |
| .. code-block:: cmake |
| |
| add_executable(myexe src1.c src2.c) |
| target_link_libraries(myexe PRIVATE foo) |
| |
| |
| On Windows, a .dll and its .lib import library may be imported together: |
| |
| .. code-block:: cmake |
| |
| add_library(bar SHARED IMPORTED) |
| set_property(TARGET bar PROPERTY |
| IMPORTED_LOCATION "c:/path/to/bar.dll") |
| set_property(TARGET bar PROPERTY |
| IMPORTED_IMPLIB "c:/path/to/bar.lib") |
| add_executable(myexe src1.c src2.c) |
| target_link_libraries(myexe PRIVATE bar) |
| |
| A library with multiple configurations may be imported with a single target: |
| |
| .. code-block:: cmake |
| |
| find_library(math_REL NAMES m) |
| find_library(math_DBG NAMES md) |
| add_library(math STATIC IMPORTED GLOBAL) |
| set_target_properties(math PROPERTIES |
| IMPORTED_LOCATION "${math_REL}" |
| IMPORTED_LOCATION_DEBUG "${math_DBG}" |
| IMPORTED_CONFIGURATIONS "RELEASE;DEBUG" |
| ) |
| add_executable(myexe src1.c src2.c) |
| target_link_libraries(myexe PRIVATE math) |
| |
| The generated build system will link ``myexe`` to ``m.lib`` when built in the |
| release configuration, and ``md.lib`` when built in the debug configuration. |
| |
| Exporting Targets |
| ================= |
| |
| While :prop_tgt:`IMPORTED` targets on their own are useful, they still |
| require that the project that imports them knows the locations of the target |
| files on disk. The real power of :prop_tgt:`IMPORTED` targets is when the |
| project providing the target files also provides a CMake file to help import |
| them. A project can be setup to produce the necessary information so that it |
| can easily be used by other CMake projects be it from a build directory, a |
| local install or when packaged. |
| |
| In the remaining sections, we will walk through a set of example projects |
| step-by-step. The first project will create and install a library and |
| corresponding CMake configuration and package files. The second project will |
| use the generated package. |
| |
| Let's start by looking at the ``MathFunctions`` project in the |
| ``Help/guide/importing-exporting/MathFunctions`` directory. Here we have a |
| header file ``MathFunctions.h`` that declares a ``sqrt`` function: |
| |
| .. literalinclude:: MathFunctions/MathFunctions.h |
| :language: c++ |
| |
| And a corresponding source file ``MathFunctions.cxx``: |
| |
| .. literalinclude:: MathFunctions/MathFunctions.cxx |
| :language: c++ |
| |
| Don't worry too much about the specifics of the C++ files, they are just meant |
| to be a simple example that will compile and run on many build systems. |
| |
| Now we can create a ``CMakeLists.txt`` file for the ``MathFunctions`` |
| project. Start by specifying the :command:`cmake_minimum_required` version and |
| :command:`project` name: |
| |
| .. literalinclude:: MathFunctions/CMakeLists.txt |
| :language: cmake |
| :end-before: # create library |
| |
| The :module:`GNUInstallDirs` module is included in order to provide the |
| project with the flexibility to install into different platform layouts by |
| making the directories available as cache variables. |
| |
| Create a library called ``MathFunctions`` with the :command:`add_library` |
| command: |
| |
| .. literalinclude:: MathFunctions/CMakeLists.txt |
| :language: cmake |
| :start-after: # create library |
| :end-before: # add include directories |
| |
| And then use the :command:`target_include_directories` command to specify the |
| include directories for the target: |
| |
| .. literalinclude:: MathFunctions/CMakeLists.txt |
| :language: cmake |
| :start-after: # add include directories |
| :end-before: # install the target and create export-set |
| |
| We need to tell CMake that we want to use different include directories |
| depending on if we're building the library or using it from an installed |
| location. If we don't do this, when CMake creates the export information it |
| will export a path that is specific to the current build directory |
| and will not be valid for other projects. We can use |
| :manual:`generator expressions <cmake-generator-expressions(7)>` to specify |
| that if we're building the library include the current source directory. |
| Otherwise, when installed, include the ``include`` directory. See the `Creating |
| Relocatable Packages`_ section for more details. |
| |
| The :command:`install(TARGETS)` and :command:`install(EXPORT)` commands |
| work together to install both targets (a library in our case) and a CMake |
| file designed to make it easy to import the targets into another CMake project. |
| |
| First, in the :command:`install(TARGETS)` command we will specify the target, |
| the ``EXPORT`` name and the destinations that tell CMake where to install the |
| targets. |
| |
| .. literalinclude:: MathFunctions/CMakeLists.txt |
| :language: cmake |
| :start-after: # install the target and create export-set |
| :end-before: # install header file |
| |
| Here, the ``EXPORT`` option tells CMake to create an export called |
| ``MathFunctionsTargets``. The generated :prop_tgt:`IMPORTED` targets have |
| appropriate properties set to define their |
| :ref:`usage requirements <Target Usage Requirements>`, such as |
| :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES`, |
| :prop_tgt:`INTERFACE_COMPILE_DEFINITIONS` and other relevant built-in |
| ``INTERFACE_`` properties. The ``INTERFACE`` variant of user-defined |
| properties listed in :prop_tgt:`COMPATIBLE_INTERFACE_STRING` and other |
| :ref:`Compatible Interface Properties` are also propagated to the |
| generated :prop_tgt:`IMPORTED` targets. For example, in this case, the |
| :prop_tgt:`IMPORTED` target will have its |
| :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` property populated with |
| the directory specified by the ``INCLUDES DESTINATION`` property. As a |
| relative path was given, it is treated as relative to the |
| :variable:`CMAKE_INSTALL_PREFIX`. |
| |
| Note, we have *not* asked CMake to install the export yet. |
| |
| We don't want to forget to install the ``MathFunctions.h`` header file with the |
| :command:`install(FILES)` command. The header file should be installed to the |
| ``include`` directory, as specified by the |
| :command:`target_include_directories` command above. |
| |
| .. literalinclude:: MathFunctions/CMakeLists.txt |
| :language: cmake |
| :start-after: # install header file |
| :end-before: # generate and install export file |
| |
| Now that the ``MathFunctions`` library and header file are installed, we also |
| need to explicitly install the ``MathFunctionsTargets`` export details. Use |
| the :command:`install(EXPORT)` command to export the targets in |
| ``MathFunctionsTargets``, as defined by the :command:`install(TARGETS)` |
| command. |
| |
| .. literalinclude:: MathFunctions/CMakeLists.txt |
| :language: cmake |
| :start-after: # generate and install export file |
| :end-before: # include CMakePackageConfigHelpers macro |
| |
| This command generates the ``MathFunctionsTargets.cmake`` file and arranges |
| to install it to ``lib/cmake``. The file contains code suitable for |
| use by downstreams to import all targets listed in the install command from |
| the installation tree. |
| |
| The ``NAMESPACE`` option will prepend ``MathFunctions::`` to the target names |
| as they are written to the export file. This convention of double-colons |
| gives CMake a hint that the name is an :prop_tgt:`IMPORTED` target when it |
| is used by downstream projects. This way, CMake can issue a diagnostic |
| message if the package providing it was not found. |
| |
| The generated export file contains code that creates an :prop_tgt:`IMPORTED` library. |
| |
| .. code-block:: cmake |
| |
| # Create imported target MathFunctions::MathFunctions |
| add_library(MathFunctions::MathFunctions STATIC IMPORTED) |
| |
| set_target_properties(MathFunctions::MathFunctions PROPERTIES |
| INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include" |
| ) |
| |
| This code is very similar to the example we created by hand in the |
| `Importing Libraries`_ section. Note that ``${_IMPORT_PREFIX}`` is computed |
| relative to the file location. |
| |
| An outside project may load this file with the :command:`include` command and |
| reference the ``MathFunctions`` library from the installation tree as if it |
| were built in its own tree. For example: |
| |
| .. code-block:: cmake |
| :linenos: |
| |
| include(${INSTALL_PREFIX}/lib/cmake/MathFunctionTargets.cmake) |
| add_executable(myexe src1.c src2.c ) |
| target_link_libraries(myexe PRIVATE MathFunctions::MathFunctions) |
| |
| Line 1 loads the target CMake file. Although we only exported a single |
| target, this file may import any number of targets. Their locations are |
| computed relative to the file location so that the install tree may be |
| easily moved. Line 3 references the imported ``MathFunctions`` library. The |
| resulting build system will link to the library from its installed location. |
| |
| Executables may also be exported and imported using the same process. |
| |
| Any number of target installations may be associated with the same |
| export name. Export names are considered global so any directory may |
| contribute a target installation. The :command:`install(EXPORT)` command only |
| needs to be called once to install a file that references all targets. Below |
| is an example of how multiple exports may be combined into a single |
| export file, even if they are in different subdirectories of the project. |
| |
| .. code-block:: cmake |
| |
| # A/CMakeLists.txt |
| add_executable(myexe src1.c) |
| install(TARGETS myexe DESTINATION lib/myproj |
| EXPORT myproj-targets) |
| |
| # B/CMakeLists.txt |
| add_library(foo STATIC foo1.c) |
| install(TARGETS foo DESTINATION lib EXPORTS myproj-targets) |
| |
| # Top CMakeLists.txt |
| add_subdirectory (A) |
| add_subdirectory (B) |
| install(EXPORT myproj-targets DESTINATION lib/myproj) |
| |
| Creating Packages |
| ----------------- |
| |
| At this point, the ``MathFunctions`` project is exporting the target |
| information required to be used by other projects. We can make this project |
| even easier for other projects to use by generating a configuration file so |
| that the CMake :command:`find_package` command can find our project. |
| |
| To start, we will need to make a few additions to the ``CMakeLists.txt`` |
| file. First, include the :module:`CMakePackageConfigHelpers` module to get |
| access to some helper functions for creating config files. |
| |
| .. literalinclude:: MathFunctions/CMakeLists.txt |
| :language: cmake |
| :start-after: # include CMakePackageConfigHelpers macro |
| :end-before: # set version |
| |
| Then we will create a package configuration file and a package version file. |
| |
| Creating a Package Configuration File |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| Use the :command:`configure_package_config_file` command provided by the |
| :module:`CMakePackageConfigHelpers` to generate the package configuration |
| file. Note that this command should be used instead of the plain |
| :command:`configure_file` command. It helps to ensure that the resulting |
| package is relocatable by avoiding hardcoded paths in the installed |
| configuration file. The path given to ``INSTALL_DESTINATION`` must be the |
| destination where the ``MathFunctionsConfig.cmake`` file will be installed. |
| We will examine the contents of the package configuration file in the next |
| section. |
| |
| .. literalinclude:: MathFunctions/CMakeLists.txt |
| :language: cmake |
| :start-after: # create config file |
| :end-before: # install config files |
| |
| Install the generated configuration files with the :command:`INSTALL(files)` |
| command. Both ``MathFunctionsConfigVersion.cmake`` and |
| ``MathFunctionsConfig.cmake`` are installed to the same location, completing |
| the package. |
| |
| .. literalinclude:: MathFunctions/CMakeLists.txt |
| :language: cmake |
| :start-after: # install config files |
| :end-before: # generate the export targets for the build tree |
| |
| Now we need to create the package configuration file itself. In this case, the |
| ``Config.cmake.in`` file is very simple but sufficient to allow downstreams |
| to use the :prop_tgt:`IMPORTED` targets. |
| |
| .. literalinclude:: MathFunctions/Config.cmake.in |
| |
| The first line of the file contains only the string ``@PACKAGE_INIT@``. This |
| expands when the file is configured and allows the use of relocatable paths |
| prefixed with ``PACKAGE_``. It also provides the ``set_and_check()`` and |
| ``check_required_components()`` macros. |
| |
| The ``check_required_components`` helper macro ensures that all requested, |
| non-optional components have been found by checking the |
| ``<Package>_<Component>_FOUND`` variables for all required components. This |
| macro should be called at the end of the package configuration file even if the |
| package does not have any components. This way, CMake can make sure that the |
| downstream project hasn't specified any non-existent components. If |
| ``check_required_components`` fails, the ``<Package>_FOUND`` variable is set to |
| FALSE, and the package is considered to be not found. |
| |
| The ``set_and_check()`` macro should be used in configuration files instead |
| of the normal ``set()`` command for setting directories and file locations. |
| If a referenced file or directory does not exist, the macro will fail. |
| |
| If any macros should be provided by the ``MathFunctions`` package, they should |
| be in a separate file which is installed to the same location as the |
| ``MathFunctionsConfig.cmake`` file, and included from there. |
| |
| **All required dependencies of a package must also be found in the package |
| configuration file.** Let's imagine that we require the ``Stats`` library in |
| our project. In the CMakeLists file, we would add: |
| |
| .. code-block:: cmake |
| |
| find_package(Stats 2.6.4 REQUIRED) |
| target_link_libraries(MathFunctions PUBLIC Stats::Types) |
| |
| As the ``Stats::Types`` target is a ``PUBLIC`` dependency of ``MathFunctions``, |
| downstreams must also find the ``Stats`` package and link to the |
| ``Stats::Types`` library. The ``Stats`` package should be found in the |
| configuration file to ensure this. |
| |
| .. code-block:: cmake |
| |
| include(CMakeFindDependencyMacro) |
| find_dependency(Stats 2.6.4) |
| |
| The ``find_dependency`` macro from the :module:`CMakeFindDependencyMacro` |
| module helps by propagating whether the package is ``REQUIRED``, or |
| ``QUIET``, etc. The ``find_dependency`` macro also sets |
| ``MathFunctions_FOUND`` to ``False`` if the dependency is not found, along |
| with a diagnostic that the ``MathFunctions`` package cannot be used without |
| the ``Stats`` package. |
| |
| **Exercise:** Add a required library to the ``MathFunctions`` project. |
| |
| Creating a Package Version File |
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| |
| The :module:`CMakePackageConfigHelpers` module provides the |
| :command:`write_basic_package_version_file` command for creating a simple |
| package version file. This file is read by CMake when :command:`find_package` |
| is called to determine the compatibility with the requested version, and to set |
| some version-specific variables such as ``<PackageName>_VERSION``, |
| ``<PackageName>_VERSION_MAJOR``, ``<PackageName>_VERSION_MINOR``, etc. See |
| :manual:`cmake-packages <cmake-packages(7)>` documentation for more details. |
| |
| .. literalinclude:: MathFunctions/CMakeLists.txt |
| :language: cmake |
| :start-after: # set version |
| :end-before: # create config file |
| |
| In our example, ``MathFunctions_MAJOR_VERSION`` is defined as a |
| :prop_tgt:`COMPATIBLE_INTERFACE_STRING` which means that it must be |
| compatible among the dependencies of any depender. By setting this |
| custom defined user property in this version and in the next version of |
| ``MathFunctions``, :manual:`cmake <cmake(1)>` will issue a diagnostic if |
| there is an attempt to use version 3 together with version 4. Packages can |
| choose to employ such a pattern if different major versions of the package |
| are designed to be incompatible. |
| |
| |
| Exporting Targets from the Build Tree |
| ------------------------------------- |
| |
| Typically, projects are built and installed before being used by an outside |
| project. However, in some cases, it is desirable to export targets directly |
| from a build tree. The targets may then be used by an outside project that |
| references the build tree with no installation involved. The :command:`export` |
| command is used to generate a file exporting targets from a project build tree. |
| |
| If we want our example project to also be used from a build directory we only |
| have to add the following to ``CMakeLists.txt``: |
| |
| .. literalinclude:: MathFunctions/CMakeLists.txt |
| :language: cmake |
| :start-after: # generate the export targets for the build tree |
| |
| Here we use the :command:`export` command to generate the export targets for |
| the build tree. In this case, we'll create a file called |
| ``MathFunctionsTargets.cmake`` in the ``cmake`` subdirectory of the build |
| directory. The generated file contains the required code to import the target |
| and may be loaded by an outside project that is aware of the project build |
| tree. This file is specific to the build-tree, and **is not relocatable**. |
| |
| It is possible to create a suitable package configuration file and package |
| version file to define a package for the build tree which may be used without |
| installation. Consumers of the build tree can simply ensure that the |
| :variable:`CMAKE_PREFIX_PATH` contains the build directory, or set the |
| ``MathFunctions_DIR`` to ``<build_dir>/MathFunctions`` in the cache. |
| |
| An example application of this feature is for building an executable on a host |
| platform when cross-compiling. The project containing the executable may be |
| built on the host platform and then the project that is being cross-compiled |
| for another platform may load it. |
| |
| Building and Installing a Package |
| --------------------------------- |
| |
| At this point, we have generated a relocatable CMake configuration for our |
| project that can be used after the project has been installed. Let's try to |
| build the ``MathFunctions`` project: |
| |
| .. code-block:: console |
| |
| mkdir MathFunctions_build |
| cd MathFunctions_build |
| cmake ../MathFunctions |
| cmake --build . |
| |
| In the build directory, notice that the file ``MathFunctionsTargets.cmake`` |
| has been created in the ``cmake`` subdirectory. |
| |
| Now install the project: |
| |
| .. code-block:: console |
| |
| $ cmake --install . --prefix "/home/myuser/installdir" |
| |
| Creating Relocatable Packages |
| ============================= |
| |
| Packages created by :command:`install(EXPORT)` are designed to be relocatable, |
| using paths relative to the location of the package itself. They must not |
| reference absolute paths of files on the machine where the package is built |
| that will not exist on the machines where the package may be installed. |
| |
| When defining the interface of a target for ``EXPORT``, keep in mind that the |
| include directories should be specified as relative paths to the |
| :variable:`CMAKE_INSTALL_PREFIX` but should not explicitly include the |
| :variable:`CMAKE_INSTALL_PREFIX`: |
| |
| .. code-block:: cmake |
| |
| target_include_directories(tgt INTERFACE |
| # Wrong, not relocatable: |
| $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include/TgtName> |
| ) |
| |
| target_include_directories(tgt INTERFACE |
| # Ok, relocatable: |
| $<INSTALL_INTERFACE:include/TgtName> |
| ) |
| |
| The :genex:`$<INSTALL_PREFIX>` generator expression may be used as |
| a placeholder for the install prefix without resulting in a non-relocatable |
| package. This is necessary if complex generator expressions are used: |
| |
| .. code-block:: cmake |
| |
| target_include_directories(tgt INTERFACE |
| # Ok, relocatable: |
| $<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include/TgtName> |
| ) |
| |
| This also applies to paths referencing external dependencies. |
| It is not advisable to populate any properties which may contain |
| paths, such as :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` or |
| :prop_tgt:`INTERFACE_LINK_LIBRARIES`, with paths relevant to dependencies. |
| For example, this code may not work well for a relocatable package: |
| |
| .. code-block:: cmake |
| |
| target_link_libraries(MathFunctions INTERFACE |
| ${Foo_LIBRARIES} ${Bar_LIBRARIES} |
| ) |
| target_include_directories(MathFunctions INTERFACE |
| "$<INSTALL_INTERFACE:${Foo_INCLUDE_DIRS};${Bar_INCLUDE_DIRS}>" |
| ) |
| |
| The referenced variables may contain the absolute paths to libraries |
| and include directories **as found on the machine the package was made on**. |
| This would create a package with hard-coded paths to dependencies not |
| suitable for relocation. |
| |
| Ideally such dependencies should be used through their own |
| :ref:`IMPORTED targets <Imported Targets>` that have their own |
| :prop_tgt:`IMPORTED_LOCATION` and usage requirement properties |
| such as :prop_tgt:`INTERFACE_INCLUDE_DIRECTORIES` populated |
| appropriately. Those imported targets may then be used with |
| the :command:`target_link_libraries` command for ``MathFunctions``: |
| |
| .. code-block:: cmake |
| |
| target_link_libraries(MathFunctions INTERFACE Foo::Foo Bar::Bar) |
| |
| With this approach the package references its external dependencies |
| only through the names of :ref:`IMPORTED targets <Imported Targets>`. |
| When a consumer uses the installed package, the consumer will run the |
| appropriate :command:`find_package` commands (via the ``find_dependency`` |
| macro described above) to find the dependencies and populate the |
| imported targets with appropriate paths on their own machine. |
| |
| Using the Package Configuration File |
| ==================================== |
| |
| Now we're ready to create a project to use the installed ``MathFunctions`` |
| library. In this section we will be using source code from |
| ``Help\guide\importing-exporting\Downstream``. In this directory, there is a |
| source file called ``main.cc`` that uses the ``MathFunctions`` library to |
| calculate the square root of a given number and then prints the results: |
| |
| .. literalinclude:: Downstream/main.cc |
| :language: c++ |
| |
| As before, we'll start with the :command:`cmake_minimum_required` and |
| :command:`project` commands in the ``CMakeLists.txt`` file. For this project, |
| we'll also specify the C++ standard. |
| |
| .. literalinclude:: Downstream/CMakeLists.txt |
| :language: cmake |
| :end-before: # find MathFunctions |
| |
| We can use the :command:`find_package` command: |
| |
| .. literalinclude:: Downstream/CMakeLists.txt |
| :language: cmake |
| :start-after: # find MathFunctions |
| :end-before: # create executable |
| |
| Create an executable: |
| |
| .. literalinclude:: Downstream/CMakeLists.txt |
| :language: cmake |
| :start-after: # create executable |
| :end-before: # use MathFunctions library |
| |
| And link to the ``MathFunctions`` library: |
| |
| .. literalinclude:: Downstream/CMakeLists.txt |
| :language: cmake |
| :start-after: # use MathFunctions library |
| |
| That's it! Now let's try to build the ``Downstream`` project. |
| |
| .. code-block:: console |
| |
| mkdir Downstream_build |
| cd Downstream_build |
| cmake ../Downstream |
| cmake --build . |
| |
| A warning may have appeared during CMake configuration: |
| |
| .. code-block:: console |
| |
| CMake Warning at CMakeLists.txt:4 (find_package): |
| By not providing "FindMathFunctions.cmake" in CMAKE_MODULE_PATH this |
| project has asked CMake to find a package configuration file provided by |
| "MathFunctions", but CMake did not find one. |
| |
| Could not find a package configuration file provided by "MathFunctions" |
| with any of the following names: |
| |
| MathFunctionsConfig.cmake |
| mathfunctions-config.cmake |
| |
| Add the installation prefix of "MathFunctions" to CMAKE_PREFIX_PATH or set |
| "MathFunctions_DIR" to a directory containing one of the above files. If |
| "MathFunctions" provides a separate development package or SDK, be sure it |
| has been installed. |
| |
| Set the ``CMAKE_PREFIX_PATH`` to where MathFunctions was installed previously |
| and try again. Ensure that the newly created executable runs as expected. |
| |
| Adding Components |
| ================= |
| |
| Let's edit the ``MathFunctions`` project to use components. The source code for |
| this section can be found in |
| ``Help\guide\importing-exporting\MathFunctionsComponents``. The CMakeLists file |
| for this project adds two subdirectories: ``Addition`` and ``SquareRoot``. |
| |
| .. literalinclude:: MathFunctionsComponents/CMakeLists.txt |
| :language: cmake |
| :end-before: # include CMakePackageConfigHelpers macro |
| |
| Generate and install the package configuration and package version files: |
| |
| .. literalinclude:: MathFunctionsComponents/CMakeLists.txt |
| :language: cmake |
| :start-after: # include CMakePackageConfigHelpers macro |
| |
| If ``COMPONENTS`` are specified when the downstream uses |
| :command:`find_package`, they are listed in the |
| ``<PackageName>_FIND_COMPONENTS`` variable. We can use this variable to verify |
| that all necessary component targets are included in ``Config.cmake.in``. At |
| the same time, this function will act as a custom ``check_required_components`` |
| macro to ensure that the downstream only attempts to use supported components. |
| |
| .. literalinclude:: MathFunctionsComponents/Config.cmake.in |
| |
| Here, the ``MathFunctions_NOT_FOUND_MESSAGE`` is set to a diagnosis that the |
| package could not be found because an invalid component was specified. This |
| message variable can be set for any case where the ``_FOUND`` variable is set |
| to ``False``, and will be displayed to the user. |
| |
| The ``Addition`` and ``SquareRoot`` directories are similar. Let's look at one |
| of the CMakeLists files: |
| |
| .. literalinclude:: MathFunctionsComponents/SquareRoot/CMakeLists.txt |
| :language: cmake |
| |
| Now we can build the project as described in earlier sections. To test using |
| this package, we can use the project in |
| ``Help\guide\importing-exporting\DownstreamComponents``. There's two |
| differences from the previous ``Downstream`` project. First, we need to find |
| the package components. Change the ``find_package`` line from: |
| |
| .. literalinclude:: Downstream/CMakeLists.txt |
| :language: cmake |
| :start-after: # find MathFunctions |
| :end-before: # create executable |
| |
| To: |
| |
| .. literalinclude:: DownstreamComponents/CMakeLists.txt |
| :language: cmake |
| :start-after: # find MathFunctions |
| :end-before: # create executable |
| |
| and the ``target_link_libraries`` line from: |
| |
| .. literalinclude:: Downstream/CMakeLists.txt |
| :language: cmake |
| :start-after: # use MathFunctions library |
| |
| To: |
| |
| .. literalinclude:: DownstreamComponents/CMakeLists.txt |
| :language: cmake |
| :start-after: # use MathFunctions library |
| :end-before: # Workaround for GCC on AIX to avoid -isystem |
| |
| In ``main.cc``, replace ``#include MathFunctions.h`` with: |
| |
| .. literalinclude:: DownstreamComponents/main.cc |
| :language: c |
| :start-after: #include <string> |
| :end-before: int main |
| |
| Finally, use the ``Addition`` library: |
| |
| .. literalinclude:: DownstreamComponents/main.cc |
| :language: c |
| :start-after: // calculate sum |
| :end-before: return 0; |
| |
| Build the ``Downstream`` project and confirm that it can find and use the |
| package components. |