215 lines
7.0KB

  1. How Do I Use ``dds`` in a CMake Project?
  2. ########################################
  3. .. highlight:: cmake
  4. If you have a CMake project and you wish to pull your dependencies via ``dds``,
  5. you're in luck: Such a process is explicitly supported. Here's the recommended
  6. approach:
  7. #. Download `PMM`_ and place and commit `the PMM script <pmm.cmake>`_ into your
  8. CMake project. [#f1]_
  9. #. In your ``CMakeLists.txt``, ``include()`` ``pmm.cmake``.
  10. #. Call ``pmm(DDS)`` and list your dependencies.
  11. Below, we'll walk through this in more detail.
  12. .. note::
  13. You don't even have to have ``dds`` downloaded and present on your system to
  14. use ``dds`` in PMM! Read on...
  15. Using PMM
  16. *********
  17. `PMM`_ is the *Package Manager Manager* for CMake, and is designed to offer
  18. greater integration between a CMake build and an external package management
  19. tool. `PMM`_ supports Conan, vcpkg, and, of course, ``dds``.
  20. .. seealso::
  21. Refer to the ``README.md`` file in `the PMM repo <PMM>`_ for information on
  22. how to use PMM.
  23. Getting PMM
  24. ===========
  25. To use PMM, you need to download one only file and commit it to your project:
  26. `pmm.cmake`_, the entrypoint for PMM [#f1]_. It is not significant where the
  27. ``pmm.cmake`` script is placed, but it should be noted for inclusion.
  28. ``pmm.cmake`` should be committed to the project because it contains version
  29. pinning settings for PMM and can be customized on a per-project basis to alter
  30. its behavior for a particular project's needs.
  31. Including PMM
  32. =============
  33. Suppose I have downloaded and committed `pmm.cmake`_ into the ``tools/``
  34. subdirectory of my CMake project. To use it in CMake, I first need to
  35. ``include()`` the script. The simplest way is to simply ``include()`` the file
  36. .. code-block::
  37. :caption: CMakeLists.txt
  38. :emphasize-lines: 4
  39. cmake_minimum_required(VERSION 3.12)
  40. project(MyApplication VERSION 2.1.3)
  41. include(tools/pmm.cmake)
  42. The ``include()`` command should specify the path to ``pmm.cmake``, including
  43. the file extension, relative to the directory that contains the CMake script
  44. that contains the ``include()`` command.
  45. Running PMM
  46. ===========
  47. Simply ``include()``-ing PMM won't do much, because we need to actually *invoke
  48. it*.
  49. PMM's main CMake command is ``pmm()``. It takes a variety of options and
  50. arguments for the package managers it supports, but we'll only focus on ``dds``
  51. for now.
  52. The basic signature of the ``pmm(DDS)`` command looks like this::
  53. pmm(DDS [DEP_FILES [filepaths...]]
  54. [DEPENDS [dependencies...]]
  55. [TOOLCHAIN file-or-id])
  56. The most straightforward usage is to use only the ``DEPENDS`` argument. For
  57. example, if we want to import `{fmt} <https://fmt.dev>`_::
  58. pmm(DDS DEPENDS "fmt^7.0.3")
  59. When CMake executes the ``pmm(DDS ...)`` line above, PMM will download the
  60. appropriate ``dds`` executable for your platform, generate
  61. :doc:`a dds toolchain </guide/toolchains>` based on the CMake environment, and
  62. then invoke ``dds build-deps`` to build the dependencies that were listed in the
  63. ``pmm()`` invocation. The results from ``build-deps`` are then imported into
  64. CMake as ``IMPORTED`` targets that can be used by the containing CMake project.
  65. .. seealso::
  66. For more in-depth discussion on ``dds build-deps``, refer to
  67. :doc:`/guide/build-deps`.
  68. .. note::
  69. The ``_deps`` directory and generated CMake imports file will be placed in
  70. the CMake build directory, out of the way of the rest of the project.
  71. .. note::
  72. The version of ``dds`` that PMM downloads depends on the version of PMM
  73. that is in use.
  74. Using the ``IMPORTED`` Targets
  75. ==============================
  76. Like with ``dds``, CMake wants us to explicitly declare how our build targets
  77. *use* other libraries. After ``pmm(DDS)`` executes, there will be ``IMPORTED``
  78. targets that can be linked against.
  79. In ``dds`` (and in libman), a library is identified by a combination of
  80. *namespace* and *name*, joined together with a slash ``/`` character. This
  81. *qualified name* of a library is decided by the original package author or
  82. maintainer, and should be documented. In the case of ``fmt``, the only library
  83. is ``fmt/fmt``.
  84. When ``pmm(DDS)`` imports a library, it creates a qualified name using a
  85. double-colon "``::``" instead of a slash. As such, our ``fmt/fmt`` is imported
  86. in CMake as ``fmt::fmt``. We can link against it as we would with any other
  87. target::
  88. add_executable(my-application app.cpp)
  89. target_link_libraries(my-application PRIVATE fmt::fmt)
  90. This will allow us to use **{fmt}** in our CMake project as an external
  91. dependency.
  92. In all, this is our final ``CMakeLists.txt``:
  93. .. code-block::
  94. :caption: ``CMakeLists.txt``
  95. cmake_minimum_required(VERSION 3.12)
  96. project(MYApplication VERSION 2.1.3)
  97. include(tools/pmm.cmake)
  98. pmm(DDS DEPENDS fmt^7.0.3)
  99. add_executable(my-application app.cpp)
  100. target_link_libraries(my-application PRIVATE fmt::fmt)
  101. Changing Compile Options
  102. ************************
  103. ``dds`` supports setting compilation options using
  104. :doc:`toolchains </guide/toolchains>`. PMM supports specifying a toolchain using
  105. the ``TOOLCHAIN`` argument::
  106. pmm(DDS DEPENDS fmt^7.0.3 TOOLCHAIN my-toolchain.json5)
  107. Of course, writing a separate toolchain file just for your dependencies can be
  108. tedious. For this reason, PMM will write a toolchain file on-the-fly when it
  109. executes ``dds``. The generated toolchain is created based on the current CMake
  110. settings when ``pmm()`` was executed.
  111. To add compile options, simply ``add_compile_options``::
  112. add_compile_options(-fsanitize=address)
  113. pmm(DDS ...)
  114. The above will cause all ``dds``-built dependencies to compile with
  115. ``-fsanitize=address`` as a command-line option.
  116. The following CMake variables and directory properties are used to generate the
  117. ``dds`` toolchain:
  118. ``COMPILE_OPTIONS``
  119. Adds additional compiler options. Should be provided by
  120. ``add_compile_options``.
  121. ``COMPILE_DEFINITIONS``
  122. Add preprocessor definitions. Should be provided by
  123. ``add_compile_definitions``
  124. ``CXX_STANDARD``
  125. Control the ``cxx_version`` in the toolchian
  126. ``CMAKE_MSVC_RUNTIME_LIBRARY``
  127. Sets the ``runtime`` option. This option has limited support for generator
  128. expressions.
  129. ``CMAKE_C_FLAGS`` and ``CMAKE_CXX_FLAGS``, and their per-config variants
  130. Set the basic compile flags for the respective file sypes
  131. ``CXX_COMPILE_LAUNCHER``
  132. Allow providing a compiler launcher, e.g. ``ccache``.
  133. .. note::
  134. Calls to ``add_compile_options``, ``add_compile_definitions``, or other CMake
  135. settings should appear *before* calling ``pmm(DDS)``, since the toolchain file
  136. is generated and dependencies are built at that point.
  137. ``add_link_options`` has no effect on the ``dds`` toolchain, as ``dds`` does
  138. not generate any runtime binaries.
  139. .. rubric:: Footnotes
  140. .. [#f1]
  141. Do not use ``file(DOWNLOAD)`` to "automatically" obtain `pmm.cmake`_. The
  142. ``pmm.cmake`` script is already built to do this for the rest of PMM. The
  143. `pmm.cmake`_ script itself is very small and is *designed* to be copy-pasted
  144. and committed into other projects.
  145. .. _PMM: https://github.com/vector-of-bool/pmm
  146. .. _pmm.cmake: https://github.com/vector-of-bool/pmm/raw/master/pmm.cmake