Designing CMaize’s Find or Build Dependency Function
This page describes the process of designing the find_or_build_dependency
function.
What is CMaize’s Find or Build Dependency Function?
The find_or_build_dependency function is the user-facing function CMaize
provides to help developers manage their project’s dependencies. Under the hood
the find_or_build_dependency function is responsible for mapping the user’s
dependency needs to a target (a build target if the build system will
build it and an install target if it already exists). This mapping is done via
the package manager component (see
Designing CMaize’s PackageManager Component).
Why Do We Need a Find or Build Dependency Function?
The need for the find_or_build_dependency function arose in the discussions
of the overall user API (see Overview of CMaize’s User API Design). In
particular, CMaize is designed to rely on existing packaging managers. The
find_or_build_dependency API abstracts away the details of how those
package managers work so that CMaize consumers can simply specify the dependency
details.
Find or Build Dependency Function Considerations
- CMake based
As user-facing functionality, the
find_or_build_dependencyfunction should have an interface which is consistent with traditional CMake. In particular this means the input should be strings and the result should be the name of a traditional CMake target.
- wrap package managers
As stated above, one of the primary reasons for this function is to abstract away the details of how CMaize interacts with the underlying package managers.
As a corollary, this also means that
find_or_build__dependencymust be able to accept whatever input is needed for the various package manager backends.
- CMake target
The user of the
find_or_build_dependencyfunction will provide a name for the dependency. That name will be tied to that particular invocation offind_or_build_dependencyand will represent that specific package specification. This is explicitly done by creating a traditional CMake target under the provided name.As a corollary, if the user wants to have multiple specifications of a package, then there must be be multiple calls to
find_or_build_dependency, each call must provide a unique name.The user should continue to refer to this package specification via the provided name, e.g., when using it as a dependency for another
find_or_build_dependencycall or when specifying the project’s assets (e.g.,cmaize_add_library)
Find or Build Dependency Function Design
Fig. 3 Overview of the control flow in the find_or_build_dependency function.
The control flow of find_or_build_dependency is diagramed in
Fig. 3. In addressing the CMake based
consideration the inputs to the find_or_build_dependency function are the
name of the dependency and any inputs needed to specify the dependency (e.g.,
version or URL) and any necessary build options. Internally,
find_or_build_dependency then:
Converts the dependency’s information into a
PackageSpecificationobject.Obtains the active
CMaizeProjectobject.Gets the active
PackageManagerfrom theCMaizeProjectobject.Determines if the
PackageManagerobject has a dependency matching thePackageSpecificationobject.If yes, then the
PackageManagerretrieves the already installed dependency which is returned as aInstalledTargetobject.If no, then the
PackageManagercreates aBuildTargetobject which will be built during the build phase.Finally the target is registered to the active
CMaizeProjectobject.
In turn, find_or_build_dependency thus works like a driver managing the
interactions of the CMaizeProject object with the PackageManager
objects. The reliance on a PackageManager object addresses the
wrap package managers consideration.
API Design
The API of the find_or_build_dependency function must be capable of
accepting whatever input a PackageSpecification object may need. This is
because the PackageManager will ultimately work with the
PackageSpecification. To that end, the API will accept a number of
kwargs which will be forwarded to the PackageSpecification and the
basic API will be:
cmaize_find_or_build_dependency(name_of_dependency <kwargs>)
Here name_of_dependency will be the base name assigned to the CMake target,
as required by the CMake target consideration. N.B., “CMake target”
in this context refers to a traditional CMake target, NOT a CMaize object.
Users should continue to refer to the dependency as name_of_dependency in
all future CMaize calls, e.g.:
cmaize_find_or_build_dependency(foo <kwargs>)
cmaize_find_or_build_dependency(bar DEPENDS foo <other_kwargs>)
Summary
- CMake based
The
find_or_build_dependencyfunction relies on traditional CMake inputs and ultimately produces a native CMake target which is used by dependees.- wrap package managers
The body of the
find_or_build_dependencyfunction relies onPackageManagerinstances to actually find and/or build the various dependencies.- CMake target
The
BuildTargetandInstalledTargetclasses are responsible for ensuring that a traditional CMake target is created under the name the user provides to thefind_or_build_dependencyfunction.