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:
- flatbuffers
- https://github.com/google/flatbuffers
- See flatbuffers/hunter.cmake
- Testing table: AppVeyor, Travis
- rocksdb
- https://github.com/facebook/rocksdb
- See rocksdb/hunter.cmake
- Testing table: Travis
- nlohmann_json
- https://github.com/nlohmann/json
- See nlohmann_json/hunter.cmake
- Testing table: AppVeyor, Travis
Default behavior¶
Please check that your package respect (i.e. does not rewrite) such CMake variables like:
- CMAKE_INSTALL_PREFIX (critical)
- CMAKE_{C,CXX}_FLAGS + variations (critical)
- CMAKE_{C,CXX}_COMPILER + friends (critical)
- CMAKE_BUILD_TYPE (not critical, but recommended)
- CMAKE_CONFIGURATION_TYPES (not critical, but recommended)
- BUILD_SHARED_LIBS (not critical, but may result some errors)
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 versionsexamples/hunter_box_1
directory with example for testingdocs/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 stringsfoo
withhunter_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
See also
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 your 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
At this moment you know the 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:
Release¶
After all tests pass the pull request will be merged. New release will be created:
You can use new URL
/SHA1
:
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: