Packaging with CPack in Nebula Graph

Laura
2020-05-19

Packaging with CPack in Nebula Graph

CPack is a powerful, easy to use, cross-platform software packaging tool distributed with CMake since version 2.4.2. It helps create binary package and source code package. The following figure shows where CPack locates in the whole CMake tool chain.

The CMake tool chain

CPack supports the following types of package formats:

  • 7Z (7-Zip file format)
  • DEB (Debian packages)
  • External (CPack External packages)
  • IFW (Qt Installer Framework)
  • NSIS (Null Soft Installer)
  • NSIS64 (Null Soft Installer (64-bit))
  • NuGet (NuGet packages)
  • RPM (RPM packages)
  • STGZ (Self extracting Tar GZip compression
  • TBZ2 (Tar GZip compression)
  • TXZ (Tar XZ compression)
  • TZ (Tar Compress compression)
  • ZIP (ZIP file format)

Why Packaging Tools

The one-click installation package facilitates the deployment and usage of your software in production so that you can concentrate on your work rather than the software itself.

CPack can be used by specifying a CPackConfig.cmake file without CMake or as a module of CMake.  As a built-in tool for CMake, CPack supports to generate the binary installer in multiple formats and is easy to use. You can just configure it in the CMakeLists.txt file.

How to Install CPack

CPack is installed along with CMake or you can install it separately via yum or apt-get.

A Packaging Example

Basic Configuration

The rpm files are very similar to deb files and their differences lie mainly in configurations. Here we use rpm packages as an example. CPack packages rpm with the CPack RPM generator. All the configurations used are prefixed with CPACK_RPM. The rpm-build tool is used to build the package, so make sure it has already been installed. You can install rpm-build via sudo yum install -y rpm-build. In our example, we’re using CMake 3.14.5.

The following is the structure of our sample project:

example
	|-- CMakeLists.txt            // Main CMakeLists.txt file of the project
	|-- Readme.txt
	|-- License.txt
	|-- src
	|	  |-- CMakeLists.txt
	|	  |-- MainA.cpp             // Source code of the executable file Aprogram
	|	  |__ MainB.cpp             // Source code of the executable file Bprogram
	|
	|-- etc
	|	  |-- CMakeLists.txt
	|	  |-- A.conf                // Configuration file of the executable file Aprogram
	|	  |__ B.conf                // Configuration file of the executable file Bprogram
	|
	|__ scripts
	     |-- preinst              // Script to be executed before installation
	     |-- postinst             // Script to be executed after installation
	     |-- prerm                // Script to be executed before uninstallation
	     |__ postrm               // Script to be executed after uninstallation

Add the following configurations to the example/CMakeLists.txt file.

# Set Package Name
set(CPACK_PACKAGE_NAME "example")
# Enable Customized Installation Directory With ON
set(CPACK_SET_DESTDIR ON)
# Set Installation Directory
set(CPACK_INSTALL_PREFIX "/home/vesoft/install")
# Set The Version Information of The Installation Package
set(CPACK_PACKAGE_VERSION "1.0.0")
# Set The Group Name
set(CPACK_RPM_PACKAGE_GROUP "vesoft")
# Set The Vendor Name
set(CPACK_PACKAGE_VENDOR "vesoft")
# Set The License Information
set(CPACK_RPM_PACKAGE_LICENSE "Apache 2.0 + Common Clause 1.0")
include(CPack)

When the cmake command is run, two new files will be generated in the current directory: CPackConfig.cmake and CPackSourceConfig.cmake. When compilation is completed, run cpack -G RPM to pack the files into an rpm package. You will find a new directory _CPack_Packages and a file with .rpm extension example-1.0.0-Linux.rpm is generated in the current directory. The installation package file is named example-1.0.0-Linux.rpm, which is the target package.

If you want to check detailed outputs when packing, add --verbose behind the cpack -G RPM command. CPack generates the _CPack_Packages/Linux/RPM/SPECS/example.spec file which is used to build the rpm based on the customer configuration.

The installation package example-1.0.0-Linux.rpm generated by the above configuration contains the following files:

image

Note: if there is a conflict during the installation like this file /home from install of example-1.0.0-1.x86_64 conflicts with file from package filesystem-3.2-25.el7.x86_64, add the following configurations to exclude /home and /home/vesoft in the generated rpm file.

set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/home")
list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/home/vesoft")

Adding Behaviors

You can embed a pre/post (un)installation script in the spec file:

  • preinst: Pre install script
  • postinst: Post install script
  • prerm: Pre uninstall script
  • postrm: Post uninstall script

Add the following configurations in the above CMakeLists.txt file:

# Set the script preinst to be executated before installation
set(CPACK_RPM_PRE_INSTALL_SCRIPT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/scripts/preinst)
# Set the script prerm to be executated before uninstallation
set(CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/scripts/prerm)
# Set the script postinst to be executated after installation
set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/scripts/postinst)
# Set the script postrm to be executated after uninstallation
set(CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/scripts/postrm)

Note: The above four scripts require execute permissions for all users and user groups. You can change the file permissions under the script directory with chmod 755 scripts/* after creating the scripts.

Call the sudo rpm -ivh example-1.0.0-Linux.rpm and you’ll see the following outputs:

image

Run the sudo rpm -e example-1.0.0 and you’ll see the following outputs:

image

The green and red words in the pictures are the printouts of the pre/post (un)installation scrip, which indicates they are executed as expected or not.

Generating Multiple Packages With CPackComponent

The above configuration packs all the files to a single installation package. However, often a project contains multiple services which will be deployed on different machines. In this case, you don’t want to pack all of them into one package because this will make the package too large in size. At this time, you need the CPack components.

We will introduce to you the three CPack component functions in the following section: cpack_add_component, cpack_add_component_group and install.

Add a definition for the install function:

image

Add a definition for the cpack_add_component function:

image

Add a definition for the cpack_add_component_group function:

image

Assume we are packing program A and its configuration file A.conf into an rpm package, program B and its configuration file B.conf into another rpm package, we need to replace the include(CPack) of the above example/CMakeLists.txt with the following configurations:

# Set one rpm package per group
set(CPACK_COMPONENTS_GROUPING ONE_PER_GROUP)
# Enable COMPONENT
set(CPACK_RPM_COMPONENT_INSTALL ON)

include(CPack)

# Add a component named AComponent
cpack_add_component(AComponent
    DISPLAY_NAME  "A program"
    DESCRIPTION   "The program for test"
    GROUP Aprogram)
# Add a component named BComponent
cpack_add_component(BComponent
    DISPLAY_NAME  "B program"
    DESCRIPTION   "The program for test"
    GROUP Bprogram)
# Add a group named Aprogram, this will make part of the rpm package name
cpack_add_component_group(Aprogram)
# Add a group named Bprogram
cpack_add_component_group(Bprogram)

Then modify src/CMakeLists.txt, as show below, the config the  COMPONENT option of installation rules of program A and B to AComponent and BComponent

image

So as the etc/CMakeLists.txt

image

After that, re-run cmake command to generate a new makefile. Then call cpack -G RPM. Two files will be generated under the current directory, i.e. example-1.0.0-Linux-Aprogram.rpm and example-1.0.0-Linux-Bprogram.rpm, each of which contains the following files:

image

More Common Parameters

  • Cutomized installation directory: The package will be installed to the directory configured by CPACK_INSTALL_PREFIX, which is /home/vesoft/installin the configuration above. To build a relocatable RPM,, add the following configuration before include(CPack).
# Set CPACK_SET_DESTDIR to OFF
set(CPACK_SET_DESTDIR OFF)
# Enable the CPACK_RPM_PACKAGE_RELOCATABLE
set(CPACK_RPM_PACKAGE_RELOCATABLE ON)
# Set the default reset directory
set(CPACK_PACKAGING_INSTALL_PREFIX "/home/vesoft/install")

The relocatable RPM can be installed using:

sudo rpm -ivh example-1.0.0-Linux-Aprogram.rpm --prefix=/home/test/install

You can use CPACK_RPM_SPEC_MORE_DEFINE option to add any %define lines to the generated spec file.

More About CPack

There are many parameters for CPack. And parameters in different versions may vary. Please refer to the CPack Site for details or use CPack --help for more information.

Applying CPack in Nebula Graph

We use CPack to pack rpm and deb packages for Nebula Graph. Click here to get packages of each release version.

image

You might also like:

  1. Automating Your Project Processes with Github Actions
  2. Practice Jepsen Test Framework in Nebula Graph
  3. Integrating Codecov Test Coverage With Nebula Graph

Hi, I’m Laura, an engineer at Nebula Graph. Hope my post is of help to you. Please let me know if you have any ideas about this. Thanks

Like what we do ? Star us on GitHub. https://github.com/vesoft-inc/nebula