cmakedebcpack

CMake/CPack DEB - How to add a postinstall script to a single subdirectory?


I have a single project with several subdirectories. Each subdirectory must generate a deb package. One of these packages must contain a post-installation script.

I just can't manage to find a way to set the post-installation script for a single component. I've tried quite a lot of variables combinations, but I'm obviously missing something.

Following is a MWE.


Project overview

The project is structured as follows:

tst_deb_components/
├── build.sh
├── c1
│   ├── CMakeLists.txt
│   ├── main.c
│   └── postinst
├── c2
│   ├── CMakeLists.txt
│   └── main.c
└── CMakeLists.txt

Note that both main.c are simply "hello world". could have been just files.

Files content

build.sh

#!/bin/bash

DIR_BUILD="_build"

set -e

if [[ -d "${DIR_BUILD}" ]]
then
    rm -rvf ${DIR_BUILD}
fi

if [[ -d "_packages" ]]
then
    rm -rvf _packages
fi

mkdir ${DIR_BUILD}

pushd ${DIR_BUILD}
cmake ..
cmake --build .
cpack
popd

CMakeLists.txt

cmake_minimum_required(VERSION 3.5)

project(
    tst_deb_components
    VERSION 0.1.2
)

set(COMPANY_NAME  "MyCompany")
set(
    CPACK_PACKAGE_NAME
        "${COMPANY_NAME}-${PROJECT_NAME}"
    CACHE STRING "The resulting package name"
)

set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})

set(CPACK_PACKAGE_CONTACT "contact@example.com")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "NOOOO OOOOOOOOONNNNNEEEEEE")

set(
    CPACK_PACKAGE_DESCRIPTION_SUMMARY
        "Dummy package to test postinst."
        CACHE STRING "Package description for the package metadata"
)

# Enable generating DEB packages
set(CPACK_GENERATOR "DEB")



set(CPACK_PACKAGE_VENDOR "NoVendor")

set(CPACK_VERBATIM_VARIABLES YES)

set(CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME})
SET(CPACK_OUTPUT_FILE_PREFIX "${CMAKE_SOURCE_DIR}/_packages")


set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT)

set(CPACK_COMPONENTS_GROUPING ONE_PER_GROUP)

# without this you won't be able to pack only specified component
set(CPACK_DEB_COMPONENT_INSTALL YES)

set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS YES)

set(
    CPACK_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS
        OWNER_READ OWNER_WRITE OWNER_EXECUTE
        GROUP_READ GROUP_EXECUTE
        WORLD_READ WORLD_EXECUTE
)


add_subdirectory( c1/ )
add_subdirectory( c2/ )


include(CPack)

c1/CMakeLists.txt

cmake_minimum_required(VERSION 3.5)

#project(
#   tst_deb_components
#   VERSION 0.1.2
#)
set(
    COMPONENT_NAME
        "c1"
)

add_executable(${COMPONENT_NAME} main.c)

install(TARGETS ${COMPONENT_NAME}
    COMPONENT
        ${COMPONENT_NAME}
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)


set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/postinst" PARENT_SCOPE)
set(CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION TRUE PARENT_SCOPE)

c1/postinst

#!/bin/bash


echo "########################################"
echo "# Hello from 'postinst' !"
echo "########################################"

c2/CMakeLists.txt

cmake_minimum_required(VERSION 3.5)

set(
    COMPONENT_NAME
        "c2"
)

add_executable(${COMPONENT_NAME} main.c)

install(TARGETS ${COMPONENT_NAME}
    COMPONENT
        ${COMPONENT_NAME}
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

Some of the tests I've done

I'll only list tests that seems to be relevant.

To get a description of what's inside the package, I'm using dpkg-deb --info ./<package>.

As-is, when I build using build.sh, I get two packages with the postinst script in both, where I'd expect it to only be in the package for c1.

If I remove the PARENT_SCOPE directive from the set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA [...]) command, then the postinst script is gone from both packages.

Any help greatly appreciated! After struggleing for two days, I've started to loose my mind.


Solution

  • Answering my own question thanks to a friend:

    What I was missing :

    If someone needs it, my final c1/CMakeLists.txt file for the MWE looks like this:

    cmake_minimum_required(VERSION 3.5)
    
    set(
        COMPONENT_NAME
            "c1"
    )
    
    string(
        TOUPPER
            ${COMPONENT_NAME}
            COMPONENT_NAME_UPPERCASE
    )
    
    add_executable(${COMPONENT_NAME} main.c)
    
    install(TARGETS ${COMPONENT_NAME}
        COMPONENT
            ${COMPONENT_NAME}
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
    )
    
    
    set(
        CPACK_DEBIAN_${COMPONENT_NAME_UPPERCASE}_PACKAGE_CONTROL_EXTRA
            "${CMAKE_CURRENT_SOURCE_DIR}/postinst"
    
        CACHE
            STRING
            "Component ${COMPONENT_NAME} - CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA"
            FORCE
    )
    set(
        CPACK_DEBIAN_${COMPONENT_NAME_UPPERCASE}_PACKAGE_CONTROL_STRICT_PERMISSION
            TRUE
    
        CACHE
            STRING
            "Component ${COMPONENT_NAME} - CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION"
            FORCE
    )