diff options
Diffstat (limited to 'Help/guide')
30 files changed, 558 insertions, 318 deletions
diff --git a/Help/guide/ide-integration/index.rst b/Help/guide/ide-integration/index.rst index 779883b..8473481 100644 --- a/Help/guide/ide-integration/index.rst +++ b/Help/guide/ide-integration/index.rst @@ -65,6 +65,12 @@ run: cmake -S /path/to/source -B /path/to/source/build -G Ninja +In cases where a preset contains lots of cache variables, and passing all of +them as ``-D`` flags would cause the command line length limit of the platform +to be exceeded, the IDE should instead construct a temporary cache script and +pass it with the ``-C`` flag. See :ref:`CMake Options` for details on how the +``-C`` flag is used. + While reading, parsing, and evaluating the contents of ``CMakePresets.json`` is straightforward, it is not trivial. In addition to the documentation, IDE vendors may also wish to refer to the CMake source code and test cases for a @@ -124,3 +130,31 @@ obtain this information and use it to present the user with a list of tests. IDEs should not invoke the ``test`` target of the generated buildsystem. Instead, they should invoke :manual:`ctest(1)` directly. + +IDEs with CMake integration +=========================== + +The following IDEs support CMake natively: + +* `CLion`_ +* `KDevelop`_ +* `QtCreator`_ +* `Vim`_ (via a plugin) +* `Visual Studio`_ +* `VSCode`_ (via a plugin) + +.. _CLion: https://www.jetbrains.com/clion/ +.. _KDevelop: https://www.kdevelop.org/ +.. _QtCreator: https://www.qt.io/product/development-tools +.. _Vim: https://www.vim.org/ +.. _Visual Studio: https://visualstudio.microsoft.com/ +.. _VSCode: https://code.visualstudio.com/ + +Additionally, CMake has builtin support for some IDEs: + +* :ref:`IDE Build Tool Generators`: + Generate IDE native build systems such as Visual Studio or Xcode. +* :ref:`Extra Generators`: + Extend :ref:`Command-Line Build Tool Generators` to generate IDE + project files that hook into the command-line build system. + Superseded by the :manual:`File API <cmake-file-api(7)>`. diff --git a/Help/guide/importing-exporting/MathFunctionsComponents/Config.cmake.in b/Help/guide/importing-exporting/MathFunctionsComponents/Config.cmake.in index 09f6c35..a535969 100644 --- a/Help/guide/importing-exporting/MathFunctionsComponents/Config.cmake.in +++ b/Help/guide/importing-exporting/MathFunctionsComponents/Config.cmake.in @@ -1,9 +1,9 @@ @PACKAGE_INIT@ -set(_supported_components Addition SquareRoot) +set(_MathFunctions_supported_components Addition SquareRoot) foreach(_comp ${MathFunctions_FIND_COMPONENTS}) - if (NOT _comp IN_LIST _supported_components) + if (NOT _comp IN_LIST _MathFunctions_supported_components) set(MathFunctions_FOUND False) set(MathFunctions_NOT_FOUND_MESSAGE "Unsupported component: ${_comp}") endif() diff --git a/Help/guide/tutorial/A Basic Starting Point.rst b/Help/guide/tutorial/A Basic Starting Point.rst index cf1ec01..d57cc35 100644 --- a/Help/guide/tutorial/A Basic Starting Point.rst +++ b/Help/guide/tutorial/A Basic Starting Point.rst @@ -19,8 +19,19 @@ required. This will be the starting point for our tutorial. Create a add_executable(Tutorial tutorial.cxx) -Note that this example uses lower case commands in the ``CMakeLists.txt`` file. -Upper, lower, and mixed case commands are supported by CMake. The source +Any project's top most ``CMakeLists.txt`` must start by specifying +a minimum CMake version using :command:`cmake_minimum_required`. This ensures +that the later CMake functions are run with a compatible version of CMake. + +To start a project, we use :command:`project` to set the project name. This +call is required with every project and should be called soon after +:command:`cmake_minimum_required`. + +Lastly, we use :command:`add_executable` to specify we want an executable +named Tutorial generated using ``tutorial.cxx`` as the source. + +Note that this example uses lower case commands in the ``CMakeLists.txt`` +file. Upper, lower, and mixed case commands are supported by CMake. The source code for ``tutorial.cxx`` is provided in the ``Step1`` directory and can be used to compute the square root of a number. @@ -79,7 +90,7 @@ to set the project name and version number. :language: cmake :end-before: # specify the C++ standard -Then, configure a header file to pass the version number to the source +Then use :command:`configure_file` to pass the version number to the source code: .. literalinclude:: Step2/CMakeLists.txt @@ -91,7 +102,8 @@ code: Since the configured file will be written into the binary tree, we must add that directory to the list of paths to search for include -files. Add the following lines to the end of the ``CMakeLists.txt`` file: +files. Use :command:`target_include_directories` to add the following lines to +the end of the ``CMakeLists.txt`` file: .. literalinclude:: Step2/CMakeLists.txt :caption: CMakeLists.txt @@ -107,9 +119,9 @@ directory with the following contents: :name: TutorialConfig.h.in :language: c++ -When CMake configures this header file the values for +When CMake configures this header file, the values for ``@Tutorial_VERSION_MAJOR@`` and ``@Tutorial_VERSION_MINOR@`` will be -replaced. +replaced with the corresponding version numbers from the project. Next modify ``tutorial.cxx`` to include the configured header file, ``TutorialConfig.h``. @@ -141,7 +153,7 @@ Next let's add some C++11 features to our project by replacing ``atof`` with We will need to explicitly state in the CMake code that it should use the correct flags. The easiest way to enable support for a specific C++ standard in CMake is by using the :variable:`CMAKE_CXX_STANDARD` variable. For this -tutorial, set the :variable:`CMAKE_CXX_STANDARD` variable in the +tutorial, :command:`set` the :variable:`CMAKE_CXX_STANDARD` variable in the ``CMakeLists.txt`` file to ``11`` and :variable:`CMAKE_CXX_STANDARD_REQUIRED` to ``True``. Make sure to add the ``CMAKE_CXX_STANDARD`` declarations above the call to ``add_executable``. diff --git a/Help/guide/tutorial/Adding Support for a Testing Dashboard.rst b/Help/guide/tutorial/Adding Support for a Testing Dashboard.rst index c6e0fd0..9ec195c 100644 --- a/Help/guide/tutorial/Adding Support for a Testing Dashboard.rst +++ b/Help/guide/tutorial/Adding Support for a Testing Dashboard.rst @@ -1,4 +1,4 @@ -Step 8: Adding Support for a Testing Dashboard +Step 5: Adding Support for a Testing Dashboard ============================================== Adding support for submitting our test results to a dashboard is simple. We @@ -9,21 +9,21 @@ we include the :module:`CTest` module in our top-level ``CMakeLists.txt``. Replace: -.. code-block:: cmake +.. literalinclude:: Step5/CMakeLists.txt :caption: CMakeLists.txt :name: CMakeLists.txt-enable_testing-remove - - # enable testing - enable_testing() + :language: cmake + :start-after: # enable testing + :end-before: # does the application run With: -.. code-block:: cmake +.. literalinclude:: Step6/CMakeLists.txt :caption: CMakeLists.txt :name: CMakeLists.txt-include-CTest - - # enable dashboard scripting - include(CTest) + :language: cmake + :start-after: # enable testing + :end-before: # does the application run The :module:`CTest` module will automatically call ``enable_testing()``, so we can remove it from our CMake files. @@ -46,7 +46,7 @@ downloaded from the ``Settings`` page of the project on the CDash instance that will host and display the test results. Once downloaded from CDash, the file should not be modified locally. -.. literalinclude:: Step9/CTestConfig.cmake +.. literalinclude:: Step6/CTestConfig.cmake :caption: CTestConfig.cmake :name: CTestConfig.cmake :language: cmake diff --git a/Help/guide/tutorial/Adding System Introspection.rst b/Help/guide/tutorial/Adding System Introspection.rst index e149110..710e979 100644 --- a/Help/guide/tutorial/Adding System Introspection.rst +++ b/Help/guide/tutorial/Adding System Introspection.rst @@ -1,4 +1,4 @@ -Step 5: Adding System Introspection +Step 6: Adding System Introspection =================================== Let us consider adding some code to our project that depends on features the @@ -9,17 +9,15 @@ tutorial assume that they are not common. If the platform has ``log`` and ``exp`` then we will use them to compute the square root in the ``mysqrt`` function. We first test for the availability of -these functions using the :module:`CheckSymbolExists` module in -``MathFunctions/CMakeLists.txt``. On some platforms, we will need to link to -the ``m`` library. If ``log`` and ``exp`` are not initially found, require the -``m`` library and try again. +these functions using the :module:`CheckCXXSourceCompiles` module in +``MathFunctions/CMakeLists.txt``. Add the checks for ``log`` and ``exp`` to ``MathFunctions/CMakeLists.txt``, after the call to :command:`target_include_directories`: -.. literalinclude:: Step6/MathFunctions/CMakeLists.txt +.. literalinclude:: Step7/MathFunctions/CMakeLists.txt :caption: MathFunctions/CMakeLists.txt - :name: MathFunctions/CMakeLists.txt-check_symbol_exists + :name: MathFunctions/CMakeLists.txt-check_cxx_source_compiles :language: cmake :start-after: # to find MathFunctions.h, while we don't. :end-before: # add compile definitions @@ -27,7 +25,7 @@ after the call to :command:`target_include_directories`: If available, use :command:`target_compile_definitions` to specify ``HAVE_LOG`` and ``HAVE_EXP`` as ``PRIVATE`` compile definitions. -.. literalinclude:: Step6/MathFunctions/CMakeLists.txt +.. literalinclude:: Step7/MathFunctions/CMakeLists.txt :caption: MathFunctions/CMakeLists.txt :name: MathFunctions/CMakeLists.txt-target_compile_definitions :language: cmake @@ -39,7 +37,7 @@ compute the square root in the ``mysqrt`` function. Add the following code to the ``mysqrt`` function in ``MathFunctions/mysqrt.cxx`` (don't forget the ``#endif`` before returning the result!): -.. literalinclude:: Step6/MathFunctions/mysqrt.cxx +.. literalinclude:: Step7/MathFunctions/mysqrt.cxx :caption: MathFunctions/mysqrt.cxx :name: MathFunctions/mysqrt.cxx-ifdef :language: c++ @@ -48,7 +46,7 @@ the ``mysqrt`` function in ``MathFunctions/mysqrt.cxx`` (don't forget the We will also need to modify ``mysqrt.cxx`` to include ``cmath``. -.. literalinclude:: Step6/MathFunctions/mysqrt.cxx +.. literalinclude:: Step7/MathFunctions/mysqrt.cxx :caption: MathFunctions/mysqrt.cxx :name: MathFunctions/mysqrt.cxx-include-cmath :language: c++ diff --git a/Help/guide/tutorial/Adding a Custom Command and Generated File.rst b/Help/guide/tutorial/Adding a Custom Command and Generated File.rst index 70c6695..6dc4761 100644 --- a/Help/guide/tutorial/Adding a Custom Command and Generated File.rst +++ b/Help/guide/tutorial/Adding a Custom Command and Generated File.rst @@ -1,4 +1,4 @@ -Step 6: Adding a Custom Command and Generated File +Step 7: Adding a Custom Command and Generated File ================================================== Suppose, for the purpose of this tutorial, we decide that we never want to use @@ -26,7 +26,7 @@ accomplish this. First, at the top of ``MathFunctions/CMakeLists.txt``, the executable for ``MakeTable`` is added as any other executable would be added. -.. literalinclude:: Step7/MathFunctions/CMakeLists.txt +.. literalinclude:: Step8/MathFunctions/CMakeLists.txt :caption: MathFunctions/CMakeLists.txt :name: MathFunctions/CMakeLists.txt-add_executable-MakeTable :language: cmake @@ -36,7 +36,7 @@ First, at the top of ``MathFunctions/CMakeLists.txt``, the executable for Then we add a custom command that specifies how to produce ``Table.h`` by running MakeTable. -.. literalinclude:: Step7/MathFunctions/CMakeLists.txt +.. literalinclude:: Step8/MathFunctions/CMakeLists.txt :caption: MathFunctions/CMakeLists.txt :name: MathFunctions/CMakeLists.txt-add_custom_command-Table.h :language: cmake @@ -47,7 +47,7 @@ Next we have to let CMake know that ``mysqrt.cxx`` depends on the generated file ``Table.h``. This is done by adding the generated ``Table.h`` to the list of sources for the library MathFunctions. -.. literalinclude:: Step7/MathFunctions/CMakeLists.txt +.. literalinclude:: Step8/MathFunctions/CMakeLists.txt :caption: MathFunctions/CMakeLists.txt :name: MathFunctions/CMakeLists.txt-add_library-Table.h :language: cmake @@ -57,7 +57,7 @@ of sources for the library MathFunctions. We also have to add the current binary directory to the list of include directories so that ``Table.h`` can be found and included by ``mysqrt.cxx``. -.. literalinclude:: Step7/MathFunctions/CMakeLists.txt +.. literalinclude:: Step8/MathFunctions/CMakeLists.txt :caption: MathFunctions/CMakeLists.txt :name: MathFunctions/CMakeLists.txt-target_include_directories-Table.h :language: cmake @@ -67,7 +67,7 @@ directories so that ``Table.h`` can be found and included by ``mysqrt.cxx``. Now let's use the generated table. First, modify ``mysqrt.cxx`` to include ``Table.h``. Next, we can rewrite the ``mysqrt`` function to use the table: -.. literalinclude:: Step7/MathFunctions/mysqrt.cxx +.. literalinclude:: Step8/MathFunctions/mysqrt.cxx :caption: MathFunctions/mysqrt.cxx :name: MathFunctions/mysqrt.cxx :language: c++ diff --git a/Help/guide/tutorial/Adding a Library.rst b/Help/guide/tutorial/Adding a Library.rst index ed03448..71755be 100644 --- a/Help/guide/tutorial/Adding a Library.rst +++ b/Help/guide/tutorial/Adding a Library.rst @@ -23,8 +23,9 @@ directory: To make use of the new library we will add an :command:`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 ``mysqrt.h`` header file can be found. The -last few lines of the top-level ``CMakeLists.txt`` file should now look like: +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: .. code-block:: cmake :caption: CMakeLists.txt diff --git a/Help/guide/tutorial/Complete/CMakeLists.txt b/Help/guide/tutorial/Complete/CMakeLists.txt index ac1d083..41baf64 100644 --- a/Help/guide/tutorial/Complete/CMakeLists.txt +++ b/Help/guide/tutorial/Complete/CMakeLists.txt @@ -10,7 +10,7 @@ target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11) # add compiler warning flags just when building this project via # the BUILD_INTERFACE genex -set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU>") +set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU,LCC>") set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>") target_compile_options(tutorial_compiler_flags INTERFACE "$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>" @@ -88,6 +88,7 @@ include(InstallRequiredSystemLibraries) set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt") set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}") set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}") +set(CPACK_SOURCE_GENERATOR "TGZ") include(CPack) # install the configuration targets diff --git a/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt index a47d5e0..40b9fd2 100644 --- a/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt @@ -62,6 +62,6 @@ if(TARGET SqrtLibrary) list(APPEND installable_libs SqrtLibrary) endif() install(TARGETS ${installable_libs} - DESTINATION lib - EXPORT MathFunctionsTargets) + EXPORT MathFunctionsTargets + DESTINATION lib) install(FILES MathFunctions.h DESTINATION include) diff --git a/Help/guide/tutorial/Packaging an Installer.rst b/Help/guide/tutorial/Packaging an Installer.rst index 5eb3e3e..5f0b27a 100644 --- a/Help/guide/tutorial/Packaging an Installer.rst +++ b/Help/guide/tutorial/Packaging an Installer.rst @@ -1,4 +1,4 @@ -Step 7: Packaging an Installer +Step 8: Packaging an Installer ============================== Next suppose that we want to distribute our project to other people so that @@ -11,7 +11,7 @@ installations and package management features. To accomplish this we will use CPack to create platform specific installers. Specifically we need to add a few lines to the bottom of our top-level ``CMakeLists.txt`` file. -.. literalinclude:: Step8/CMakeLists.txt +.. literalinclude:: Step9/CMakeLists.txt :caption: CMakeLists.txt :name: CMakeLists.txt-include-CPack :language: cmake @@ -22,8 +22,9 @@ That is all there is to it. We start by including libraries that are needed by the project for the current platform. Next we set some CPack variables to where we have stored the license and version information for this project. The version information was set earlier in this -tutorial and the ``license.txt`` has been included in the top-level source -directory for this step. +tutorial and the ``License.txt`` has been included in the top-level source +directory for this step. The :variable:`CPACK_SOURCE_GENERATOR` variable +selects a file format for the source package. Finally we include the :module:`CPack module <CPack>` which will use these variables and some other properties of the current system to setup an @@ -44,7 +45,11 @@ To specify the generator, use the ``-G`` option. For multi-config builds, use cpack -G ZIP -C Debug -To create a source distribution you would type: +For a list of available generators, see :manual:`cpack-generators(7)` or call +``cpack --help``. An :cpack_gen:`archive generator <CPack Archive Generator>` +like ZIP creates a compressed archive of all *installed* files. + +To create an archive of the *full* source tree you would type: .. code-block:: console diff --git a/Help/guide/tutorial/Step10/CMakeLists.txt b/Help/guide/tutorial/Step10/CMakeLists.txt index dc9a0e8..55dc409 100644 --- a/Help/guide/tutorial/Step10/CMakeLists.txt +++ b/Help/guide/tutorial/Step10/CMakeLists.txt @@ -70,4 +70,5 @@ include(InstallRequiredSystemLibraries) set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt") set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}") set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}") +set(CPACK_SOURCE_GENERATOR "TGZ") include(CPack) diff --git a/Help/guide/tutorial/Step11/CMakeLists.txt b/Help/guide/tutorial/Step11/CMakeLists.txt index 10f35ce..1044748 100644 --- a/Help/guide/tutorial/Step11/CMakeLists.txt +++ b/Help/guide/tutorial/Step11/CMakeLists.txt @@ -8,7 +8,7 @@ target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11) # add compiler warning flags just when building this project via # the BUILD_INTERFACE genex -set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU>") +set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU,LCC>") set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>") target_compile_options(tutorial_compiler_flags INTERFACE "$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>" @@ -78,4 +78,5 @@ include(InstallRequiredSystemLibraries) set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt") set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}") set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}") +set(CPACK_SOURCE_GENERATOR "TGZ") include(CPack) diff --git a/Help/guide/tutorial/Step12/CMakeLists.txt b/Help/guide/tutorial/Step12/CMakeLists.txt index 634b84c..63f9643 100644 --- a/Help/guide/tutorial/Step12/CMakeLists.txt +++ b/Help/guide/tutorial/Step12/CMakeLists.txt @@ -8,7 +8,7 @@ target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11) # add compiler warning flags just when building this project via # the BUILD_INTERFACE genex -set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU>") +set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU,LCC>") set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>") target_compile_options(tutorial_compiler_flags INTERFACE "$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>" diff --git a/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt index ea3861c..d5961da 100644 --- a/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt @@ -58,6 +58,6 @@ if(TARGET SqrtLibrary) list(APPEND installable_libs SqrtLibrary) endif() install(TARGETS ${installable_libs} - DESTINATION lib - EXPORT MathFunctionsTargets) + EXPORT MathFunctionsTargets + DESTINATION lib) install(FILES MathFunctions.h DESTINATION include) diff --git a/Help/guide/tutorial/Step5/CTestConfig.cmake b/Help/guide/tutorial/Step5/CTestConfig.cmake new file mode 100644 index 0000000..73efdb1 --- /dev/null +++ b/Help/guide/tutorial/Step5/CTestConfig.cmake @@ -0,0 +1,7 @@ +set(CTEST_PROJECT_NAME "CMakeTutorial") +set(CTEST_NIGHTLY_START_TIME "00:00:00 EST") + +set(CTEST_DROP_METHOD "http") +set(CTEST_DROP_SITE "my.cdash.org") +set(CTEST_DROP_LOCATION "/submit.php?project=CMakeTutorial") +set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/Help/guide/tutorial/Step6/CMakeLists.txt b/Help/guide/tutorial/Step6/CMakeLists.txt index 82d00c8..3ac5cd6 100644 --- a/Help/guide/tutorial/Step6/CMakeLists.txt +++ b/Help/guide/tutorial/Step6/CMakeLists.txt @@ -37,7 +37,7 @@ install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h" ) # enable testing -enable_testing() +include(CTest) # does the application run add_test(NAME Runs COMMAND Tutorial 25) diff --git a/Help/guide/tutorial/Step6/CTestConfig.cmake b/Help/guide/tutorial/Step6/CTestConfig.cmake new file mode 100644 index 0000000..73efdb1 --- /dev/null +++ b/Help/guide/tutorial/Step6/CTestConfig.cmake @@ -0,0 +1,7 @@ +set(CTEST_PROJECT_NAME "CMakeTutorial") +set(CTEST_NIGHTLY_START_TIME "00:00:00 EST") + +set(CTEST_DROP_METHOD "http") +set(CTEST_DROP_SITE "my.cdash.org") +set(CTEST_DROP_LOCATION "/submit.php?project=CMakeTutorial") +set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt index f64c6ac..b12f27d 100644 --- a/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt @@ -6,27 +6,6 @@ target_include_directories(MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ) -# does this system provide the log and exp functions? -include(CheckSymbolExists) -check_symbol_exists(log "math.h" HAVE_LOG) -check_symbol_exists(exp "math.h" HAVE_EXP) -if(NOT (HAVE_LOG AND HAVE_EXP)) - unset(HAVE_LOG CACHE) - unset(HAVE_EXP CACHE) - set(CMAKE_REQUIRED_LIBRARIES "m") - check_symbol_exists(log "math.h" HAVE_LOG) - check_symbol_exists(exp "math.h" HAVE_EXP) - if(HAVE_LOG AND HAVE_EXP) - target_link_libraries(MathFunctions PRIVATE m) - endif() -endif() - -# add compile definitions -if(HAVE_LOG AND HAVE_EXP) - target_compile_definitions(MathFunctions - PRIVATE "HAVE_LOG" "HAVE_EXP") -endif() - # install rules install(TARGETS MathFunctions DESTINATION lib) install(FILES MathFunctions.h DESTINATION include) diff --git a/Help/guide/tutorial/Step6/MathFunctions/MakeTable.cxx b/Help/guide/tutorial/Step6/MathFunctions/MakeTable.cxx deleted file mode 100644 index ee58556..0000000 --- a/Help/guide/tutorial/Step6/MathFunctions/MakeTable.cxx +++ /dev/null @@ -1,25 +0,0 @@ -// A simple program that builds a sqrt table -#include <cmath> -#include <fstream> -#include <iostream> - -int main(int argc, char* argv[]) -{ - // make sure we have enough arguments - if (argc < 2) { - return 1; - } - - std::ofstream fout(argv[1], std::ios_base::out); - const bool fileOpen = fout.is_open(); - if (fileOpen) { - fout << "double sqrtTable[] = {" << std::endl; - for (int i = 0; i < 10; ++i) { - fout << sqrt(static_cast<double>(i)) << "," << std::endl; - } - // close the table with a zero - fout << "0};" << std::endl; - fout.close(); - } - return fileOpen ? 0 : 1; // return 0 if wrote the file -} diff --git a/Help/guide/tutorial/Step6/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step6/MathFunctions/mysqrt.cxx index 0637063..abe767d 100644 --- a/Help/guide/tutorial/Step6/MathFunctions/mysqrt.cxx +++ b/Help/guide/tutorial/Step6/MathFunctions/mysqrt.cxx @@ -1,4 +1,3 @@ -#include <cmath> #include <iostream> #include "MathFunctions.h" @@ -10,12 +9,6 @@ double mysqrt(double x) return 0; } - // if we have both log and exp then use them -#if defined(HAVE_LOG) && defined(HAVE_EXP) - double result = exp(log(x) * 0.5); - std::cout << "Computing sqrt of " << x << " to be " << result - << " using log and exp" << std::endl; -#else double result = x; // do ten iterations @@ -27,6 +20,5 @@ double mysqrt(double x) result = result + 0.5 * delta / result; std::cout << "Computing sqrt of " << x << " to be " << result << std::endl; } -#endif return result; } diff --git a/Help/guide/tutorial/Step7/CMakeLists.txt b/Help/guide/tutorial/Step7/CMakeLists.txt index 82d00c8..3ac5cd6 100644 --- a/Help/guide/tutorial/Step7/CMakeLists.txt +++ b/Help/guide/tutorial/Step7/CMakeLists.txt @@ -37,7 +37,7 @@ install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h" ) # enable testing -enable_testing() +include(CTest) # does the application run add_test(NAME Runs COMMAND Tutorial 25) diff --git a/Help/guide/tutorial/Step7/CTestConfig.cmake b/Help/guide/tutorial/Step7/CTestConfig.cmake new file mode 100644 index 0000000..73efdb1 --- /dev/null +++ b/Help/guide/tutorial/Step7/CTestConfig.cmake @@ -0,0 +1,7 @@ +set(CTEST_PROJECT_NAME "CMakeTutorial") +set(CTEST_NIGHTLY_START_TIME "00:00:00 EST") + +set(CTEST_DROP_METHOD "http") +set(CTEST_DROP_SITE "my.cdash.org") +set(CTEST_DROP_LOCATION "/submit.php?project=CMakeTutorial") +set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/Help/guide/tutorial/Step7/License.txt b/Help/guide/tutorial/Step7/License.txt deleted file mode 100644 index c62d00b..0000000 --- a/Help/guide/tutorial/Step7/License.txt +++ /dev/null @@ -1,2 +0,0 @@ -This is the open source License.txt file introduced in -CMake/Tutorial/Step7... diff --git a/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt index 9ede4b3..42e098a 100644 --- a/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt @@ -1,29 +1,34 @@ -# first we add the executable that generates the table -add_executable(MakeTable MakeTable.cxx) - -# add the command to generate the source code -add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h - COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h - DEPENDS MakeTable - ) - -# add the main library -add_library(MathFunctions - mysqrt.cxx - ${CMAKE_CURRENT_BINARY_DIR}/Table.h - ) +add_library(MathFunctions mysqrt.cxx) # state that anybody linking to us needs to include the current source dir # to find MathFunctions.h, while we don't. -# state that we depend on Tutorial_BINARY_DIR but consumers don't, as the -# TutorialConfig.h include is an implementation detail -# state that we depend on our binary dir to find Table.h target_include_directories(MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} - PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ) +# does this system provide the log and exp functions? +include(CheckCXXSourceCompiles) +check_cxx_source_compiles(" + #include <cmath> + int main() { + std::log(1.0); + return 0; + } +" HAVE_LOG) +check_cxx_source_compiles(" + #include <cmath> + int main() { + std::exp(1.0); + return 0; + } +" HAVE_EXP) + +# add compile definitions +if(HAVE_LOG AND HAVE_EXP) + target_compile_definitions(MathFunctions + PRIVATE "HAVE_LOG" "HAVE_EXP") +endif() + # install rules install(TARGETS MathFunctions DESTINATION lib) install(FILES MathFunctions.h DESTINATION include) diff --git a/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx index 7d80ee9..7eecd26 100644 --- a/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx +++ b/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx @@ -1,10 +1,8 @@ +#include <cmath> #include <iostream> #include "MathFunctions.h" -// include the generated table -#include "Table.h" - // a hack square root calculation using simple operations double mysqrt(double x) { @@ -12,12 +10,13 @@ double mysqrt(double x) return 0; } - // use the table to help find an initial value + // if we have both log and exp then use them +#if defined(HAVE_LOG) && defined(HAVE_EXP) + double result = std::exp(std::log(x) * 0.5); + std::cout << "Computing sqrt of " << x << " to be " << result + << " using log and exp" << std::endl; +#else double result = x; - if (x >= 1 && x < 10) { - std::cout << "Use the table to help find an initial value " << std::endl; - result = sqrtTable[static_cast<int>(x)]; - } // do ten iterations for (int i = 0; i < 10; ++i) { @@ -28,6 +27,6 @@ double mysqrt(double x) result = result + 0.5 * delta / result; std::cout << "Computing sqrt of " << x << " to be " << result << std::endl; } - +#endif return result; } diff --git a/Help/guide/tutorial/Step8/CMakeLists.txt b/Help/guide/tutorial/Step8/CMakeLists.txt index 4ae898f..3ac5cd6 100644 --- a/Help/guide/tutorial/Step8/CMakeLists.txt +++ b/Help/guide/tutorial/Step8/CMakeLists.txt @@ -37,7 +37,7 @@ install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h" ) # enable testing -enable_testing() +include(CTest) # does the application run add_test(NAME Runs COMMAND Tutorial 25) @@ -64,10 +64,3 @@ do_test(Tutorial 7 "7 is 2.645") do_test(Tutorial 25 "25 is 5") do_test(Tutorial -25 "-25 is (-nan|nan|0)") do_test(Tutorial 0.0001 "0.0001 is 0.01") - -# setup installer -include(InstallRequiredSystemLibraries) -set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt") -set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}") -set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}") -include(CPack) diff --git a/Help/guide/tutorial/Step9/CMakeLists.txt b/Help/guide/tutorial/Step9/CMakeLists.txt index 130bc9a..b13a662 100644 --- a/Help/guide/tutorial/Step9/CMakeLists.txt +++ b/Help/guide/tutorial/Step9/CMakeLists.txt @@ -65,8 +65,10 @@ do_test(Tutorial 25 "25 is 5") do_test(Tutorial -25 "-25 is (-nan|nan|0)") do_test(Tutorial 0.0001 "0.0001 is 0.01") +# setup installer include(InstallRequiredSystemLibraries) set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt") set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}") set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}") +set(CPACK_SOURCE_GENERATOR "TGZ") include(CPack) diff --git a/Help/guide/tutorial/index.rst b/Help/guide/tutorial/index.rst index 8b20a2d..65d4829 100644 --- a/Help/guide/tutorial/index.rst +++ b/Help/guide/tutorial/index.rst @@ -11,8 +11,9 @@ work together in an example project can be very helpful. Steps ===== -The tutorial documentation and source code for examples can be found in -the ``Help/guide/tutorial`` directory of the CMake source code tree. +.. include:: source.txt + +|tutorial_source| Each step has its own subdirectory containing code that may be used as a starting point. The tutorial examples are progressive so that each step provides the complete solution for the previous step. @@ -24,10 +25,10 @@ provides the complete solution for the previous step. Adding a Library Adding Usage Requirements for a Library Installing and Testing + Adding Support for a Testing Dashboard Adding System Introspection Adding a Custom Command and Generated File Packaging an Installer - Adding Support for a Testing Dashboard Selecting Static or Shared Libraries Adding Generator Expressions Adding Export Configuration diff --git a/Help/guide/tutorial/source.txt b/Help/guide/tutorial/source.txt new file mode 100644 index 0000000..bb45e86 --- /dev/null +++ b/Help/guide/tutorial/source.txt @@ -0,0 +1,3 @@ +.. |tutorial_source| replace:: + The tutorial documentation and source code examples can be found in + the ``Help/guide/tutorial`` directory of the CMake source code tree. diff --git a/Help/guide/using-dependencies/index.rst b/Help/guide/using-dependencies/index.rst index f4d7845..bb519ad 100644 --- a/Help/guide/using-dependencies/index.rst +++ b/Help/guide/using-dependencies/index.rst @@ -8,193 +8,412 @@ Using Dependencies Guide Introduction ============ -For developers wishing to use CMake to consume a third -party binary package, there are multiple possibilities -regarding how to optimally do so, depending on how -CMake-aware the third-party library is. - -CMake files provided with a software package contain -instructions for finding each build dependency. Some -build dependencies are optional in that the build may -succeed with a different feature set if the dependency -is missing, and some dependencies are required. CMake -searches well-known locations for each dependency, and -the provided software may supply additional hints or -locations to CMake to find each dependency. - -If a required dependency is not found by -:manual:`cmake(1)`, the cache is populated with an entry -which contains a ``NOTFOUND`` value. This value can be -replaced by specifying it on the command line, or in -the :manual:`ccmake(1)` or :manual:`cmake-gui(1)` tool. -See the :guide:`User Interaction Guide` for -more about setting cache entries. - -Libraries providing Config-file packages -======================================== - -The most convenient way for a third-party to provide library -binaries for use with CMake is to provide -:ref:`Config File Packages`. These packages are text files -shipped with the library which instruct CMake how to use the -library binaries and associated headers, helper tools and -CMake macros provided by the library. - -The config files can usually be found in a directory whose -name matches the pattern ``lib/cmake/<PackageName>``, though -they may be in other locations instead. The -``<PackageName>`` corresponds to use in CMake code with the -:command:`find_package` command such as -``find_package(PackageName REQUIRED)``. - -The ``lib/cmake/<PackageName>`` directory will contain a -file which is either named ``<PackageName>Config.cmake`` -or ``<PackageName>-config.cmake``. This is the entry point +Projects will frequently depend on other projects, assets, and artifacts. +CMake provides a number of ways to incorporate such things into the build. +Projects and users have the flexibility to choose between methods that +best suit their needs. + +The primary methods of bringing dependencies into the build are the +:command:`find_package` command and the :module:`FetchContent` module. +The :module:`FindPkgConfig` module is also sometimes used, although it +lacks some of the integration of the other two and is not discussed any +further in this guide. + +Dependencies can also be made available by a custom +:ref:`dependency provider <dependency_providers>`. +This might be a third party package manager, or it might be custom code +implemented by the developer. Dependency providers co-operate with the +primary methods mentioned above to extend their flexibility. + +.. _prebuilt_find_package: + +Using Pre-built Packages With ``find_package()`` +================================================ + +A package needed by the project may already be built and available at some +location on the user's system. That package might have also been built by +CMake, or it could have used a different build system entirely. It might +even just be a collection of files that didn't need to be built at all. +CMake provides the :command:`find_package` command for these scenarios. +It searches well-known locations, along with additional hints and paths +provided by the project or user. It also supports package components and +packages being optional. Result variables are provided to allow the project +to customize its own behavior according to whether the package or specific +components were found. + +In most cases, projects should generally use the :ref:`basic signature`. +Most of the time, this will involve just the package name, maybe a version +constraint, and the ``REQUIRED`` keyword if the dependency is not optional. +A set of package components may also be specified. + +.. code-block:: cmake + :caption: Examples of ``find_package()`` basic signature + + find_package(Catch2) + find_package(GTest REQUIRED) + find_package(Boost 1.79 COMPONENTS date_time) + +The :command:`find_package` command supports two main methods for carrying +out the search: + +**Config mode** + With this method, the command looks for files that are typically provided + by the package itself. This is the more reliable method of the two, since + the package details should always be in sync with the package. + +**Module mode** + Not all packages are CMake-aware. Many don't provide the files needed to + support config mode. For such cases, a Find module file can be provided + separately, either by the project or by CMake. A Find module is typically + a heuristic implementation which knows what the package normally provides + and how to present that package to the project. Since Find modules are + usually distributed separately from the package, they are not as reliable. + They are typically maintained separately, and they are likely to follow + different release schedules, so they can easily become out-of-date. + +Depending on the arguments used, :command:`find_package` may use one or both +of the above methods. By restricting the options to just the basic signature, +both config mode and module mode can be used to satisfy the dependency. +The presence of other options may restrict the call to using only one of the +two methods, potentially reducing the command's ability to find the dependency. +See the :command:`find_package` documentation for full details about this +complex topic. + +For both search methods, the user can also set cache variables on the +:manual:`cmake(1)` command line or in the :manual:`ccmake(1)` or +:manual:`cmake-gui(1)` UI tools to influence and override where to find +packages. See the :ref:`User Interaction Guide <Setting Build Variables>` +for more on how to set cache variables. + +.. _Libraries providing Config-file packages: + +Config-file packages +-------------------- + +The preferred way for a third party to provide executables, libraries, +headers, and other files for use with CMake is to provide +:ref:`config files <Config File Packages>`. These are text files shipped +with the package, which define CMake targets, variables, commands, and so on. +The config file is an ordinary CMake script, which is read in by the +:command:`find_package` command. + +The config files can usually be found in a directory whose name matches the +pattern ``lib/cmake/<PackageName>``, although they may be in other locations +instead (see :ref:`search procedure`). The ``<PackageName>`` is usually the +first argument to the :command:`find_package` command, and it may even be the +only argument. Alternative names can also be specified with the ``NAMES`` +option: + +.. code-block:: cmake + :caption: Providing alternative names when finding a package + + find_package(SomeThing + NAMES + SameThingOtherName # Another name for the package + SomeThing # Also still look for its canonical name + ) + +The config file must be named either ``<PackageName>Config.cmake`` or +``<LowercasePackageName>-config.cmake`` (the former is used for the remainder +of this guide, but both are supported). This file is the entry point to the package for CMake. A separate optional file named -``<PackageName>ConfigVersion.cmake`` may also exist in the -directory. This file is used by CMake to determine whether -the version of the third party package satisfies uses of the -:command:`find_package` command which specify version -constraints. It is optional to specify a version when using -:command:`find_package`, even if a ``ConfigVersion`` file is -present. - -If the ``Config.cmake`` file is found and the -optionally-specified version is satisfied, then the CMake -:command:`find_package` command considers the package to be -found and the entire library package is assumed to be -complete as designed. - -There may be additional files providing CMake macros or -:ref:`imported targets` for you to use. CMake does not -enforce any naming convention for these -files. They are related to the primary ``Config`` file by -use of the CMake :command:`include` command. - -:guide:`Invoking CMake <User Interaction Guide>` with the -intent of using a package of third party binaries requires -that cmake :command:`find_package` commands succeed in finding -the package. If the location of the package is in a directory -known to CMake, the :command:`find_package` call should -succeed. The directories known to cmake are platform-specific. -For example, packages installed on Linux with a standard -system package manager will be found in the ``/usr`` prefix -automatically. Packages installed in ``Program Files`` on -Windows will similarly be found automatically. - -Packages which are not found automatically are in locations -not predictable to CMake such as ``/opt/mylib`` or -``$HOME/dev/prefix``. This is a normal situation and CMake -provides several ways for users to specify where to find -such libraries. +``<PackageName>ConfigVersion.cmake`` or +``<LowercasePackageName>-config-version.cmake`` may also exist in the same +directory. This file is used by CMake to determine whether the version of +the package satisfies any version constraint included in the call to +:command:`find_package`. It is optional to specify a version when calling +:command:`find_package`, even if a ``<PackageName>ConfigVersion.cmake`` +file is present. + +If the ``<PackageName>Config.cmake`` file is found and any version constraint +is satisfied, the :command:`find_package` command considers the package to be +found, and the entire package is assumed to be complete as designed. + +There may be additional files providing CMake commands or +:ref:`imported targets` for you to use. CMake does not enforce any naming +convention for these files. They are related to the primary +``<PackageName>Config.cmake`` file by use of the CMake :command:`include` +command. The ``<PackageName>Config.cmake`` file would typically include +these for you, so they won't usually require any additional step other than +the call to :command:`find_package`. + +If the location of the package is in a +:ref:`directory known to CMake <search procedure>`, the +:command:`find_package` call should succeed. The directories known to CMake +are platform-specific. For example, packages installed on Linux with a +standard system package manager will be found in the ``/usr`` prefix +automatically. Packages installed in ``Program Files`` on Windows will +similarly be found automatically. + +Packages will not be found automatically without help if they are in +locations not known to CMake, such as ``/opt/mylib`` or ``$HOME/dev/prefix``. +This is a normal situation, and CMake provides several ways for users to +specify where to find such libraries. The :variable:`CMAKE_PREFIX_PATH` variable may be :ref:`set when invoking CMake <Setting Build Variables>`. -It is treated as a list of paths to search for -:ref:`Config File Packages`. A package installed in -``/opt/somepackage`` will typically install config files -such as +It is treated as a list of base paths in which to search for +:ref:`config files <Config File Packages>`. A package installed in +``/opt/somepackage`` will typically install config files such as ``/opt/somepackage/lib/cmake/somePackage/SomePackageConfig.cmake``. In that case, ``/opt/somepackage`` should be added to :variable:`CMAKE_PREFIX_PATH`. -The environment variable ``CMAKE_PREFIX_PATH`` may also be -populated with prefixes to search for packages. Like the -``PATH`` environment variable, this is a list and needs to use -the platform-specific environment variable list item separator -(``:`` on Unix and ``;`` on Windows). - -The :variable:`CMAKE_PREFIX_PATH` variable provides convenience -in cases where multiple prefixes need to be specified, or when -multiple different package binaries are available in the same -prefix. Paths to packages may also be specified by setting -variables matching ``<PackageName>_DIR``, such as -``SomePackage_DIR``. Note that this is not a prefix but should -be a full path to a directory containing a config-style package -file, such as ``/opt/somepackage/lib/cmake/SomePackage/`` in -the above example. - -Imported Targets from Packages -============================== - -A third-party package which provides config-file packages may -also provide :ref:`Imported targets`. These will be -specified in files containing configuration-specific file -paths relevant to the package, such as debug and release -versions of libraries. - -Often the third-party package documentation will point out the -names of imported targets available after a successful -``find_package`` for a library. Those imported target names -can be used with the :command:`target_link_libraries` command. - -A complete example which makes a simple use of a third party -library might look like: +The environment variable ``CMAKE_PREFIX_PATH`` may also be populated with +prefixes to search for packages. Like the ``PATH`` environment variable, +this is a list, but it needs to use the platform-specific environment variable +list item separator (``:`` on Unix and ``;`` on Windows). + +The :variable:`CMAKE_PREFIX_PATH` variable provides convenience in cases +where multiple prefixes need to be specified, or when multiple packages +are available under the same prefix. Paths to packages may also be +specified by setting variables matching ``<PackageName>_DIR``, such as +``SomePackage_DIR``. Note that this is not a prefix, but should be a full +path to a directory containing a config-style package file, such as +``/opt/somepackage/lib/cmake/SomePackage`` in the above example. +See the :command:`find_package` documentation for other CMake variables and +environment variables that can affect the search. + +.. _Libraries not Providing Config-file Packages: + +Find Module Files +----------------- + +Packages which do not provide config files can still be found with the +:command:`find_package` command, if a ``FindSomePackage.cmake`` file is +available. These Find module files are different to config files in that: + +#. Find module files should not be provided by the package itself. +#. The availability of a ``Find<PackageName>.cmake`` file does not indicate + the availability of the package, or any particular part of the package. +#. CMake does not search the locations specified in the + :variable:`CMAKE_PREFIX_PATH` variable for ``Find<PackageName>.cmake`` + files. Instead, CMake searches for such files in the locations given + by the :variable:`CMAKE_MODULE_PATH` variable. It is common for users to + set the :variable:`CMAKE_MODULE_PATH` when running CMake, and it is common + for CMake projects to append to :variable:`CMAKE_MODULE_PATH` to allow use + of local Find module files. +#. CMake ships ``Find<PackageName>.cmake`` files for some + :manual:`third party packages <cmake-modules(7)>`. These files are a + maintenance burden for CMake, and it is not unusual for these to fall + behind the latest releases of the packages they are associated with. + In general, new Find modules are not added to CMake any more. Projects + should encourage the upstream packages to provide a config file where + possible. If that is unsuccessful, the project should provide its own + Find module for the package. + +See :ref:`Find Modules` for a detailed discussion of how to write a +Find module file. + +.. _Imported Targets from Packages: + +Imported Targets +---------------- + +Both config files and Find module files can define :ref:`Imported targets`. +These will typically have names of the form ``SomePrefix::ThingName``. +Where these are available, the project should prefer to use them instead of +any CMake variables that may also be provided. Such targets typically carry +usage requirements and apply things like header search paths, compiler +definitions, etc. automatically to other targets that link to them (e.g. using +:command:`target_link_libraries`). This is both more robust and more +convenient than trying to apply the same things manually using variables. +Check the documentation for the package or Find module to see what imported +targets it defines, if any. + +Imported targets should also encapsulate any configuration-specific paths. +This includes the location of binaries (libraries, executables), compiler +flags, and any other configuration-dependent quantities. Find modules may +be less reliable in providing these details than config files. + +A complete example which finds a third party package and uses a library +from it might look like the following: .. code-block:: cmake - cmake_minimum_required(VERSION 3.10) - project(MyExeProject VERSION 1.0.0) - - find_package(SomePackage REQUIRED) - add_executable(MyExe main.cpp) - target_link_libraries(MyExe PRIVATE SomePrefix::LibName) - -See :manual:`cmake-buildsystem(7)` for further information -about developing a CMake buildsystem. - -Libraries not Providing Config-file Packages --------------------------------------------- - -Third-party libraries which do not provide config-file packages -can still be found with the :command:`find_package` command, if -a ``FindSomePackage.cmake`` file is available. - -These module-file packages are different to config-file packages -in that: - -#. They should not be provided by the third party, except - perhaps in the form of documentation -#. The availability of a ``Find<PackageName>.cmake`` file does - not indicate the availability of the binaries themselves. -#. CMake does not search the :variable:`CMAKE_PREFIX_PATH` for - ``Find<PackageName>.cmake`` files. Instead CMake searches - for such files in the :variable:`CMAKE_MODULE_PATH` - variable. It is common for users to set the - :variable:`CMAKE_MODULE_PATH` when running CMake, and it is - common for CMake projects to append to - :variable:`CMAKE_MODULE_PATH` to allow use of local - module-file packages. -#. CMake ships ``Find<PackageName>.cmake`` files for some - :manual:`third party packages <cmake-modules(7)>` - for convenience in cases where the third party does - not provide config-file packages directly. These files are - a maintenance burden for CMake, so new Find modules are - generally not added to CMake anymore. Third-parties should - provide config file packages instead of relying on a Find - module to be provided by CMake. - -Module-file packages may also provide :ref:`Imported targets`. -A complete example which finds such a package might look -like: + cmake_minimum_required(VERSION 3.10) + project(MyExeProject VERSION 1.0.0) + + # Make project-provided Find modules available + list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + + find_package(SomePackage REQUIRED) + add_executable(MyExe main.cpp) + target_link_libraries(MyExe PRIVATE SomePrefix::LibName) + +Note that the above call to :command:`find_package` could be resolved by +a config file or a Find module. It uses only the basic arguments supported +by the :ref:`basic signature`. A ``FindSomePackage.cmake`` file in the +``${CMAKE_CURRENT_SOURCE_DIR}/cmake`` directory would allow the +:command:`find_package` command to succeed using module mode, for example. +If no such module file is present, the system would be searched for a config +file. + + +Downloading And Building From Source With ``FetchContent`` +========================================================== + +Dependencies do not necessarily have to be pre-built in order to use them +with CMake. They can be built from sources as part of the main project. +The :module:`FetchContent` module provides functionality to download +content (typically sources, but can be anything) and add it to the main +project if the dependency also uses CMake. The dependency's sources will +be built along with the rest of the project, just as though the sources were +part of the project's own sources. + +The general pattern is that the project should first declare all the +dependencies it wants to use, then ask for them to be made available. +The following demonstrates the principle (see :ref:`fetch-content-examples` +for more): .. code-block:: cmake - cmake_minimum_required(VERSION 3.10) - project(MyExeProject VERSION 1.0.0) + include(FetchContent) + FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG 703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0 + ) + FetchContent_Declare( + Catch2 + GIT_REPOSITORY https://github.com/catchorg/Catch2.git + GIT_TAG de6fe184a9ac1a06895cdd1c9b437f0a0bdf14ad # v2.13.4 + ) + FetchContent_MakeAvailable(googletest Catch2) + +Various download methods are supported, including downloading and extracting +archives from a URL (a range of archive formats are supported), and a number +of repository formats including Git, Subversion, and Mercurial. +Custom download, update, and patch commands can also be used to support +arbitrary use cases. + +When a dependency is added to the project with :module:`FetchContent`, the +project links to the dependency's targets just like any other target from the +project. If the dependency provides namespaced targets of the form +``SomePrefix::ThingName``, the project should link to those rather than to +any non-namespaced targets. See the next section for why this is recommended. + +Not all dependencies can be brought into the project this way. Some +dependencies define targets whose names clash with other targets from the +project or other dependencies. Concrete executable and library targets +created by :command:`add_executable` and :command:`add_library` are global, +so each one must be unique across the whole build. If a dependency would +add a clashing target name, it cannot be brought directly into the build +with this method. + +``FetchContent`` And ``find_package()`` Integration +=================================================== + +.. versionadded:: 3.24 + +Some dependencies support being added by either :command:`find_package` or +:module:`FetchContent`. Such dependencies must ensure they define the same +namespaced targets in both installed and built-from-source scenarios. +A consuming project then links to those namespaced targets and can handle +both scenarios transparently, as long as the project does not use anything +else that isn't provided by both methods. + +The project can indicate it is happy to accept a dependency by either method +using the ``FIND_PACKAGE_ARGS`` option to :command:`FetchContent_Declare`. +This allows :command:`FetchContent_MakeAvailable` to try satisfying the +dependency with a call to :command:`find_package` first, using the arguments +after the ``FIND_PACKAGE_ARGS`` keyword, if any. If that doesn't find the +dependency, it is built from source as described previously instead. - find_package(PNG REQUIRED) +.. code-block:: cmake - # Add path to a FindSomePackage.cmake file - list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") - find_package(SomePackage REQUIRED) + include(FetchContent) + FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG 703bd9caab50b139428cea1aaff9974ebee5742e # release-1.10.0 + FIND_PACKAGE_ARGS NAMES GTest + ) + FetchContent_MakeAvailable(googletest) + + add_executable(ThingUnitTest thing_ut.cpp) + target_link_libraries(ThingUnitTest GTest::gtest_main) + +The above example calls +:command:`find_package(googletest NAMES GTest) <find_package>` first. +CMake provides a :module:`FindGTest` module, so if that finds a GTest package +installed somewhere, it will make it available, and the dependency will not be +built from source. If no GTest package is found, it *will* be built from +source. In either case, the ``GTest::gtest_main`` target is expected to be +defined, so we link our unit test executable to that target. + +High-level control is also available through the +:variable:`FETCHCONTENT_TRY_FIND_PACKAGE_MODE` variable. This can be set to +``NEVER`` to disable all redirection to :command:`find_package`. It can be +set to ``ALWAYS`` to try :command:`find_package` even if ``FIND_PACKAGE_ARGS`` +was not specified (this should be used with caution). + +The project might also decide that a particular dependency must be built from +source. This might be needed if a patched or unreleased version of the +dependency is required, or to satisfy some policy that requires all +dependencies to be built from source. The project can enforce this by adding +the ``OVERRIDE_FIND_PACKAGE`` keyword to :command:`FetchContent_Declare`. +A call to :command:`find_package` for that dependency will then be redirected +to :command:`FetchContent_MakeAvailable` instead. - add_executable(MyExe main.cpp) - target_link_libraries(MyExe PRIVATE - PNG::PNG - SomePrefix::LibName - ) +.. code-block:: cmake -The :variable:`<PackageName>_ROOT` variable is also -searched as a prefix for :command:`find_package` calls using -module-file packages such as ``FindSomePackage``. + include(FetchContent) + FetchContent_Declare( + Catch2 + URL https://intranet.mycomp.com/vendored/Catch2_2.13.4_patched.tgz + URL_HASH MD5=abc123... + OVERRIDE_FIND_PACKAGE + ) + + # The following is automatically redirected to FetchContent_MakeAvailable(Catch2) + find_package(Catch2) + +For more advanced use cases, see the +:variable:`CMAKE_FIND_PACKAGE_REDIRECTS_DIR` variable. + +.. _dependency_providers_overview: + +Dependency Providers +==================== + +.. versionadded:: 3.24 + +The preceding section discussed techniques that projects can use to specify +their dependencies. Ideally, the project shouldn't really care where a +dependency comes from, as long as it provides the things it expects (often +just some imported targets). The project says what it needs and may also +specify where to get it from, in the absence of any other details, so that it +can still be built out-of-the-box. + +The developer, on the other hand, may be much more interested in controlling +*how* a dependency is provided to the project. You might want to use a +particular version of a package that you built yourself. You might want +to use a third party package manager. You might want to redirect some +requests to a different URL on a system you control for security or +performance reasons. CMake supports these sort of scenarios through +:ref:`dependency_providers`. + +A dependency provider can be set to intercept :command:`find_package` and +:command:`FetchContent_MakeAvailable` calls. The provider is given an +opportunity to satisfy such requests before falling back to the built-in +implementation if the provider doesn't fulfill it. + +Only one dependency provider can be set, and it can only be set at a very +specific point early in the CMake run. +The :variable:`CMAKE_PROJECT_TOP_LEVEL_INCLUDES` variable lists CMake files +that will be read while processing the first :command:`project()` call (and +only that call). This is the only time a dependency provider may be set. +At most, one single provider is expected to be used throughout the whole +project. + +For some scenarios, the user wouldn't need to know the details of how the +dependency provider is set. A third party may provide a file that can be +added to :variable:`CMAKE_PROJECT_TOP_LEVEL_INCLUDES`, which will set up +the dependency provider on the user's behalf. This is the recommended +approach for package managers. The developer can use such a file like so:: + + cmake -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=/path/to/package_manager/setup.cmake ... + +For details on how to implement your own custom dependency provider, see the +:command:`cmake_language(SET_DEPENDENCY_PROVIDER)` command. |
