Using packages
This part provides a detailed description on the usage of PID methodology’s core concepts and tools to deal with packages.
Package definition
When developing a PID package one need to handle information such as:
- meta-information : who is involved in its development ? what is its general purpose ? where to find this package on the network ? what is the license of the code ? etc.
- build-related information : what are the components provided by the package and how to compile/link them from source code ? How components are tested ? what is the version of the package ? what are its functional dependencies ?
- functional information : this is the source code of the components and other associated files like configuration files if any required.
The whole package development is organized and described with CMake, and the CMakeLists.txt files used contain the whole meta-information and
build-related information used by the package. Each package contains several CMakeLists.txt files that are generally used to define components :
- the root
CMakeLists.txtfile is used to define meta-information and dependencies of the package. - the
CMakeLists.txtfile contained in thesrcfolder defines the library components. - the
CMakeLists.txtfile contained in theappsfolder defines the application components. - the
CMakeLists.txtfile contained in thetestfolder defines the tests components and running tests (using these components or others). - the
CMakeLists.txtfile contained in thesharefolder defines additional files to install, like configuration files.
In the context of PID components are software artefacts generated and installed by a package. Each component may require other components from another package and so may explicitly define dependencies between packages. The primary role of PID is to manage these dependencies.
The CMakeLists.txt files are so used to describe 1) the way components are built and 2) dependencies between them. Each CMakeLists.txt uses the PID cmake API and follow a predefine pattern depending on its role in the project. The following subsections present examples on how to use the API together with more classical CMake code in order to completely define a functionnal PID package.
General description
The package general description takes place in the root CMakeLists.txt. This file contains the description of meta-information and dependencies of the package.
Meta-information
Let’s suppose we define a package with the name a-given-package, its root CMakeLists.txt could look like:
cmake_minimum_required(VERSION 3.0.2) #minimum version of CMake to use PID
set(WORKSPACE_DIR ${CMAKE_SOURCE_DIR}/../.. CACHE PATH "root of the packages workspace directory")
list(APPEND CMAKE_MODULE_PATH ${WORKSPACE_DIR}/cmake) #registereing PID CMake scripts
include(Package_Definition NO_POLICY_SCOPE) # use the PID API
project(a-given-package)
PID_Package(
AUTHOR Robin Passama
INSTITUTION LIRMM
YEAR 2013
LICENSE CeCILL
ADDRESS git@gite.lirmm.fr:passama/a-given-package.git
DESCRIPTION an example PID package
VERSION 1 2
)
PID_Category(example/simple)
# adding some binary packages references
PID_Reference(
BINARY VERSION 0 1 0 PLATFORM x86_64_linux_stdc++
URL http://gite.lirmm.fr/a-given-package/download/0.1.0/release
http://gite.lirmm.fr/a-given-package/download/0.1.0/debug
)
PID_Reference(
BINARY VERSION 1 1 PLATFORM x86_64_linux_stdc++
URL http://gite.lirmm.fr/a-given-package/download/1.1.0/release
http://gite.lirmm.fr/a-given-package/download/1.1.0/debug
)Explanations:
-
Exactly as in any CMake project, the CMake package is defined with the
PROJECTkeyword. The CMake project’s name must be the same as the name of the git repository and must be the same as the project root folder name. The remaining lines until thePID_Packagemacro call must be let unchanged (initialization of the PID specific cmake API). -
Then comes the
PID_Package(or equivalentdeclare_PID_Package) macro, which is mandatory. This macro defines general meta-information on the package, and should not change a lot during package life cycle:- the main author (
AUTHORkeyword) and its institution (INSTITUTIONoptional keyword), considered as the maintainer of the package. - the
YEARfield helps defining the package’s life cycle range. For instance one can input a field such as “2009-2013”. - the
LICENSEfield is used to specify the license that applies to the code. This license must be defined in the workspace in the form of a license file. - the
ADDRESSfield is used to specify the address of the official GIT repository of the package. - the
DESCRIPTIONfield must be filled with a short description of the package usage/utility. - the
VERSIONargument (equivalent to usingset_PID_Package_Version) is used to set the currently developed version of the package. It takes as arguments at least a major and minor numbers and optionally a patch number (default value for patch number is 0). The version number thus follows the same pattern as git release versions. Before a version is released with a git tag this version number must be set adequately so that git tag matches cmake package version. Generally, the best way to do is to set the version number used in theCMakeLists.txtwith the number of the next version to release. In the example we consider that the version 1.1 of the package has been released so the version number has been set to 1.2.
- the main author (
-
Then the user fill other meta-information that may evolve during project life cycle:
- the
PID_Referencefunction is used to register a downloadable binary version of the package. TheVERSIONkeyword specify the version with major.minor.patch pattern. ThePLATFORMkeyword specifies the target platform for which the binaries have been built. The two addresses after theURLkeyword specify where the binary package version can be downloaded either in release (first address) and debug (second address) modes. - the
PID_Categoryfunction is used to specify to which categories the package belongs to. A Category is nothing more than a text identifier that tells what concerns are treated by the package. For instance a package implementing a robot driver could belong to the “drivers/robot” category. Many categories can be defined for the same package. This information can be use at the workspace level (using workspace specific commands) to know which packages are bound to a given concern. This information just helps classifying packages and does not impact the build process.
- the
Dependencies
The last part of the root CMakeLists.txt is used to manage dependencies between the current package and other packages it depends on. It could look like:
# finding used packages
PID_Dependency(boost VERSION 1.55.0)
PID_Dependency(a-given-package 1.0 COMPONENTS lib-first-sh lib-second-st)
#declare a dependency over another PID package
declare_PID_Package_Dependency ( # same as using PID_Dependency
PACKAGE another-package NATIVE VERSION 1.0
COMPONENTS lib-other-sh
)
build_PID_Package()Explanations:
-
The PID development process imposes to declare dependencies of the current package. Indeed this is not because you try to find other packages that you will use them, even if obviously this assumption will be right most of time. A dependency simply means that components of the package are using components from other packages. For instance, the current package uses the package
another-packagewith minimum version 1.0. To make this declaration possible PID API provides thePID_Dependency(or equivalentdeclare_PID_Package_Dependency) function. This function can be used in two different ways:- it is used to specify a dependency to an external package (optionnaly using the keyword
EXTERNALafter the package name but not required as PID detect dependency nature). An external package is a “light” PID package that is not available as a repository: it is just a kind of port of an existing project into PID system in order to ease its deployment process. Installed external packages version can be found in theinstallfolder of the workspace as for native packages. The idea behind external packages is to allow to import existing projects and wrap them as specific PID packages. - it is used to specify a dependency to a native package (optionnaly using
NATIVEkeyword). Then version and component requirement informations can be used exactly as in the example.
- it is used to specify a dependency to an external package (optionnaly using the keyword
-
The last command called by the
CMakeLists.txtmust thebuild_PID_Packagemacro. This line is mandatory in order to allow the build of the package: compilation, installation, deployment, API doc generation, etc. Without this call, the CMake process would simply do nothing.
Dealing with conditional dependencies
The previous example is quite simple since it directly deals with required dependencies. Nevertheless, when using cmake one sometimes have to deal with conditional dependencies. Indeed, conditional dependencies allow to configure the build according to the OS requirements or to the configuration of user’s station. This conditional dependencies are managed nearly the same way as previously:
PID_Dependency(another-package OPTIONAL VERSION 1.0)
if(NOT another-package_AVAILABLE)
PID_Dependency(yet-another-one VERSION 5.0)
endif()Explanations:
-
This technic is used to describe dependencies that are either optional or alternative requirements when multiple different packages can be used for the same purpose. This later case is shown in the previous code. Defining such conditional dependencies is made using
PID_Dependencyas previously but using theOPTIONALkeyword. -
In the previous example, there is an implicit priority of required packages:
another-packagewill be used prior toyet-another-oneif it is found (information given byanother-package_AVAILABLE). -
The only mandatory descriptive elements is to use
PID_Dependencyfunction to tell to PID system which package is required or optional.
Defining library components
Once package dependencies have been defined, the package developers can then declare the components of the package and their relationship with these dependencies. Most common components are library components : they are used by developers to define reusable functionalities. All libraries are defined in the CMakeLists.txt contained in the src folder of the package repository.
PID defines three types of libraries, matching the three classical types available in C/C++. It provides a systematic way to define these libraries and automate their use, avoiding the user to know precisely how to deal with each type and their relative properties. Following subsections explain how to declare each of these types. These definitions rely on cmake functions provided within PID: declare_PID_Component and declare_PID_Component_Dependency.
Header libraries
Header libraries are not compiled to produce a binary object. They are just made of a set of header files that defines an API. This kind of library is often used for template libraries definitions, for instance the Boost framework essentially contains lots of header libraries. A header library is never used at link time (never linked to another library or executable using a linker) but only at compile time (when including header files in code). The definition of a header library should look like:
declare_PID_Component(HEADER_LIB NAME my-given-lib DIRECTORY my_lib)
declare_PID_Component_Dependency(COMPONENT my-given-lib
EXPORT NATIVE lib-other-sh PACKAGE another-package
EXPORTED_DEFINITIONS USE_SPECIFIC_COMPILE_OPTION)or equivalent short signature:
PID_Component(my-given-lib HEADER DIRECTORY my_lib)
PID_Component_Dependency(COMPONENT my-given-lib
EXPORT lib-other-sh PACKAGE another-package
EXPORTED_DEFINITIONS USE_SPECIFIC_COMPILE_OPTION)Explanations:
-
The first thing to do is to declare the header library by using the function
declare_PID_Component(orPID_Component):- the
HEADER_LIB(orHEADER) keyword is used to declare a header library component. - the
NAMEkeyword is used to define the identifier of the component in PID, whose unicity must be preserved. In the example the name ismy-given-lib.NAMEkeyword can be ommitted if the name if the first argument (see short signature). - the
DIRECTORYkeyword is used to specify in which sub-directory of theincludefolder the header files are found (in the example themy_libsub-folder). The direct consequence is that all headers of a given library must be placed in a unique folder.DIRECTORYargument can be ommitted if the name of the folder is the same as the name of the component (not the case here).
- the
- Then, depending on the library’s content, some dependencies can be attached to the library, using
declare_PID_Component_Dependency(orPID_Component_Dependency). Indeed a header library can depend on other libraries (either header, static or shared): - the
COMPONENTkeyword is used to specify for which component a dependency is defined, in the example the previously definedmy-given-libheader library. - the
EXPORTkeyword specifies thatmy-given-libexports the required dependency. Exporting means that the reference to the required component is defined in the interface of the library. Since an header library is only made of an interface, it must export each of its dependencies. - the
NATIVEandPACKAGEkeywords are used to specify the dependency itself:my-given-libdepends on the componentlib-other-shdefined in the PID packageanother-package. Declaring an external or system dependency or even an internal dependency is slightly different, but follows the same logic. - the
EXPORTED_DEFINITIONSis used to specify values of C preprocessor definitions that are exported by the library. In the example the exported dedinition isUSE_SPECIFIC_COMPILE_OPTION. Exported definition are used by components that will usemy-given-libto configure its code adequately.
One interesting property of PID is to be able to declare different components from the same code. For instance:
declare_PID_Component(HEADER_LIB NAME my-given-lib-bis DIRECTORY my_lib)In this example, a new component named my-given-lib-bis is declared and created from the same source code contained in the my_lib folder. The differences with the previous component are that my-given-lib-bis has no dependencies and it does not define USE_SPECIFIC_COMPILE_OPTION. This is useful to declare many alternatives from the same code.
Static libraries
Static libraries are binary archives that provides some functionalities through an API defined by a set of headers. A static library is made of:
- a set of header files that define its interface (i.e. what functionnalities is available for library users).
- a set of (compiled) binary objects that implement its behaviour. Its interface is used at compile time (when its header are included) and its contained objects are linked to executables and shared libraries at link time, so they no more exist at run time. The definition of a static lib should look like:
declare_PID_Component(STATIC_LIB NAME my-static-lib DIRECTORY binary_lib
INTERNAL DEFINITIONS A_VERY_SPECIFIC_IMPLEM
)
declare_PID_Component_Dependency(COMPONENT my-static-lib
EXTERNAL boost INCLUDE_DIRS <boost>/include
)
declare_PID_Component_Dependency(COMPONENT my-static-lib
EXPORT NATIVE my-given-lib-bis
)or with short signature:
PID_Component(my-static-lib STATIC DIRECTORY binary_lib
INTERNAL DEFINITIONS A_VERY_SPECIFIC_IMPLEM
EXPORT boost/boost-headers my-given-lib-bis
)Explanations:
As for any component, the first thing to do is to declare it by using declare_PID_Component (equivalent to PID_Component):
- the
STATIC_LIB(orSTATIC) keyword is used to declare a static library. - the
NAMEkeyword is used to define the identifier of the library,my-static-libin the example.NAMEkeyword can be ommitted if the name if the first argument. - the
DIRECTORYkeyword is used to say in which sub-directory of theincludefolder the header files of the static library are found, in the example thebinary_libsub-folder. The same folder name is used to specify in which subdirectory of thesrcfolder the source and non-public header files of the library are found. For a same library, this constraints the user to use same folder names betweenincludeandsrcdirectories.DIRECTORYargument can be ommitted if the name of the folder is the same as the name of the component (not the case here). - the
INTERNAL DEFINITIONSis used to specify definitions that affect only the implementation (i.e. that is not used in any header file of the library). In the examplemy-static-libdefines the preprocessor definitionA_VERY_SPECIFIC_IMPLEM.
As readers may notice, the declaration is quite the same as for header libraries. Note also that static libraries can dedine exported definitions (same as header libraries) for those which are used in their header files. The declaration of dependencies also follows the exact same pattern. In the example:
my-static-libuses an external package namedboost. As boost is a pure header library it only needs to specify where to find its header files, using theINCLUDE_DIRSkeyword. The include path specified is relative to the boost external package root folder (using thespecifier). my-static-libis also using (keywordNATIVE)my-given-lib-bisthat is defined in the same package (noPACKAGEkeyword used). It exportsmy-given-lib-bismeaning that its headers contain#includedirective over headers ofmy-given-lib-bis.
Shared libraries
Shared libraries are binary objects that provides some functionalities through an API defined by a set of headers. A shared library is made of:
- a set of header files that define its interface (i.e. what class/functions are available for library users).
- a binary object (file with
.soextension on linux) that implements its behaviour.
Its interface is used at compile time (when including its headers) and its binary object is checked at link time and truly used at run time, either when the dependent executable is loaded (load time) or when it explicitly loads the library at run time. The definition of a shared library is more or less the same as for static libraries and should look like:
declare_PID_Component(SHARED_LIB NAME my-shared-lib DIRECTORY binary_lib
INTERNAL DEFINITIONS ANOTHER_SPECIFIC_IMPLEM
)
declare_PID_Component_Dependency(COMPONENT my-shared-lib
EXTERNAL boost INCLUDE_DIRS <boost>/include
)
declare_PID_Component_Dependency(COMPONENT my-shared-lib
EXPORT NATIVE my-given-lib
)or with short signature:
PID_Component(my-shared-lib SHARED DIRECTORY binary_lib
INTERNAL DEFINITIONS ANOTHER_SPECIFIC_IMPLEM
EXPORT boost/boost-headers my-given-lib
)Explanations:
In this example, the function declare_PID_Component (equivalent to PID_Component) is used the common way:
- the
SHARED_LIB(orSHARED) keyword declares the type of component as a shared library. - the
NAMEkeyword is used to declaremy-shared-lib.NAMEkeyword can be ommitted if the name if the first argument. - the
DIRECTORYkeyword definesincludeandsrcsub folders where to find code.DIRECTORYargument can be ommitted if the name of teh flder is the same as the name of the component (not the case here). - the
INTERNAL DEFINITIONSis used to define the preprocessor variableANOTHER_SPECIFIC_IMPLEMcontrarily tomy-static-lib.
This example shows how shared and static libraries can be built from the same source code and how developers can define alternative implementation for part of their code using preprocessor definitions. In the example reader can notice that the shared
library is built from the same code as static library my-static-lib but with different compile flags (ANOTHER_SPECIFIC_IMPLEM instead of A_VERY_SPECIFIC_IMPLEM). Their dependencies can also vary depending on the way they are built:
my-shared-libuses the Boost external package the same way asmy-static-lib.my-shared-libuses the librarymy-given-libinstead ofmy-given-lib-bisused bymy-static-lib.
Defining application components
In order to produce programs a package can also contains application components. Application components designed to be used by end-users are defined in the CMakeLists.txt contained in the apps folder of the package. Test applications are specifically used to test package libraries or applications and are placed in the test folder of the package repository.
PID defines three types of applications explained in following subsections. These definitions rely on same cmake API already presented in defining library component section.
Standard applications
By standard applications we mean applications that are intended to be used by end-users or a run-time software component that can be deployed using a specific middleware/framework. The definition of a standard application should look like:
declare_PID_Component(APPLICATION NAME my-app DIRECTORY my_app_dir
INTERNAL INCLUDE_DIRS common_defs common_types
)
declare_PID_Component_Dependency(COMPONENT my-app
EXPORT NATIVE lib-other-sh PACKAGE another-package
)or with short signature:
PID_Component(my-app APP DIRECTORY my_app_dir
INTERNAL INCLUDE_DIRS common_defs common_types
EXPORT another-package/lib-other-sh
)Explanations:
As for library components, the first thing to do is to declare the application by using the macro declare_PID_Component (or PID_Component):
- the
APPLICATION(orAPP) keyword defines the type of the component as a standard application. - the
NAMEkeyword defines the unique identifier of the application,my-appin the example.NAMEkeyword can be ommitted if the name if the first argument. - the
DIRECTORYspecifies in which sub-directory of theappfolder the source files of the application are found, in the example themy_app_dirsub-folder.DIRECTORYargument can be ommitted if the name of the folder is the same as the name of the component (not the case here). - the
INTERNAL INCLUDE_DIRSspecifies additional directories (sub folders of theappsfolder) where to find non-public header files, in the examples folderscommon_defsandcommon_types.
Then developers can add dependencies for the application, exactly the same way as for libraries using the declare_PID_Component_Dependency (or PID_Component_Dependency) function:
- the
COMPONENTspecifies the application that declares a dependency,my-appin the example. NATIVEandPACKAGEkeyword are used to target a specific component from another package, here the shared librarylib-other-shof the packageanother-packagethat is a native package.NATIVEkeyword is optional. Dependencies management work the same way as for libraries.
Example applications
Example applications are little pieces of executable code whose only purpose is to provide to developers examples and tutorials on the way of using other components (most of time libraries) defined in the package. The definition of an example application should look like:
declare_PID_Component(EXAMPLE_APPLICATION NAME my-example DIRECTORY my_example_dir)
declare_PID_Component_Dependency(COMPONENT my-example NATIVE my-shared-lib)or short signature:
PID_Component(my-example EXAMPLE DIRECTORY my_example_dir
DEPEND my-shared-lib)Explanations:
From a strict C/C++ point of view example application are just like standard applications, in other word an executable binary object. From PID point of view this is also nearly the same:
- Example application are developed with same rules as standard applications except that we have to use the
EXAMPLE(orEXAMPLE_APPLICATION) keyword withinPID_Component(or equivalentdeclare_PID_Component) function. - Developers can decide (using dedicated CMake option in cache) to avoid compiling example applications since most of time they are not really useful.
- Example application code may be referenced into the API documentation.
Test applications
The test folder of the package contains a CMakeLists.txt file that builds (and run) test units. The organization into subdirectories follows the same logic as for libraries and applications. The first step when playing test is to define test applications, by doing something like this in the CMakeLists.txt of test:
declare_PID_Component(TEST_APPLICATION NAME my-test DIRECTORY my_test_dir)
declare_PID_Component_Dependency(COMPONENT my-test NATIVE my-shared-lib)or short signature:
PID_Component(my-test TEST DIRECTORY my_test_dir
DEPEND my-shared-lib)Explanations:
- Test applications are developed with same rules as standard or example applications except that we have to use the
TEST(or equivalentTEST_APPLICATION) keyword withinPID_Component(or equivalentdeclare_PID_Component) function. DEPENDkeyword is used to say thatmy-testusesmy-shared-libbut that not export its symbols (a test never export symbols since it has no interface).- Tests are specific components because they will not be installed with package version binary. They are just used to test the validity of the codes, for instance to be sure it behaves properly or respects some backward compatibility constraints.
Defining tests
PID uses the CMake basic API to provide basic testing capabilities to packages. The previous section shows my-test that is in charge of testing the library my-shared-lib. Then, in the CMakeLists.txt of the test folder, this test application can be used to launch series of tests, using standard CTest tooling integrated in CMake:
run_PID_Test (NAME correctness_of_my-shared-lib_step1 COMPONENT my-test ARGUMENTS "first" "124" "12")
run_PID_Test (NAME correctness_of_my-shared-lib_step2 COMPONENT my-test ARGUMENTS "second" "12" "46")
run_PID_Test (NAME correctness_of_my-shared-lib_step3 COMPONENT my-test ARGUMENTS "first" "0" "87")In the previous example, one can see that the same test application my-shared-lib may be used to run series of tests, simply by changing its input parameters. Of course different test applications may be used to test same libraries if needed (for instance to discriminate unit testing, backward compatibility testing, non-regression testing, etc.). Another option is to use generic test tools (e.g. Valgrind, Purify, etc.) to check for validity of general properties (e.g. runtime memory errors, analysis of code metrics), but this is far beyond the topic of this document.
A simple and standard way to proceed is to define test applications that take different arguments:
- an argument represents the tested functionality (e.g. “first” in the previous example). A functionality can be seen as a particular use of the testes library’s API in order to obtain a given behaviour. It is implemented as a particular block of code inside the test application.
- one or more arguments represent input parameters (e.g. “124” in first test).
- one or more arguments represent the expected output parameters (e.g. “12” in first test).
- the test program (e.g.
my-test) calls the adequate target functionality (e.g. “first”) of the tested library (e.g.my-shared-lib) with adequate input parameters (e.g. “124”) and check if the result is the expected one (e.g. “12”). If successful it returns 0, otherwise it returns an error code (something else than 0).
The previous code will automatically generate a sequence of tests whose result is PASSED or FAILED according to the result returned by the test program. The package cannot be installed in the wrkspace until all tests have PASSED.
Remark: If you want to use some program as test but also as an example for instance, then always declare it as an EXAMPLE_APPLICATION. Indeed, this way your test application will be installed and so will be usable by a third party user.
Generating API documentation
When a library is defined, it is intended to be used by third party developers. To this end, it is always useful to have a clear way to consult the API provided by this library. The API documentation has to be as close as possible to the source code, that is why the best way is to use an API documentation generation tool like doxygen and to automate its use directly during the build process.
PID automatically manages the generation of API documentation with doxygen. The generated documentation is installed in the binary package version folder in the share/doc/html sub-folder. If latex is installed on the building host, it is also possible to generate an equivalent pdf document that will placed in the share/doc/latex sub-folder.
The API documentation requires that the users document the header files contained in each sub-folder of include. Indeed, these headers constitue the interface of libraries defined in the package and this is the only part to document from a API user point of view. The way to document headers is defined by doxygen tooling. Generally speaking, it consists in defining comments with specific annotations in header files code. You can report to the wiki explaining how to document source code.
When developers have documented their headers, they have to do nothing more to get a standard html or pdf document automatically generated, API generation with CMake is completely managed by PID. The doxygen compiler generates a raw API documentation, that may be customize by following the next requirements:
- add some content in the
docsub-folder of the package’ssharefolder. Typically a set of images can be put in aimgsub-folder of thedocfolder. - modify the doxygen configuration file (
Doxyfile.in) that can be found in thedoxygensub-folder of the package’s share folder. This file is used by doxygen to know how to generate the documentation. For instance, one can modify the IMAGE_PATH contained in this file to make it reference the newimgfolder. - Then images can be referenced directly into doxygen headers comments using a specific keyword (
@image).
The main constraint
Configuring doxygen behaviour is far beyond the scope of this document. The only thing that is absolutely required is to let some variables of the Doxyfile.in unchanged: all variables whose value is surrounded by the @ symbol must be let unchanged. These variables are automatically fill by PID cmake scripts, for instance:
...
# The PROJECT_NAME tag is a single word
PROJECT_NAME = "@DOXYFILE_PROJECT_NAME@"
# The PROJECT_NUMBER tag can be used to enter a version.
PROJECT_NUMBER = "@DOXYFILE_PROJECT_VERSION@"
# The OUTPUT_DIRECTORY tag is used to specify the (relative or
# absolute) base path where the generated documentation will
# be put.
OUTPUT_DIRECTORY = "@DOXYFILE_OUTPUT_DIR@"
...
# If the GENERATE_HTML tag is set to YES (the default) Doxygen
# will generate HTML output.
GENERATE_HTML= @DOXYFILE_GENERATE_HTML@
# The HTML_OUTPUT tag is used to specify where the HTML docs
# will be put.
HTML_OUTPUT= "@DOXYFILE_HTML_DIR@"When PID API generates the doxygen configuration file, it uses the Doxyfile.in pattern and automatically fills all fields surrounded by the @ symbol. Modifying these fields would provoke unexpected behaviours.
Adding package-specific content
The CMakeLists.txt of the share folder does not explicitly manage installation of the API documentation (it is automatically managed by PID). If developers add resources to the share folder like for instance images, these resources may be needed when the package binary is installed. This is the case when some components of the package require these resources at runtime. In such a case they have to be put in the share/resources folder (or any subfolder created by the user). The whole content of the share/resources folder will be automatically installed.
Nevertheless, you may need to install more resources (e.g. README files or folders containing technical documents) that are not used by components, then the CMakeLists.txt has to manage the installation of these resources, using the classical CMake install command. These resources have to be “manually” placed in the binary package’s share folder with a cmake command like:
install(DIRECTORY doc/documents DESTINATION ${${PROJECT_NAME}_INSTALL_SHARE_PATH})This later command will install the documents folder (that is in the share/doc folder) and all its content into the adequate share folder of the installed binary package. For simple files use the install(FILE ...) command.
Package development process control
PID packages provide a set of cache variables that are usd to control the build process of the package. The configuration of these CMake cache variables is basically made using ccmake .. command in the build directory of the package or by using Cmake configuration GUI. Depending on this configuration there will build command available or not, and the whole build process will behaves differently.
All these options and related behaviors are explained here.
Understanding the result
From the complete build/install process an “installed version” of the package is generated and put into the adequate folder of the workspace. The install process is managed by PID system so developer should not worry about how it takes place. The only exception is for documents and other resources (like images) placed into the source package repository’s share folder that must be installed “by hand”.

The figure provides an example of the workspace’s install folder containing two installed packages for a given platform (x86_64_linux_stdc++11). There can be many versions of the same package installed in the workspace for teh same platform, as for the package another-package, that has two versions installed. The installers folder of this package may contains many binary package version relocatable archive (quickly called “package installers”), for instance two for each installed version. Indeed each binary version is associated with two package installers: one for Release mode and one for Debug mode.
Package installers are tar.gz archives (cmake is able to compress and extract those archives in a cross-platform way) with following pattern for their name: <package name>-<package version number>[-dbg]-<platform>.tar.gz. Package installers for Debug mode have an additional -dbg postfix notation appended to their name and version.
Each binary package version folder also have a .rpath folder which is a PID specific folder used for configuring runtime links of PID components. It contains, for each binary executable component (shared or module libraries binaries, applications binaries) of the package a set of symbolic links that points to the adequate shared libraries or executable. PID system can reconfigure “on demand” run-time dependencies depending on the shared libraries versions installed and used. This system allows to create relocatable and reconfigurable binary code without using system mechanisms.
Generally speaking users should never change the content of any of those folders “by hand”, otherwise it could cause troubles.