Why do we need forks?¶
Forks put the burden of pushing new branches/releases from upstream, merging and resolving conflicts by maintainers and at the first view look like a bad, aggressively intrusive choice. But in practice it’s the clearest, robust and universal solution for all the issues related to integration of package into Hunter.
Forks are not requirement. Hunterization changes can be pushed upstream without affecting main functionality, see compatibility for details. And if package has no dependencies it can be used as is in Hunter, see examples.
As already noted here all the issues that are not related to hunterization should be pushed upstream. Including most of the issues described in this section.
Solution for bundled sources¶
Take a look at this example:
rabit has bundled dependencies
dmlc. In fact
folder is a separated project and lives here:
Assuming that we can’t change the order of include paths (local includes
should have higher priority than external because different version of same
package itself can be installed in system) there is no “soft” solution here
and the only way to integrate package is to remove
dmlc folder from
sources. In practice it means forking the project and applying “remove folder”
patch. Note that it really doesn’t depend on the package manager, build system
or C++ compiler. All C++ compilers works similar to
> c++ -I/path/to/local -I/path/to/external ...
#include <dmlc/timer.h> will always fall to the choice of picking
Set of patch files¶
Another way to avoid forks is to keep needed
*.patch files in Hunter and
apply them to upstream releases before running build instructions. Such approach
used by Homebrew and Gentoo
for example. In practice such set of patches can be quite big, e.g. 19 commits
HunterGate module, lock version in
hunter_add_package calls, applying
variables introduced by new CMake version and general improvements):
Note that Hunter keep all available
OpenCV versions in
At this moment there are 29 versions of
OpenCV available for users, hence
it will be 19 x 29 = 551
*.patch files to maintain. Some of them can be
shared between versions, some of them can be fused with each other, etc.
If such approach will be chosen we will end up with system for maintaining
patches, but there is no need to reinvent the wheel, such system already
exist and called
Git. Assuming the fact that Hunter project hosted on
GitHub and GitHub offer free unlimited repositories for public projects there
are no real reasons to choose
*.patch approach over forks. The use of
the forks allow us to rebase, merge, cherry-pick, discuss and review the patches
High cohesion means that you should keep parts of a code base that are related
to each other in a single place . The fact that version
v1.0 of package
Foo works fine with Hunter archive
v0.10 is perfectly expressed by
adding child commit
Add Hunter v0.10 to parent commit
Foo v1.0. Change
of dependencies from version to version is another example.
if(WIN32) find_package(boo CONFIG REQUIRED) endif() find_package(bar CONFIG REQUIRED)
if(FOO_WITH_BAZ) find_package(baz CONFIG REQUIRED) endif() find_package(bar CONFIG REQUIRED)
It’s hard to make a mistake in both cases:
--- /home/docs/checkouts/readthedocs.org/user_builds/hunter/checkouts/latest/docs/faq/foo-v1.0.cmake +++ /home/docs/checkouts/readthedocs.org/user_builds/hunter/checkouts/latest/docs/faq/foo-v1.0-hunter.cmake @@ -1,5 +1,7 @@ if(WIN32) + hunter_add_package(boo) find_package(boo CONFIG REQUIRED) endif() +hunter_add_package(bar) find_package(bar CONFIG REQUIRED)
--- /home/docs/checkouts/readthedocs.org/user_builds/hunter/checkouts/latest/docs/faq/foo-v2.0.cmake +++ /home/docs/checkouts/readthedocs.org/user_builds/hunter/checkouts/latest/docs/faq/foo-v2.0-hunter.cmake @@ -1,5 +1,7 @@ if(FOO_WITH_BAZ) + hunter_add_package(baz) find_package(baz CONFIG REQUIRED) endif() +hunter_add_package(bar) find_package(bar CONFIG REQUIRED)
It will be much easier to miss something while trying to support any fork-free approach:
if(FOO_VERSION VERSION_EQUAL 1.0 AND WIN32) magic_download(boo) endif() if(FOO_VERSION VERSION_EQUAL 2.0 AND FOO_WITH_BAZ) magic_download(baz) endif() magic_download(bar)
Any non-CMake custom build scheme suffers from this problem since build instructions have to know everything about all versions available, e.g. see Boost components .
Rejected/pending CMake patches¶
Having CMake build instructions in package is the easiest way to integrate package into Hunter (but not the only one) however not all developers of the upstream projects are ready to accept CMake code because it may put burden on maintaining another build system (if CMake added as extra build system), learning new build system (if you want to substitute existing system with CMake) or increase CMake minimum version to introduce new code. https://github.com/hunter-packages is a central place where CMake friendly code can leave and shared with others.
Removing usage of FindXXX.cmake¶
Overwhelming majority of projects use
FindXXX.cmake (or even something like
find_library) instead of recommended
effectively making project non-relocatable. It’s not a problem for the package
managers that are using single-root directory (e.g.
apt-get on Ubuntu and
brew on OSX) but since
Hunter allow to have
multiple custom configurations
it will not work.
Lock URL/SHA1 in HunterGate¶
Even if all the issues will be resolved and
‘hunter_add_package’ will be called by hook inside ‘find_package’
it’s still will be convenient to save latest successful 3rd parties
configuration for debugging purposes. In terms of Hunter it means attaching
URL/SHA1 arguments of
HunterGate to some commit.