Cmake как подключить библиотеку

от admin

Step 2: Adding a Library¶

At this point, we have seen how to create a basic project using CMake. In this step, we will learn how to create and use a library in our project. We will also see how to make the use of our library optional.

Exercise 1 — Creating a Library¶

To add a library in CMake, use the add_library() command and specify which source files should make up the library.

Rather than placing all of the source files in one directory, we can organize our project with one or more subdirectories. In this case, we will create a subdirectory specifically for our library. Here, we can add a new CMakeLists.txt file and one or more source files. In the top level CMakeLists.txt file, we will use the add_subdirectory() command to add the subdirectory to the build.

Once the library is created, it is connected to our executable target with target_include_directories() and target_link_libraries() .

Add and use a library.

Helpful Resources¶

Files to Edit¶

Getting Started¶

In this exercise, we will add a library to our project that contains our own implementation for computing the square root of a number. The executable can then use this library instead of the standard square root function provided by the compiler.

For this tutorial we will put the library into a subdirectory called MathFunctions . This directory already contains a header file, MathFunctions.h , and a source file mysqrt.cxx . We will not need to modify either of these files. The source file has one function called mysqrt that provides similar functionality to the compiler’s sqrt function.

From the Help/guide/tutorial/Step2 directory, start with TODO 1 and complete through TODO 6 .

First, fill in the one line CMakeLists.txt in the MathFunctions subdirectory.

Next, edit the top level CMakeLists.txt .

Finally, use the newly created MathFunctions library in tutorial.cxx

Build and Run¶

Run the cmake executable or the cmake-gui to configure the project and then build it with your chosen build tool.

Below is a refresher of what that looks like from the command line:

Try to use the newly built Tutorial and ensure that it is still producing accurate square root values.

Solution¶

In the CMakeLists.txt file in the MathFunctions directory, we create a library target called MathFunctions with add_library() . The source file for the library is passed as an argument to add_library() . This looks like the following line:

TODO 1: Click to show/hide answer

To make use of the new library we will add an add_subdirectory() call in the top-level CMakeLists.txt file so that the library will get built.

TODO 2: Click to show/hide answer

Next, the new library target is linked to the executable target using target_link_libraries() .

TODO 3: Click to show/hide answer

Finally we need to specify the library’s header file location. Modify target_include_directories() to add the MathFunctions subdirectory as an include directory so that the MathFunctions.h header file can be found.

TODO 4: Click to show/hide answer

Now let’s use our library. In tutorial.cxx , include MathFunctions.h :

TODO 5: Click to show/hide answer

Lastly, replace sqrt with our library function mysqrt .

TODO 6: Click to show/hide answer

Exercise 2 — Making Our Library Optional¶

Now let us make the MathFunctions library optional. While for the tutorial there really isn’t any need to do so, for larger projects this is a common occurrence.

CMake can do this using the option() command. This gives users a variable which they can change when configuring their cmake build. This setting will be stored in the cache so that the user does not need to set the value each time they run CMake on a build directory.

Add the option to build without MathFunctions .

Helpful Resources¶

Files to Edit¶

Getting Started¶

Start with the resulting files from Exercise 1. Complete TODO 7 through TODO 13 .

First create a variable USE_MYMATH using the option() command in the top-level CMakeLists.txt file. In that same file, use that option to determine whether to build and use the MathFunctions library.

Then, update tutorial.cxx and TutorialConfig.h.in to use USE_MYMATH .

Build and Run¶

Since we have our build directory already configured from Exercise 1, we can rebuild by simply calling the following:

Next, run the Tutorial executable on a few numbers to verify that it’s still correct.

Now let’s update the value of USE_MYMATH to OFF . The easiest way is to use the cmake-gui or ccmake if you’re in the terminal. Or, alternatively, if you want to change the option from the command-line, try:

Now, rebuild the code with the following:

Then, run the executable again to ensure that it still works with USE_MYMATH set to OFF . Which function gives better results, sqrt or mysqrt ?

Solution¶

The first step is to add an option to the top-level CMakeLists.txt file. This option will be displayed in the cmake-gui and ccmake with a default value of ON that can be changed by the user.

TODO 7: Click to show/hide answer

Next, make building and linking the MathFunctions library conditional.

Start by creating a list() of the optional library targets for our project. At the moment, it is just MathFunctions . Let’s name our list EXTRA_LIBS .

Similarly, we need to make a list() for the optional includes which we will call EXTRA_INCLUDES . In this list, we will APPEND the path of the header file needed for our library.

Next, create an if() statement which checks the value of USE_MYMATH . Inside the if() block, put the add_subdirectory() command from Exercise 1 with the additional list() commands.

When USE_MYMATH is ON , the lists will be generated and will be added to our project. When USE_MYMATH is OFF , the lists stay empty. With this strategy, we allow users to toggle USE_MYMATH to manipulate what library is used in the build.

The top-level CMakeLists.txt file will now look like the following:

TODO 8: Click to show/hide answer

Now that we have these two lists, we need to update target_link_libraries() and target_include_directories() to use them. Changing them is fairly straightforward.

For target_link_libraries() , we replace the written out library names with EXTRA_LIBS . This looks like the following:

TODO 9: Click to show/hide answer

Then, we do the same thing with target_include_directories() and EXTRA_INCLUDES .

TODO 10: Click to show/hide answer

Note that this is a classic approach when dealing with many components. We will cover the modern approach in the Step 3 of the tutorial.

The corresponding changes to the source code are fairly straightforward. First, in tutorial.cxx , we include the MathFunctions.h header if USE_MYMATH is defined.

TODO 11: Click to show/hide answer

Then, in the same file, we make USE_MYMATH control which square root function is used:

TODO 12: Click to show/hide answer

Since the source code now requires USE_MYMATH we can add it to TutorialConfig.h.in with the following line:

TODO 13: Click to show/hide answer

With these changes, our library is now completely optional to whoever is building and using it.

add_library¶

Add a library to the project using the specified source files.

Normal Libraries¶

Adds a library target called <name> to be built from the source files listed in the command invocation. The <name> corresponds to the logical target name and must be globally unique within a project. The actual file name of the library built is constructed based on conventions of the native platform (such as lib<name>.a or <name>.lib ).

New in version 3.1: Source arguments to add_library may use "generator expressions" with the syntax $<. > . See the cmake-generator-expressions(7) manual for available expressions.

New in version 3.11: The source files can be omitted if they are added later using target_sources() .

STATIC , SHARED , or MODULE may be given to specify the type of library to be created. STATIC libraries are archives of object files for use when linking other targets. SHARED libraries are linked dynamically and loaded at runtime. MODULE libraries are plugins that are not linked into other targets but may be loaded dynamically at runtime using dlopen-like functionality. If no type is given explicitly the type is STATIC or SHARED based on whether the current value of the variable BUILD_SHARED_LIBS is ON . For SHARED and MODULE libraries the POSITION_INDEPENDENT_CODE target property is set to ON automatically. A SHARED library may be marked with the FRAMEWORK target property to create an macOS Framework.

New in version 3.8: A STATIC library may be marked with the FRAMEWORK target property to create a static Framework.

If a library does not export any symbols, it must not be declared as a SHARED library. For example, a Windows resource DLL or a managed C++/CLI DLL that exports no unmanaged symbols would need to be a MODULE library. This is because CMake expects a SHARED library to always have an associated import library on Windows.

By default the library file will be created in the build tree directory corresponding to the source tree directory in which the command was invoked. See documentation of the ARCHIVE_OUTPUT_DIRECTORY , LIBRARY_OUTPUT_DIRECTORY , and RUNTIME_OUTPUT_DIRECTORY target properties to change this location. See documentation of the OUTPUT_NAME target property to change the <name> part of the final file name.

If EXCLUDE_FROM_ALL is given the corresponding property will be set on the created target. See documentation of the EXCLUDE_FROM_ALL target property for details.

See the cmake-buildsystem(7) manual for more on defining buildsystem properties.

See also HEADER_FILE_ONLY on what to do if some sources are pre-processed, and you want to have the original sources reachable from within IDE.

Object Libraries¶

Creates an Object Library . An object library compiles source files but does not archive or link their object files into a library. Instead other targets created by add_library or add_executable() may reference the objects using an expression of the form $<TARGET_OBJECTS:objlib> as a source, where objlib is the object library name. For example:

will include objlib’s object files in a library and an executable along with those compiled from their own sources. Object libraries may contain only sources that compile, header files, and other files that would not affect linking of a normal library (e.g. .txt ). They may contain custom commands generating such sources, but not PRE_BUILD , PRE_LINK , or POST_BUILD commands. Some native build systems (such as Xcode) may not like targets that have only object files, so consider adding at least one real source file to any target that references $<TARGET_OBJECTS:objlib> .

New in version 3.12: Object libraries can be linked to with target_link_libraries() .

Interface Libraries¶

Creates an Interface Library . An INTERFACE library target does not compile sources and does not produce a library artifact on disk. However, it may have properties set on it and it may be installed and exported. Typically, INTERFACE_* properties are populated on an interface target using the commands:

and then it is used as an argument to target_link_libraries() like any other target.

An interface library created with the above signature has no source files itself and is not included as a target in the generated buildsystem.

New in version 3.15: An interface library can have PUBLIC_HEADER and PRIVATE_HEADER properties. The headers specified by those properties can be installed using the install(TARGETS) command.

New in version 3.19: An interface library target may be created with source files:

Source files may be listed directly in the add_library call or added later by calls to target_sources() with the PRIVATE or PUBLIC keywords.

If an interface library has source files (i.e. the SOURCES target property is set), or header sets (i.e. the HEADER_SETS target property is set), it will appear in the generated buildsystem as a build target much like a target defined by the add_custom_target() command. It does not compile any sources, but does contain build rules for custom commands created by the add_custom_command() command.

In most command signatures where the INTERFACE keyword appears, the items listed after it only become part of that target’s usage requirements and are not part of the target’s own settings. However, in this signature of add_library , the INTERFACE keyword refers to the library type only. Sources listed after it in the add_library call are PRIVATE to the interface library and do not appear in its INTERFACE_SOURCES target property.

Imported Libraries¶

Creates an IMPORTED library target called <name> . No rules are generated to build it, and the IMPORTED target property is True . The target name has scope in the directory in which it is created and below, but the GLOBAL option extends visibility. It may be referenced like any target built within the project. IMPORTED libraries are useful for convenient reference from commands like target_link_libraries() . Details about the imported library are specified by setting properties whose names begin in IMPORTED_ and INTERFACE_ .

The <type> must be one of:

STATIC , SHARED , MODULE , UNKNOWN

References a library file located outside the project. The IMPORTED_LOCATION target property (or its per-configuration variant IMPORTED_LOCATION_<CONFIG> ) specifies the location of the main library file on disk:

For a SHARED library on most non-Windows platforms, the main library file is the .so or .dylib file used by both linkers and dynamic loaders. If the referenced library file has a SONAME (or on macOS, has a LC_ID_DYLIB starting in @rpath/ ), the value of that field should be set in the IMPORTED_SONAME target property. If the referenced library file does not have a SONAME , but the platform supports it, then the IMPORTED_NO_SONAME target property should be set.

For a SHARED library on Windows, the IMPORTED_IMPLIB target property (or its per-configuration variant IMPORTED_IMPLIB_<CONFIG> ) specifies the location of the DLL import library file ( .lib or .dll.a ) on disk, and the IMPORTED_LOCATION is the location of the .dll runtime library (and is optional, but needed by the TARGET_RUNTIME_DLLS generator expression).

Additional usage requirements may be specified in INTERFACE_* properties.

An UNKNOWN library type is typically only used in the implementation of Find Modules . It allows the path to an imported library (often found using the find_library() command) to be used without having to know what type of library it is. This is especially useful on Windows where a static library and a DLL’s import library both have the same file extension.

References a set of object files located outside the project. The IMPORTED_OBJECTS target property (or its per-configuration variant IMPORTED_OBJECTS_<CONFIG> ) specifies the locations of object files on disk. Additional usage requirements may be specified in INTERFACE_* properties.

Does not reference any library or object files on disk, but may specify usage requirements in INTERFACE_* properties.

See documentation of the IMPORTED_* and INTERFACE_* properties for more information.

Alias Libraries¶

Creates an Alias Target , such that <name> can be used to refer to <target> in subsequent commands. The <name> does not appear in the generated buildsystem as a make target. The <target> may not be an ALIAS .

New in version 3.11: An ALIAS can target a GLOBAL Imported Target

New in version 3.18: An ALIAS can target a non- GLOBAL Imported Target. Such alias is scoped to the directory in which it is created and below. The ALIAS_GLOBAL target property can be used to check if the alias is global or not.

ALIAS targets can be used as linkable targets and as targets to read properties from. They can also be tested for existence with the regular if(TARGET) subcommand. The <name> may not be used to modify properties of <target> , that is, it may not be used as the operand of set_property() , set_target_properties() , target_link_libraries() etc. An ALIAS target may not be installed or exported.

Importing and Exporting Guide¶

In this guide, we will present the concept of 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¶

IMPORTED targets are used to convert files outside of a CMake project into logical targets inside of the project. IMPORTED targets are created using the IMPORTED option of the add_executable() and add_library() commands. No build files are generated for IMPORTED targets. Once imported, 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 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 IMPORTED target are specified by setting properties whose names begin in IMPORTED_ and INTERFACE_ . For example, 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 IMPORTED executable target and then references it from the 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 cmake and build and install the project.

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 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 IMPORTED target property will be set to true .

Читать:
Входящие подключения windows 7 что это

Next, set the IMPORTED_LOCATION property of the target using the 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.

We can now reference this 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 IMPORTED target in the add_custom_command() command:

As COMMAND specifies an executable target name, it will automatically be replaced by the location of the executable given by the IMPORTED_LOCATION property above.

Finally, use the output from add_custom_command() :

Importing Libraries¶

In a similar manner, libraries from other projects may be accessed through 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 IMPORTED library and specify its location on disk:

Then use the IMPORTED library inside of our project:

On Windows, a .dll and its .lib import library may be imported together:

A library with multiple configurations may be imported with a single target:

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 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 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:

And a corresponding source file MathFunctions.cxx :

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 cmake_minimum_required() version and project() name:

The 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 add_library() command:

And then use the target_include_directories() command to specify the include directories for the target:

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 generator expressions 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 install(TARGETS) and 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 install(TARGETS) command we will specify the target, the EXPORT name and the destinations that tell CMake where to install the targets.

Here, the EXPORT option tells CMake to create an export called MathFunctionsTargets . The generated IMPORTED targets have appropriate properties set to define their usage requirements , such as INTERFACE_INCLUDE_DIRECTORIES , INTERFACE_COMPILE_DEFINITIONS and other relevant built-in INTERFACE_ properties. The INTERFACE variant of user-defined properties listed in COMPATIBLE_INTERFACE_STRING and other Compatible Interface Properties are also propagated to the generated IMPORTED targets. For example, in this case, the IMPORTED target will have its 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 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 install(FILES) command. The header file should be installed to the include directory, as specified by the target_include_directories() command above.

Now that the MathFunctions library and header file are installed, we also need to explicitly install the MathFunctionsTargets export details. Use the install(EXPORT) command to export the targets in MathFunctionsTargets , as defined by the install(TARGETS) command.

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 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 IMPORTED library.

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 include() command and reference the MathFunctions library from the installation tree as if it were built in its own tree. For example:

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 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.

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 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 CMakePackageConfigHelpers module to get access to some helper functions for creating config files.

Then we will create a package configuration file and a package version file.

Creating a Package Configuration File¶

Use the configure_package_config_file() command provided by the CMakePackageConfigHelpers to generate the package configuration file. Note that this command should be used instead of the plain 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.

Install the generated configuration files with the INSTALL(files) command. Both MathFunctionsConfigVersion.cmake and MathFunctionsConfig.cmake are installed to the same location, completing the package.

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 IMPORTED targets.

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:

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.

The find_dependency macro from the 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 CMakePackageConfigHelpers module provides the write_basic_package_version_file() command for creating a simple package version file. This file is read by CMake when 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 cmake-packages documentation for more details.

In our example, MathFunctions_MAJOR_VERSION is defined as a 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 , cmake 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 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 :

Here we use the 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 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:

In the build directory, notice that the file MathFunctionsTargets.cmake has been created in the cmake subdirectory.

Now install the project:

Creating Relocatable Packages¶

Packages created by 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 CMAKE_INSTALL_PREFIX but should not explicitly include the CMAKE_INSTALL_PREFIX :

The $<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:

This also applies to paths referencing external dependencies. It is not advisable to populate any properties which may contain paths, such as INTERFACE_INCLUDE_DIRECTORIES or INTERFACE_LINK_LIBRARIES , with paths relevant to dependencies. For example, this code may not work well for a relocatable package:

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 IMPORTED targets that have their own IMPORTED_LOCATION and usage requirement properties such as INTERFACE_INCLUDE_DIRECTORIES populated appropriately. Those imported targets may then be used with the target_link_libraries() command for MathFunctions :

With this approach the package references its external dependencies only through the names of IMPORTED targets . When a consumer uses the installed package, the consumer will run the appropriate 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.

Cmake как подключить библиотеку

Now we will add a library to our project. This library will contain our own implementation for computing the square root of a number. The executable can then use this library instead of the standard square root function provided by the compiler.

For this tutorial we will put the library into a subdirectory called MathFunctions . This directory already contains a header file, MathFunctions.h , and a source file mysqrt.cxx . The source file has one function called mysqrt that provides similar functionality to the compiler’s sqrt function.

Add the following one line CMakeLists.txt file to the MathFunctions directory:

To make use of the new library we will add an add_subdirectory() call in the top-level CMakeLists.txt file so that the library will get built. We add the new library to the executable, and add MathFunctions as an include directory so that the MathFunctions.h header file can be found. The last few lines of the top-level CMakeLists.txt file should now look like:

Now let us make the MathFunctions library optional. While for the tutorial there really isn’t any need to do so, for larger projects this is a common occurrence. The first step is to add an option to the top-level CMakeLists.txt file.

This option will be displayed in the cmake-gui and ccmake with a default value of ON that can be changed by the user. This setting will be stored in the cache so that the user does not need to set the value each time they run CMake on a build directory.

The next change is to make building and linking the MathFunctions library conditional. To do this, we will create an if statement which checks the value of the option. Inside the if block, put the add_subdirectory() command from above with some additional list commands to store information needed to link to the library and add the subdirectory as an include directory in the Tutorial target. The end of the top-level CMakeLists.txt file will now look like the following:

Note the use of the variable EXTRA_LIBS to collect up any optional libraries to later be linked into the executable. The variable EXTRA_INCLUDES is used similarly for optional header files. This is a classic approach when dealing with many optional components, we will cover the modern approach in the next step.

The corresponding changes to the source code are fairly straightforward. First, in tutorial.cxx , include the MathFunctions.h header if we need it:

Then, in the same file, make USE_MYMATH control which square root function is used:

Since the source code now requires USE_MYMATH we can add it to TutorialConfig.h.in with the following line:

Exercise: Why is it important that we configure TutorialConfig.h.in after the option for USE_MYMATH ? What would happen if we inverted the two?

Run the cmake executable or the cmake-gui to configure the project and then build it with your chosen build tool. Then run the built Tutorial executable.

Now let’s update the value of USE_MYMATH . The easiest way is to use the cmake-gui or ccmake if you’re in the terminal. Or, alternatively, if you want to change the option from the command-line, try:

Related Posts