|
- .. highlight:: cmake
-
- Using ``dds`` Packages in a CMake Project
- #########################################
-
- One of ``dds``'s primary goals is to inter-operate with other build systems
- cleanly. One of ``dds``'s primary outputs is *libman* package indices. These
- package indices can be imported into other build systems that support the
- *libman* format.
-
- .. note::
- ``dds`` doesn't (yet) have a ready-made central repository of packages that
- can be downloaded. You'll need to populate the local package catalog
- appropriately. The default catalog file contains a limited set of useful
- packages, but you may wish to add more for yourself.
-
- .. seealso:: Refer to :doc:`catalog` for information about remote packages.
-
- .. _PMM: https://github.com/vector-of-bool/PMM
-
- .. _CMakeCM: https://github.com/vector-of-bool/CMakeCM
-
- .. _lm-cmake: https://raw.githubusercontent.com/vector-of-bool/libman/develop/cmake/libman.cmake
-
-
- Generating a libman Index
- *************************
-
- Importing libman packages into a build system requires that we have a libman
- index generated on the filesystem. **This index is not generated globally**: It
- is generated on a per-build basis as part of the build setup. The index will
- describe in build-system-agnostic terms how to include a set of packages and
- libraries as part of a build.
-
- ``dds`` has first-class support for generating this index. The ``build-deps``
- subcommand of ``dds`` will download and build a set of dependencies, and places
- an ``INDEX.lmi`` file that can be used to import the built results.
-
-
- Declaring Dependencies
- ======================
-
- ``dds build-deps`` accepts a list of dependency statements as commnad line
- arguments, but it may be useful to specify those requirements in a file.
-
- ``dds build-deps`` accepts a JSON5 file describing the dependencies of a
- project as well. This file is similar to a very stripped-down version of a
- ``dds`` :ref:`package manifest <pkgs.pkgs>`, and only includes the ``depends``
- key. (The presence of any other key is an error.)
-
- Here is a simple dependencies file that declares a single requirement:
-
- .. code-block:: js
- :caption: ``dependencies.json5``
-
- {
- depends: [
- 'neo-sqlite3^0.2.0',
- ]
- }
-
-
- Building Dependencies and the Index
- ===================================
-
- We can invoke ``dds build-deps`` and give it the path to this file:
-
- .. code-block:: bash
-
- $ dds build-deps --deps dependencies.json5
-
- When finished, ``dds`` will write the build results into a subdirectory called
- ``_deps`` and generate a file named ``INDEX.lmi``. This file is ready to be
- imported into any build system that can understand libman files (in our case,
- CMake).
-
- .. note::
- The output directory and index filepath can be controlled with the
- ``--out`` and ``--lmi-path`` flags, respectively.
-
-
- Importing into CMake
- ********************
-
- We've generated a libman index and set of packages, and we want to import
- them into CMake. CMake doesn't know how to do this natively, but there exists a
- single-file module for CMake that allows CMake to import libraries from libman
- indices without any additional work.
-
- The module is not shipped with CMake, but is available online as a single
- stand-alone file. The `libman.cmake <lm-cmake_>`_ file can be downloaded and
- added to a project directly, or it can be obtained automatically through a
- CMake tool like `PMM`_ (recommended).
-
-
- Enabling *libman* Support in CMake via PMM
- ==========================================
-
- Refer to the ``README.md`` file in `the PMM repo <PMM_>`_ for information on how
- to get PMM into your CMake project. In short, download and place the
- ``pmm.cmake`` file in your repository, and ``include()`` the file near the top
- of your ``CMakeLists.txt``::
-
- include(pmm.cmake)
-
- Once it has been included, you can call the ``pmm()`` function. To obtain
- *libman*, we need to start by enabling `CMakeCM`_::
-
- pmm(CMakeCM ROLLING)
-
- .. warning::
- It is not recommended to use the ``ROLLING`` mode, but it is the easiest to
- use when getting started. For reproducible and reliable builds, you should
- pin your CMakeCM version using the ``FROM <url>`` argument.
-
- Enabling CMakeCM will make available all of the CMake modules available in `the
- CMakeCM repository <CMakeCM_>`_, which includes `libman.cmake <lm-cmake_>`_.
-
- After the call to ``pmm()``, simply ``include()`` the ``libman`` module::
-
- include(libman)
-
- That's it! The only function from the module that we will care about for now
- is the ``import_packages()`` function.
-
-
- Importing Our Dependencies' Packages
- ====================================
-
- To import a package from a libman tree, we need only know the *name* of the
- package we wish to import. In our example case above, we depend on
- ``neo-sqlite3``, so we simply call the libman-CMake function
- ``import_packages()`` with that package name::
-
- import_packages("neo-sqlite3")
-
- You'll note that we don't request any particular version of the package: All
- versioning resolution is handled by ``dds``. You'll also note that we don't
- need to specify our transitive dependencies: This is handled by the libman
- index that was generated by ``dds``: It will automatically ``import_packages()``
- any of the transitive dependencies required.
-
-
- Using Our Dependencies' Libraries
- =================================
-
- Like with ``dds``, CMake wants us to explicitly declare how our build targets
- *use* other libraries. When we import a package from a libman index, the
- import will generate CMake ``IMPORTED`` targets that can be linked against.
-
- In ``dds`` and in libman, a library is identified by a combination of
- *namespace* and *name*, joined together with a slash ``/`` character. This
- *qualified name* of a library is decided by the original package author, and
- should be documented. In the case of ``neo-sqlite3``, the only target is
- ``neo/sqlite3``.
-
- When the libman CMake module imports a library, it creates a qualified name
- using a double-colon "``::``" instead of a slash. As such, our ``neo/sqlite3``
- is imported in CMake as ``neo::sqlite3``. We can link against it as we would
- with any other target::
-
- add_executable(my-application app.cpp)
- target_link_libraries(my-application PRIVATE neo::sqlite3)
-
- Altogether, here is the final CMake file:
-
- .. code-block::
- :caption: ``CMakeLists.txt``
- :linenos:
-
- cmake_minimum_required(VERSION 3.15)
- project(MyApplication VERSION 1.0.0)
-
- include(pmm.cmake)
- pmm(CMakeCM ROLLING)
-
- include(libman)
- import_packages("neo-sqlite3")
-
- add_executable(my-application app.cpp)
- target_link_libraries(my-application PRIVATE neo::sqlite3)
-
-
- Additional PMM Support
- **********************
-
- The ``pmm()`` function also supports ``dds`` directly, similar to ``CMakeCM``
- mode. This will automatically download a prebuilt ``dds`` for the host platform
- and invoke ``dds build-deps`` in a single pass as part of CMake's configure
- process. This is especially useful for a CI environment where you want to have
- a stable ``dds`` version and always have your dependencies obtained
- just-in-time.
-
- To start, pass the ``DDS`` argument to ``pmm()`` to use it::
-
- pmm(DDS)
-
- .. note::
- The ``_deps`` directory and ``INDEX.lmi`` file will be placed in the CMake
- build directory, out of the way of the rest of the project.
-
- .. note::
- The version of ``dds`` that PMM downloads depends on the version of PMM
- that is in use.
-
- This alone won't do anything useful, because you'll need to tell it what
- dependencies we want to install::
-
- pmm(DDS DEP_FILES dependencies.json5)
-
- You can also list your dependencies as an inline string in your CMakeLists.txt
- instead of a separate file::
-
- pmm(DDS DEPENDS neo-sqlite3^0.2.2)
-
- Since you'll probably want to be using ``libman.cmake`` at the same time, the
- calls for ``CMakeCM`` and ``DDS`` can simply be combined. This is how our new
- CMake project might look:
-
- .. code-block::
- :caption: ``CMakeLists.txt``
- :linenos:
-
- cmake_minimum_required(VERSION 3.15)
- project(MyApplication VERSION 1.0.0)
-
- include(pmm.cmake)
- pmm(CMakeCM ROLLING
- DDS DEPENDS neo-sqlite3^0.2.2
- )
-
- include(libman)
- import_packages("neo-sqlite3")
-
- add_executable(my-application app.cpp)
- target_link_libraries(my-application PRIVATE neo::sqlite3)
-
- This removes the requirement that we write a separate dependencies file, and we
- no longer need to invoke ``dds build-deps`` externally, as it is all handled
- by ``pmm``.
|