Tutorial - Defining system requirements
In previous tutorials you learned how to develop native packages that depends either on native packages and or external packages. This tutorial show you how to define a dependency between a native package and the target platform using system configurations.
Technically a configuration is a PID entity used to:
- check if a system requirement is valid.
- extract important information if it is valid.
- optionally install (if possible) this system requirement if not valid.
Configurations are basically use to manage OS dependencies that we cannot reasonnably or for any reason do not want to wrap as an external package.
Step 1: Define a system requirement
Let’s suppose we continue to work on my-first-package
starting from previous tutorial.
We now want to add threading and we want to use threads posix API. To do this we have to check that the system supports the posix
configuration that will check that all basic posix API are available on the system. In the root CMakeLists.txt
of my-first-package
:
The call to check_PID_Platform
checks that the system provides the posix
configuration. If the system does not provide this configuration then CMake configuration will fail. To test if everything goes well:
Step 2: Using variables from configurations
If a system configuration is satisfied then it produces somes variables that may be used by components. For instance the posix
configuration provides the CMake variable posix_LINK_OPTIONS
that contains linker flags to use (e.g. -lpthread
) in order to use posix API.
2.1 Write the code
First edit the file named hello_main.cpp
in apps/hello
folder and paste the following code:
The modification simply creates a thread to do exactly the same job as previously so the output should be the same as previously. But now the code explicitly depends on an API found in pthread.h
header that is provided by the target platform.
2.2 Modify the description
We need to modify the description of component hello-app
to be able to build it: we need to provide some flags to compiler and linker to make it possible to build it. These flags are contained in variables provided by the posix
configuration.
We simply added the dependency to posix by setting adequate link options (using LINKS SHARED
argument) with those coming from the posix
configuration. Indeed the variable posix_LINK_OPTIONS
holds the list of linker flags to use when linking with libraries referenced by this configuration.
We here suppose that include dirs containing headers are in default system path and will so be found without additionnal include directive. This should be always true for the posix
configuration but sometimes we need to adapt to custom include folders. Let’s suppose we have to do that with posix
, the code would have been:
We use the INCLUDE_DIRS
argument of PID_Component_Dependency
to set the list of include folders required by the posix
configuration. The difference with previous example is that these include folders may change depending on the distributions and version of system the binary is deployed in. So the registered element is now directly the variable posix_INCLUDE_DIRS
and not its value (like for ${posix_LINK_OPTIONS}
, i.e. usage of ${}
). Indeed when a binary is linked, the name of the dependency is somehow registered in the binary itself so we need exact names of dependencies used to build the packages when we use the library. But the binary does not need to memorize where was include or library folders when it was build, it needs to be able to retrieve these folders for the given platform it is installed in. Using variable names like posix_INCLUDE_DIRS
(instead of values) allows to specify that corresponding information can be modified when package binary is used. So in the example, when my-first-package
is used the include dirs pointed by posix_INCLUDE_DIRS
may be different from those used to build it. This is an important feature to develop relocatable binary code while keeping consistency of meta-data.
2.3 Use a simple and robust description
Of course there are different standard variables generated by configurations like posix
, and depending on their nature each must be used either as a value or as a variable. Furthermore sometimes only part of these standard variables are generated by a configuration simply because they are not useful. For instance posix
does not define posix_COMPILER_OPTIONS
or posix_DEFINITIONS
simply because they are not required.
All of this make it a bit difficult, for an end user to known what exactly must be used and in which way. That is why recent versions of PID API now allows to use shortcuts names when a component uses a configuration:
We now specifically use the CONFIGURATION
keyword to tell hello-app
to use libraries from posix
configuration. Technically the system automatically deduces what standard variables are available for the given configruation and automatically and adequately (using variables or values) configure the dependency accordingly.
To make it even more simple you can simply do:
In this situation the system autmatically deduces that posix
is a configuration and then performs same operations as if PID_Component_Dependency
were explicitly used.
Step 3: Configure, build and run
Now that the source code is ready, let’s build it.
- configure and build the package:
Or simpler, use the pid
script:
This command checks that posix
configuration is supported by currrent platform.
- build the package:
- run
hello-app
:
The output of the command should print something like: