CMake (no dependencies)

If your CMake code is correctly written and has no dependencies then release with sources can be used as is in Hunter. There is no need to have HunterGate/hunter_add_package calls and no need to have a maintenance fork.

Examples of such packages:

Default behavior

Please check that your package respect (i.e. does not rewrite) such CMake variables like:

Environment

Configuration of the package should be predictable.

For example it should not depend on the fact that some package already installed or not:

find_package(OpenSSL)
if(OPENSSL_FOUND)
  target_compile_definitions(... PUBLIC FOO_WITH_OPENSSL=1)
endif()

If package is optional then control behavior explicitly:

option(FOO_WITH_OPENSSL "Build with OpenSSL" ON)

if(FOO_WITH_OPENSSL)
  find_package(OpenSSL REQUIRED) # fatal error if not found!
  target_compile_definitions(... PUBLIC FOO_WITH_OPENSSL=1)
endif()

Same with the programs:

find_program(PYTHON_EXE python) # Use 'find_package(PythonInterp)' in real code
if(PYTHON_EXE)
  # generate some extra code
endif()

Use this code instead:

option(FOO_WITH_PYTHON "Build with Python" ON)

if(FOO_WITH_PYTHON)
  find_program(PYTHON_EXE python)
  if(NOT PYTHON_EXE)
    message(FATAL_ERROR "Python not found")
  endif()
endif()

Environment variable example:

if(EXISTS "$ENV{FOO_EXTRA_CODE}")
  # add some code
endif()

Solution:

option(FOO_WITH_EXTRA_CODE "Use extra code" ON)

if(FOO_WITH_EXTRA_CODE)
  if(NOT EXISTS "$ENV{FOO_EXTRA_CODE}")
    message(FATAL_ERROR "...")
  endif()
endif()

Note that this is kind of a natural limitation because otherwise Hunter have to save the whole outside environment like default paths, environment variables, etc. This is not doable on practice.

Exception is the variables related to compiler/toolchain like compiler version, compiler id, platforms, generators, architectures: WIN32, IOS, ANDROID, etc. Number of such traits is limited and forms toolchain-id.

Install XXXConfig.cmake

The easiest way to integrate installed libraries into other project is to use find_package command. Project should generate and install *Config.cmake files instead of using Find*.cmake modules. It’s the one of the painless ways to support relocation - imported targets can be cached and downloaded as prebuilt binary archive from build servers. Plus only imported targets works nicely with non standard build types like MinSizeRel or RelWithDebInfo.

To check this feature you can try to install files to local directory. If result of installation looks like this:

Install the project...
/.../cmake -P cmake_install.cmake
-- Install configuration: "Release"
-- Installing: /.../lib/libhunter_box_1.a
-- Installing: /.../include/hunter_box_1.hpp

It means that this feature is missing and you need to patch CMake code to introduce it. Details can be found here.

Installation after fix:

Install the project...
/.../cmake -P cmake_install.cmake
-- Install configuration: "Release"
-- Installing: /.../lib/libhunter_box_1.a
-- Installing: /.../include/hunter_box_1.hpp
-- Installing: /.../lib/cmake/hunter_box_1/hunter_box_1Config.cmake
-- Installing: /.../lib/cmake/hunter_box_1/hunter_box_1ConfigVersion.cmake
-- Installing: /.../lib/cmake/hunter_box_1/hunter_box_1Targets.cmake
-- Installing: /.../lib/cmake/hunter_box_1/hunter_box_1Targets-release.cmake

CMake documentation

Add package to Hunter

Next let’s assume user hunterbox is trying to add hunter_box_1 project to Hunter.

Examples on GitHub

Recommended name for the package is lowercase separated with underscore.

C++:

#include <hunter_box_1/hunter_box_1.hpp>

int main() {
  hunter_box_1::foo();
}
// file hunter_box_1.hpp

namespace hunter_box_1 {
} // namespace hunter_box_1

CMake with Hunter:

hunter_add_package(hunter_box_1)
find_package(hunter_box_1 CONFIG REQUIRED)
target_link_libraries(... hunter_box_1::hunter_box_1)

In Hunter sources:

  • cmake/projects/hunter_box_1/hunter.cmake file with versions
  • examples/hunter_box_1 directory with example for testing
  • docs/packages/pkg/hunter_box_1.rst documentation for package

Fork Hunter

Hunter hosted on GitHub service where common way to add code is to fork project and create pull request.

Fork cpp-pm/hunter, clone your fork and initialize all submodules:

> git clone https://github.com/hunterbox/hunter
> cd hunter
[hunter]> git submodule update --init --recursive .

Create branch to work on new package:

[hunter]> git checkout -b pr.hunter_box_1

Add versions

Add one or several versions of hunter_box_1 package to corresponding hunter.cmake file.

Copy template and substitute all strings foo to hunter_box_1:

[hunter]> cp -r cmake/projects/foo cmake/projects/hunter_box_1
[hunter]> sed -i 's,foo,hunter_box_1,g' cmake/projects/hunter_box_1/hunter.cmake

Download release archive and calculate SHA1:

> wget https://github.com/hunterbox/hunter_box_1/archive/v1.0.0.tar.gz
> openssl sha1 v1.0.0.tar.gz
SHA1(v1.0.0.tar.gz)= c724e0f8a4ebc95cf7ba628b89b998b3b3c2697d

Add this information to cmake/projects/hunter_box_1/hunter.cmake file:

# !!! DO NOT PLACE HEADER GUARDS HERE !!!

include(hunter_add_version)
include(hunter_cacheable)
include(hunter_download)
include(hunter_pick_scheme)

hunter_add_version(
    PACKAGE_NAME
    hunter_box_1
    VERSION
    1.0.0
    URL
    "https://github.com/hunterbox/hunter_box_1/archive/v1.0.0.tar.gz"
    SHA1
    c724e0f8a4ebc95cf7ba628b89b998b3b3c2697d
)

hunter_pick_scheme(DEFAULT url_sha1_cmake)
hunter_cacheable(hunter_box_1)
hunter_download(PACKAGE_NAME hunter_box_1)

Consistency

Please keep Git tag and VERSION in consistent state. For example if URL is:

hunter_add_version(
    # ...
    URL
    "https://github.com/hunterbox/hunter_box_1/archive/v1.3.15-da39a3e-p6.tar.gz"
    # ...
)

Then VERSION should be:

hunter_add_version(
    # ...
    VERSION
    1.3.15-da39a3e-p6
    URL
    "https://github.com/hunterbox/hunter_box_1/archive/v1.3.15-da39a3e-p6.tar.gz"
    # ...
)

CMake options

Note that it does not make sense to build and install stuff like examples, tests or documentation. Please check that your package has CMake options to disable those. If such an option is not disabled by default use hunter_cmake_args:

include(hunter_cmake_args)

# ...

# bottom of cmake/projects/foo/hunter.cmake
hunter_cmake_args(
    foo
    CMAKE_ARGS
        FOO_BUILD_EXAMPLES=OFF
        FOO_BUILD_TESTS=OFF
        FOO_BUILD_DOCUMENTATION=OFF
)

hunter_pick_scheme(DEFAULT url_sha1_cmake)
hunter_download(PACKAGE_NAME foo)

Options set by hunter_cmake_args have lower precedence than options set by hunter_config(... CMAKE_ARGS ...) (see order).

Build types

Warning

Usually there is no need to set a build type explicitly. If the package does not work with default Debug + Release it means something is wrong with the package itself.

Default build type(s) can be set by hunter_configuration_types:

hunter_configuration_types(foo CONFIGURATION_TYPES Release)
hunter_download(PACKAGE_NAME foo)

User can overwrite this default by using custom hunter_config parameters.

Set default version

Add hunter_default_version directive with default version to cmake/configs/default.cmake:

hunter_default_version(hunter_box_1 VERSION 1.0.0)

Create example

To test the integration of the package into another project a simple example will be used. Copy the template example and substitute all strings foo with hunter_box_1:
[hunter]> cp -r examples/foo examples/hunter_box_1
[hunter]> sed -i 's,foo,hunter_box_1,g' examples/hunter_box_1/*

Tweak all files in examples/hunter_box_1 directory to fit headers and names of imported targets.

Add documentation

Each package should have a page with information and usage example.

To create such a page copy the template file and substitute all strings foo with the project name (for example hunter_box_1):

[hunter]> cp docs/packages/pkg/foo.rst docs/packages/pkg/hunter_box_1.rst
[hunter]> sed -i 's,foo,hunter_box_1,g' docs/packages/pkg/hunter_box_1.rst

Open file docs/packages/pkg/hunter_box_1.rst and tweak all entries.

Substitute unsorted with some tag in directive single: unsorted ; foo. This tag will be used on this page.

If you want to have two tags add another line with single:

.. index::
  single: category_1 ; foo
  single: category_2 ; foo

Note

Since you don’t know the pull request number a priori leave it as N for now. You can update it later.

Commit

Now save all changes by doing a commit:

[hunter]> git branch
  master
* pr.hunter_box_1

[hunter]> git add cmake/configs/default.cmake
[hunter]> git add cmake/projects/hunter_box_1/
[hunter]> git add docs/packages/pkg/hunter_box_1.rst
[hunter]> git add examples/hunter_box_1/

[hunter]> git commit -m "Add 'hunter_box_1' package"

Test package

Hunter uses GitHub Actions for continuous integration testing. You can also test package building and documentation locally, however this is optional.

Testing will be performed automatically on pull request. To perform testing on push to yours Hunter fork, ensure that GitHub Actions are enabled for your repository - Managing GitHub Actions.

Package build testing will be performed for multiple platforms (different toolchains). If some toolchains are working and some toolchains failed it means the project has platform-specific problems. Note that you don’t have to have all toolchains working and there is no need to fix all issues you see. If at least documentation test is passing and some toolchain tests are working you can make a pull request and you or somebody else can apply fixes later.

If you’re sure that testing is failing due to system specific requirements and NOT due to package dependencies or platform specific code errors, or your package contains components and needs to perform some special tests with different examples - you can modify default build matrix and scripts.

Pull requests

After CI testing is done you can open a pull request with package:

[hunter]> git checkout pr.hunter_box_1
[hunter]> git push -u origin pr.hunter_box_1
PR with package

At this moment you know the pull request number:

Pull request number

Add it to documentation:

[hunter]> git checkout pr.hunter_box_1
[hunter]> vim docs/packages/pkg/hunter_box_1.rst
[hunter]> git add docs/packages/pkg/hunter_box_1.rst
[hunter]> git commit -m 'Pull request number'
[hunter]> git push

Pull request will be approved and tests run on CI, documentation will be tested automatically:

Package testing

Release

After all tests pass the pull request will be merged. New release will be created:

You can use new URL/SHA1:

Release

Clean

At this moment working branch can be removed:

[hunter]> git checkout master
[hunter]> git push origin :pr.hunter_box_1
[hunter]> git branch -D pr.hunter_box_1

Badge

Badge in README.rst can signal that package hunter_box_1 is available via Hunter:

|hunter|

.. |hunter| image:: https://img.shields.io/badge/hunter-hunter_box_1-blue.svg
  :target: https://hunter.readthedocs.io/en/latest/packages/pkg/hunter_box_1.html
  :alt: Hunter

Example: