Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to build debian package with CPack to execute setup.py?

Until now, my project had only .cpp files that were compiled into different binaries and I managed to configure CPack to build a proper debian package without any problems.

Recently I wrote a couple of python applications and added them to the project, as well as some custom modules that I would also like to incorporate to the package.

After writing a setup.py script, I'm wondering how to add these files to the CPack configuration in a way that setup.py get's executed automatically when the user installs the package on the system with dpkg -i package.deb.

I'm struggling to find relevant information on how to configure CPack to install custom python applications/modules. Has anyone tried this?

like image 667
karlphillip Avatar asked Aug 30 '11 20:08

karlphillip


1 Answers

I figured out a way to do it but it's not very simple. I'll do my best to explain the procedure so please be patient.

The idea of this approach is to use postinst and prerm to install and remove the python application from the system.

In the CMakeLists.txt that defines the project, you need to state that CPACK is going to be used to generate a .deb package. There's some variables that need to be filled with info related to the package itself, but one named CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA is very important because it's used to specify the location of postinst and prerm, which are standard scripts of the debian packaging system that are automatically executed by dpkg when the package is installed/removed.

At some point of your main CMakeLists.txt you should have something like this:

add_subdirectory(name_of_python_app)

set(CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE 1)

set(CPACK_PACKAGE_NAME "fake-package")
set(CPACK_PACKAGE_VENDOR "ACME")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "fake-package - brought to you by ACME")
set(CPACK_PACKAGE_VERSION "1.0.2")
set(CPACK_PACKAGE_VERSION_MAJOR "1")
set(CPACK_PACKAGE_VERSION_MINOR "0")
set(CPACK_PACKAGE_VERSION_PATCH "2")
SET(CPACK_SYSTEM_NAME "i386")

set(CPACK_GENERATOR "DEB")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "ACME Technology")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.3.1-6), libgcc1 (>= 1:3.4.2-12), python2.6, libboost-program-options1.40.0 (>= 1.40.0)")
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_SOURCE_DIR}/name_of_python_app/postinst;${CMAKE_SOURCE_DIR}/name_of_python_app/prerm;")
set(CPACK_SET_DESTDIR "ON")

include(CPack)

Some of these variables are optional, but I'm filling them with info for educational purposes.

Now, let's take a look at the scripts:

postinst:

#!/bin/sh
# postinst script for fake_python_app

set -e

cd /usr/share/pyshared/fake_package
sudo python setup.py install

prerm:

#!/bin/sh
# prerm script
#
# Removes all files installed by: ./setup.py install
sudo rm -rf /usr/share/pyshared/fake_package
sudo rm /usr/local/bin/fake_python_app

If you noticed, script postinst enters at /usr/share/pyshared/fake_package and executes the setup.py that is laying there to install the app on the system. Where does this file come from and how it ends up there? This file is created by you and will be copied to that location when your package is installed on the system. This action is configured in name_of_python_app/CMakeLists.txt:

install(FILES setup.py
        DESTINATION "/usr/share/pyshared/fake_package"
)

install(FILES __init__.py
        DESTINATION "/usr/share/pyshared/fake_package/fake_package"
)

install(FILES fake_python_app
        DESTINATION "/usr/share/pyshared/fake_package/fake_package"
)

install(FILES fake_module_1.py
        DESTINATION "/usr/share/pyshared/fake_package/fake_package"
)

install(FILES fake_module_2.py
        DESTINATION "/usr/share/pyshared/fake_package/fake_package"
)

As you can probably tell, besides the python application I want to install there's also 2 custom python modules that I wrote that also need to be installed. Below I describe the contents of the most important files:

setup.py:

#!/usr/bin/env python
from distutils.core import setup

setup(name='fake_package',
      version='1.0.5',
      description='Python modules used by fake-package',
      py_modules=['fake_package.fake_module_1', 'fake_package.fake_module_2'],
      scripts=['fake_package/fake_python_app']
     )

_init_.py: is an empty file.

fake_python_app : your python application that will be installed in /usr/local/bin

And that's pretty much it!

like image 170
karlphillip Avatar answered Sep 18 '22 07:09

karlphillip