Management of dependencies in wrapper
In this tutorial we will show how an external package can define its dependencies. There is basically 2 ways:
- dependencies to other external packages.
- explicit platform requirement through configurations.
Step 5 : add a new managed version
We continue to work on the yaml-cpp
project defined in previous steps. This time we want to port another existing version of this external project: version 0.5.2. In this earlier version than the previously defined one, yaml-cpp
depends on another external package called boost
. boost
is a famous project aiming at providing useful APIs to C++ programmers.
5.1 : create a new version folder in the wrapper
5.2 : define deployment procedure (in src/0.5.2/deploy.cmake
):
As you may have notice there is less user entries set by build_CMake_External_Project
. This is because version 0.5.2 of yaml-cpp
does not define these cache entries.
5.3 : define resulting components (in src/0.5.2/CMakeLists.txt
):
5.4 build the version 0.5.2
Now that the description is completed, we can try configuring and building the package.
You can face two situations:
- the build failed. This is surely explainable by the fact that
boost
is not installed in your operating system. This way you saw that there is an implicit dependency betweenyaml-cpp
andboost
projects. - the build succeeded. Well this is in fact not a good situation because you did not see that there is an implicit dependency !
Step 6 : add a dependency to an external package
What we need to do now is to specify the dependency between yaml-cpp
and boost
projects. We will specify this dependency as an external dependency. This is possible because boost
is provided as an external package in PID, in other words a wrapper exists for this project.
6.1 Describe the dependency (in src/0.5.2/CMakeLists.txt
):
or shorter (recommended):
There are two operation to do, quite the same way as for native packages:
- define the dependency between external packages using the
PID_Wrapper_Dependency
command. In the exampleyaml-cpp
depends on a specific range of version of theboost
project. - define the dependencies between components of
yaml-cpp
and components ofboost
, using eitherPID_Wrapper_Component_Dependency
orEXPORT/DEPEND
argument ofPID_Wrapper_Component
. In the examplelibyaml
depends onboost-headers
. We use the keywordEXPORT
because some headers of boost are included in public headers ofyaml-cpp
. To detect that we did:
In output you should see something like:
For instance we see that the header boost/utility.hpp
is included in yaml-cpp/node/detail/node_ref.h
.
6.2 Modify deploy script to manage the dependency at build time:
In previous description we changed 2 things:
- call to
get_External_Dependencies_Info(PACKAGE boost ROOT root_folder INCLUDES boost_include)
is used to get all necessary information aboutboost
package in use. Here what is needed are the include and rootboost
project folders. - arguments like
Boost_NO_SYSTEM_PATHS=ON Boost_INCLUDE_DIR=${boost_include} BOOST_INCLUDEDIR=${boost_include} BOOST_ROOT=${root_folder} BOOSTROOT=${root_folder}
are passed to CMake definitions of the external project. It simply sets the include and root folders where to find boost. These arguments are required by the CMake script of the original project to configure boost adequately and so be able to compile theyaml-cpp
code with the adequzte version of boost. Here the boost version used will be the one provided by PID.
6.3 build again the version 0.5.2
This time everything should work as expected and furthermore the build process may have automatically deploy the boost
external package.
Step 7 : define a required configuration for target platform
Another way to deal with dependencies is by using platform configurations, as for native packages. Using this kind of dependencies should be limited as far as possible but is sometimes required or more easy to use than external packages.
This last step of the tutorial simply shows how to write the dependency to boost
as a check of the platform configuration. Indeed the boost
wrapper also defines a way to test / and install systems packages. But in this example we will use it directly to get also all the compilation/linker flags used to configrue libyaml
.
The tutorial consists in rewriting the previous example for version 0.5.2 of yaml-cpp
.
7.1 : describe the dependency (in src/0.5.2/CMakeLists.txt
):
What changed:
- the call to
PID_Wrapper_Configuration
explicitly checks if the target platform hasboost
system library installed. This call generates various variables, includingboost_INCLUDE_DIRS
that contains the path to the include folder forboost
. - the call to
PID_Wrapper_Component
now adds the variableboost_INCLUDE_DIRS
to the set of includes exported by the project. We use the variable instead of its value (i.e.boost_INCLUDE_DIRS
rather than${boost_INCLUDE_DIRS}
) because we want the resulting binary package to be relocatable: the variableboost_INCLUDE_DIRS
will be interpreted anytime the binary package ofyaml-cpp
will be used (while if its value was used this variable would be only interpreted when the external project is built and so will match only the current build environment in use).
7.2 : build the project
There is no more modification required because the deployment procedure is still valid. So we simply build the project:
Everything should work as expected. The procedure may have installed the boost
system package automatically if it was not already present in OS.
7.3 : Discussion about dependencies version management
One very bad thing about the previous design is that we will face troubles anytime we need to use yaml-cpp
because it will require to use system version of boost
which can conflict with other packages using the PID version. Furthermore it is more convenient to use external project wrapper because they define the components and so dependency are far more simple to write.
We would rather prefer use the system version “as if” it was a PID built version. This way we would be able to use the description of boost
components. To do this we need to change a bit the description:
Then an explicit dependency to the boost
external package is specified (PID_Wrapper_Dependency
), and this time there is a version constraint to SYSTEM
version. The SYSTEM
keyword simply tells that the dependency version is the version installed in operating system and retrieved (automatically) using boost
configuration. So we have to memorize that using the SYSTEM
keyword for version constraint requires the configuration with same name to exist. The call to PID_Wrapper_Configuration
becomes optional because the call to PID_Wrapper_Dependency
with SYSTEM
version constraint will do the job automatically.
Using the SYSTEM
version constraint is possible if external project wrappers are provided with a way to build equivalent system version of a given PID version. You can test it on boost
wrapper by doing:
The use of os_variant
argument:
- will check if the version of
boost
installed in operating system matches theversion
to build. - if everything is OK then the command generates an external package for this boost version but without using the deploy script : instead of compiling
boost
it rather generates symlinks to equivalent binary components and include folders that are installed in system.
This way users can use packages description provided for the given version of boost
while in fact using the boost
version installed in operating system.
Hete if OS installed version (that you do not control) does not match the required version to build (here 1.58.0), an error is generated. To know the currently installed version of boost we can do:
The output should be something like:
Now the boost_VERSION
variable gives you the version of the boost installed version, on the PC used to write this doc 1.74.0
. So to correctly build the os variant of version 1.74.0 the good command is:
Now if you adapt previous example with your OS installed version of boost the wrapper build process should be OK.
Main problem with previous description is sill that the yaml-cpp
version defined must use the OS installed version of boost
in the end, which is not so flexible. We want to be able to use any version of boost
whether it is OS installed or PID built one. To do this we simply have to go back to the initial description:
Indeed with this description we just say that any version of boost
in the range of allowed versions (here 1.55 to 1.65.1) can be used to build yaml-cpp
and this also include OS installed version !!
The choice of the OS variant at yaml-cpp
level:
- can be decided by the build process : the OS or non os variant will be used depending on constraints coming from packages using
yaml-cpp
as a dependency. For instance if a package usingyaml-cpp
also forces the use of system variant ofboost
(e.g.PID_Wrapper_Dependency(boost VERSION SYSTEM)
) then the os variant version will be used OR an error will be generated if the OS version is not in the range of allowed versions (here 1.55 to 1.65.1). - can be forced using dedicated variables:
Previous build command just ask PID to selection othe OS variant for boost dependency when building yaml-cpp
version 0.5.2.
If now you just want to use the version 1.59.0 of boost
instead: