Tutorial - Creating a package
Step 2 : Create a new package
Now let’s suppose you want to create a new package:
cd <pid-worskspace>
pid create package=my-first-package author="My Name" institution="LIRMM"The package has been created and is purely local to you workspace (nobody knows about it and can access to it except yourself). One of the first thing to do is to connect it to a remote repository on the gitlab server. To do so:
-
create a gitlab project (in your account or in a group if you have the adequate rights in this group). Simply push the
New Projectbutton in gitlab dashboard. You must give to this repository the same name as your newly created package : in this examplemy-first-package! -
Once created your server repository is empty but it has an address like
git@gite.lirmm.fr:own/my-first-package.git. You must now connect it to the PID package you just created:
cd <pid-worskspace>
pid connect package=my-first-package official=git@gite.lirmm.fr:own/my-first-package.gitWell done ! The package is now connected to the remote repository on the server ! You can now start developping the package.
Remark
You can do a all in one command to create and connect the newly created package:
cd <pid-worskspace>
pid create package=my-first-package url=git@gite.lirmm.fr:own/my-first-package.git2.1 Look at git branches
A PID package has two standard git branches:
masterbranch always reflects the last released version of the package. This branch is used only to get and publish updates of the package.integrationbranch is where developpers actually work. This branch is used to directly develop new functionnalities or to merge patches coming from feature specific branches.
After creation the package repository is on integration branch, just do:
cd <pid-worskspace>/packages/my-first-packages
git branch -aYou should see a star * in front of the integration branch indicating that this is the current branch. From developper perspective, they should always work on integration branch or on feature specific branches but never directly on master branch.
2.2 Look at git remotes
A PID package has two standard git remotes defined:
-
officialremote is the online repository (in your project server) that is referenced inside the workspace. It is used to update package and to release its versions using tags. The address bound to the official remotes is the address defined with theurlargument in connect and create commands. It is also the address defined in the rootCMakeLists.txtfile of your package (see next section). -
originremote is the online repository you are currently working with. Most of time, and after creation,originhas exactly the same value thanofficial. But sometimes you need to work on an isolated online repository (typically after a fork of the official repository) that you can update. Keep in mind that even if you work with a different origin, updates and releases of the package always target theofficialrepository.
After these preliminary explanations, let’s code !
Step 3 : Write code and describe package content
For the remaining of this section we name <my-first-package> the path to the newly created package for the sake of readability.
3.1 Edit package content description
The first thing to do is to edit the package meta-information. This is achieved by editing the root CMakeLists.txt file of the package.
At the beginning, your package’s root CMakeLists.txt file should look like this:
cmake_minimum_required(VERSION 3.15.7)
set(WORKSPACE_DIR ${CMAKE_SOURCE_DIR}/../.. CACHE PATH "root of the packages workspace directory")
list(APPEND CMAKE_MODULE_PATH ${WORKSPACE_DIR}/cmake) # using generic scripts/modules of the workspace
include(Package_Definition NO_POLICY_SCOPE)
project(my-first-package)
PID_Package(AUTHOR My Name
INSTITUTION LIRMM
YEAR 2015
ADDRESS git@gite.lirmm.fr:own/my-first-package.git
LICENSE CeCILL
DESCRIPTION TODO: input a short description of package toto utility here
VERSION 0.1.0
)
#now finding packages
build_PID_Package()As you may see the PID_Package function (equivalent to declare_PID_Package) is the function used to set the CMake project as a PID package and contains arguments whose values are set according to arguments you passed to the creation command (see previous sections). You may have to change some arguments that have default values if you do not set corresponding argument in the command. For instance, you can decide:
- to apply a given license (
CeCILLis acually the default license when packages are created) by changing the value of theLICENSEargument. - set the main author name by changing the value of the
AUTHORargument. By default the name is the name of your workstation current user if you do not set theauthorargument with the create command. - add (beside
INSTITUTIONline) a line to specify the email of the person to contact to have information about this package (well, yourself we presume):MAIL my.Name@mymail.fr. - provide a short description of the package replacing the line beginning by TODO.
There are many way to better document and formalize you package but these basic informations are sufficient.
The call to PID_Package also sets the current version using the VERSION argument. At beginning the version is 0.1.0. If the patch version is not specified, then it is considered as 0.
Finally, the last line of the package’s root CMakeLists.txt must be the call to build_PID_Package() macro. To be short, this macro does all the job for configuring the package adequately so never forget it.
As long as your package has no dependency you have nothing more to do in this root CMakeLists.txt file. Now, let’s add components to your package !
3.2 Create a library
Let’s suppose you want to create a very simple library printing an “Hello World” message in console by calling a function called, print_Hello(). We want this library to be a static (or shared) library, it will so need to have a header file and a source file.
3.2.1 Create folders containing sources
With PID, source files are not targeted directly, but instead you have to specify a folder that contains source and header files. When creating a static or shared library you basically have to create a folder that contains the sources, both in the include and in the src folders. Let’s call this folder hello.
cd <my-first-package>
mkdir src/hello
mkdir include/hello3.2.2 Define the library in PID
Now to inform the PID system that you want to create a library you have to edit the CMakeLists.txt file contained in the src folder. Write the following code:
PID_Component(STATIC_LIB NAME hello-static DIRECTORY hello)You just specify that the source code of the static library named hello-static is in the hello folder of both include and src folder (using the DIRECTORY keyword).
3.2.3 Write the code
Now you have of course to write C/C++ code of your library.
- Edit a file named
hello.hin theinclude/hellofolder and paste the following code:
#include <string>
void print_Hello(const std::string& user_input);- Edit a file named
hello.cppin thesrc/hellofolder and paste the following code:
#include <hello.h>
#include <iostream>
#ifdef DO_NOT_PRINT_HELLO
static std::string output_string = "Not Hello ";
#else
static std::string output_string = "Hello ";
#endif
using namespace std;
void print_Hello(const std::string& user_input){
cout<<output_string<<user_input<<endl;
}Now your library is completely defined.
3.2.4 Define another library, with the same code
With PID it is quite simple to define another component built from the same code ! As an example we will define a shared library from the exact same code as previously. To do this, you have to edit the CMakeLists.txt file contained in the src folder and write the following code at the end of the file:
PID_Component(SHARED_LIB NAME hello-shared DIRECTORY hello
INTERNAL DEFINITIONS DO_NOT_PRINT_HELLO)The things that changed are:
-
the name of the component (here
hello-shared). You just have to remember that components name are unique in the context of a package. -
the type of component (here a shared library using the
SHARED_LIBkeyword). -
a definition has been added to the compilation of the library code, using
INTERNAL DEFINITIONSkeywords.DO_NOT_PRINT_HELLOis so defined for this library only, this way the shared library will print “Not Hello “ as prefix of the output, instead of “Hello “ (look at hello.cpp).
3.3 Create an example application
Now let’s suppose we want to write an application using the previous library. The process is more or less the same.
3.3.1 Create the folder containing sources of the application
As previously, you have to create a folder that contains source of the application, but this time in the apps folder. We simply call this folder hello.
cd <my-first-package>
mkdir apps/hello3.3.2 Define the application in PID
To inform the PID system that you want to create an application you have to edit the CMakeLists.txt file contained in the apps folder. Write the following code:
PID_Component(hello-app APPLICATION DIRECTORY hello)As with libraries you just specify that the source code of the application named hello-app is in the hello subfolder of apps folder (using the DIRECTORY keyword).
Now as this application uses a library we have to define a dependency between the application and the library. Let’s suppose we use the static library hello-static defined previously.
PID_Component_Dependency(COMPONENT hello-app DEPEND hello-static)Here the important part is the DEPEND keyword followed by the name of the component in use (hello-static). It specifies that the hello-app component depends on a component called hello-static. Another way to define such a dependency is to use the DEPEND argument of the component declaration command, allowing so to define a component and its dependencies in the same time:
PID_Component(hello-app APP DIRECTORY hello
DEPEND hello-static)This is far more convenient to use when the dependency is simple to specify. Sometimes, more things have to be defined (e.g. preprocessor definitions) and then it is required to use the PID_Component_Dependency command that provides arguments to precisely set all aspects of the dependency.
3.2.3 Write the code
Now you have of course to write C/C++ code of your application. Edit a file named hello_main.cpp in apps/hello folder and paste the following code:
#include <hello.h>
#include <iostream>
using namespace std;
int main(int argc, char* argv[]){
if(argc == 1){
cout<<"Only one argument ... error !! Please input a string as argument of the program"<<endl;
return 1;
}
print_Hello(argv[1]);
return 0;
}Now your application is completely defined. It simply takes the arguments passed to the program and passed them to the call of the print_Hello() function so that they in turn will be printed on standard output after the prefix “Hello “ message.
Remark
More complete explanations about the usage of the PID API can be found here and an example giving deeper explanations is provided here.
Step 4 : Build and install a first version of your code
Now you have to build your code to get the resulting binaries.
cd <my-first-package>
pid buildThe build folder is used to perform out of source build with cmake. The build command perfoms build (compile + link) and install, all in one !! Depending on the option you choose the command may perform much more things. To know and set these options use the standard CMake configuration tool by doing:
cd <my-first-package>/build
ccmake ..All options and their influence on the build process are explained here.
The install process puts the generated files in the adequate places, in a folder corresponding to the current version. With the current settings of the package (see the root CMakeLists.txt file) it puts them in the folder <pid-workspace>/install/<platform>/my-first-package/0.1.0. You may see the resulting artefacts:
-
libhello-static.aandlibhello-shared.socan be found in thelibsubfolder. -
hello-appcan be found in thebinsubfolder.
To run the application simply do:
cd <pid-workspace>/install/<platform>/my-first-package/0.1.0/bin
./hello-app "this is my message"The console should print :
Hello this is my messageNow let’s see how to release your package.