package is the basic working unit for developers: it is in the same time a CMake C/C++ project and a git repository. It basically contains:
- the functional source code of the project (header and source files, configuration files, scripts).
- git version control information.
CMake projects files used to :
- build the source code and the documentation
- run tests
- generate configuration files
- install its resulting binaries in the workspace
- generate an installable relocatable archive.
The main idea is that a package is self-explanatory. It does not means it contains all code and artefacts it uses but it contains all information needed to satisfy its dependencies. In other words considering a given package, its installation process is done using this information and the information contained in its dependent packages.
A package provides some functional code that can be reused (libraries, executables, header files, scripts, etc.) and depends on other packages either for its compilation (e.g. archive libraries, header files) or for its runtime use (dynamic libraries, executables, script-like files).
A package has two main different forms :
- a source form. In this form, the package is a git repository that contains the package’s source code. It is something alive that is continuously evolving along development process.
- a binary form. In this form, the package is a collection of software artifacts (headers, configuration files, executables, libraries, documentation, etc.) deployed in a given place of a file system. A binary package can be embedded into an archive in order to be easily retrieved and deployed on a file system.
In all this web site, we use the term package to say source form package. If we speak about the binary form of the package we use the term binary package.
One important concept when dealing with PID packages is the concept of component. A component is the generic term to denote a unitary software artifact that is contained in a package. As well as packages, components have a source form (its source files and all configuration elements used to build it) and a binary form (its public headers and/or the binary object resulting from the build process) when installed.
Within PID there are different kind of components:
- header libraries (compile time only linked library). A header library is made only of public C/C++ headers files (no binary object) and so its binary form is the same as its source form.
- static libraries (link time only linked library). A static library is made of a set of public C/C++ headers and source files that result in an archive of binary objects (a
- shared libraries (load-time linked library). A shared library is made of a set of public C/C++ headers and source files that result in a shared binary object (a
- module libraries (run-time dynamically linked library). A module library is only made of source files that result in a shared binary object (a
.solibrary), that will be linked at runtime. If the module library contains a python package description file (i.e.
__init__.py) then it is also considered as a python module.
- applications. An application is a set of source files that result in a binary executable.
- example applications. An example application is the same as an application, but the binary will not be deployed with its containing package, it’s source code is just used to enrich documentation. They are typically used to demonstrate how to use libraries.
- test application. This is the same as an application but implementing test units that will not be deployed with the package. They are used internally to test other components of the package.
- pure Python package. This a folder declared as a Python package (i.e. containing a
__init__.pyfile) that contains only Python scripts. This component is never built.
A package is implemented as folder hierarchies inside a worskpace. There are basically two types of folder hierarchies:
- the one in the workspace
packagesfolder, that is the source project of the package.
- those in the workspace
installfolders, that are the binary versions of the package available for different platforms.
A Package is a CMake project structured according to the standard folder hierarchy defined below:
- the root folder of the package has the name of the package. This folder is basically a git repository which allows to manage concurrent work and version control on a package’s content.
.gitfolder contains version control related information, automatically managed by the git tool.
- the root
.gitignorefile is used to exclude from version control some artefacts like temporary files.
CMakeLists.txtfile is used to describe how to build, install and test the whole package. It also contains meta-information on the package (authors and institutions, repository address, license, etc.).
buildfolder contains results from build process and contains two subdirectories:
debug. Each of them contains the hierarchy of files and artefacts generated by the compilation process with the corresponding build configuration.
srcfolder contains sources files (.c/.cpp/.cc/.cxx in C/C++) of libraries. Each subdirectory of
srccontains sources use to build one or more library and is itself hierarchically organized according to developers needs. Libraries provided by the package are defined by the
CMakeLists.txtfile contained in the
includefolder contains interface description files, typically exported (i.e. installed) headers files (.h, .hpp, .hh, .hxx) in C/C++. Hierarchical organization in this directory is the same as in
src. Non exported headers are let in the
srcfolder, as they are not considered as a part of the interface of the library.
appsfolder contains source files for applications, an application being an example for the usage of a library, a runtime component or a end-user software. Each subdirectory of
appscontains sources for one or more built application and is hierarchically organized according to developers needs. Applications provided by the package are defined by the
CMakeLists.txtfile contained in the
testfolder contains source files for test units. Each subdirectory of
testcontains sources for one or more test unit. Custom test programs and running tests applied to the package are defined by the
CMakeLists.txtfile contained in the
sharefolder contains user written documents and some specific files used by the build process. It also contains a
CMakeLists.txtfile that can be used to perform specific action at install time, particularly the description of python packages. The share folder has following subdirectories:
doxygenfolder contains a default
Doxyfile.infile that is used by doxygen to generate API documentation. This file can be modified by the user to add additional information to the generated documentation. The folder can also contain additional resources (like images), hierarchically organized according to developers needs, used by doxygen to integrate additionnal information in the API documentation.
cmakefolder contains cmake scripts (notably find scripts) that the package uses to find external resources like libraries. This is the place used only for very specific resources for which no default cmake script is available.
resourcesfolder contains resources files used by libraries and applications/tests of the package.
cifolder contains scripts used during continuous integration process.
sitefolder contains markdown/html and image files used to generate static pages documenting the project.
scriptfolder contains python packages description.
license.txtfile contains the license that applies to the whole source code produced in the package. This file is generated by the build process.
README.mdfile contains the text presenting the package.
.gitlab-ci.ymlfile ise used to control and configure the continuous integration process of the package.
git repositories, whose content is structured according to the previously defined pattern.
git is used to version all text files used (C/C++ sources, cmake scripts, latex sources, etc.). Only source form of a package is a git repository not its binary form.
A package is continuously evolving along time and git provides an internal version representation of this evolution. Nevertheless, this representation is so fine grained (each time a modification is committed) that it is not really understandable by persons not involved in the package development. That is why we need a version representation that can be either understandable by users and developers. These versions, called release versions are defined according to a specific policy.
A release version can be viewed as a snapshot of the git repository at a given time of package’s life. It is associated to a number (called release version number) that is uniquely identifying the version. Technically, a version if represented as a git tag : a git tag memorizes a given state of the repository and is marked with a unique label that is used to retrieve this state. In our context the label of the git tag represents the release version number and the repository state pointed by the tag corresponds to the release version. The labelling of git tags representing release versions follows the pattern bellow:
- the release tags have the shape
Xis the major version number (starts with value 0). Change of major version number indicates that the code is no more completely backward compatible with previous versions. In other words, the interface of the package (some of the headers files it contains) has been modified in such a way that some functions have change or disappeared, or the behaviour/meaning of existing functions completely changed. While
Xis 0 the version is considered as pre-released and so is not ready for use by third party developers.
Yis the minor version number (starts with value 0). It indicates an improvement that is completely backward compatible with previous version with same major version number. In other words, the only a little change of existing behaviours occurred OR the interface of the package has been improved with new functionalities without breaking the way one may have used the older functionalities.
Zis the patch version (starts with value 0). It represents a simple bug fix or a security fix. A patch changes nothing to the interface (no new behaviour/functionality) and modify only in a minimal way the internal behaviour.
Each time a new version of a package is released, its version number must be incremented according to the previously defined rules and a corresponding git tag is created. Here are some examples:
0.1.0is the first pre-released version of the package.
0.Y.Zare early development pre-released version of the package.
1.0.0is the first release of source code.
1.2.0is a release of source code backward compatible with version
1.2.5is a release of source code of version
1.2after 5 bug/security fixes.
2.0.0is a release that is no more backward compatible with
For a deep explanation one the reasons to use this kind of “strict” scheme, one can report to semantic versionning. The release version number is the primary information that developpers must keep coherent during the development process. Indeed, it will be used to find an adequate version of a package (in function of a specified constraint) after this later has been installed. This is a fundamental information to deal with dependencies.
Considering the branching model and cooperative scheme used with PID you can simply report to the git guide.