CPack Debian dpkg-shlibdeps with components

I’m trying to use CPACK_DEBIAN_PACKAGE_SHLIBDEPS but I’m getting errors despite setting up my RPATH correctly.

I think the issue is that I’m creating a componentized package and one of my executables depends on a library in a different component. The dpkg-shlibdeps command succeeds when creating a monolithic package (i.e. no components).

I tried to declare that dependency using CPACK_DEBIAN_ENABLE_COMPONENT_DEPENDS and setting CPACK_COMPONENT_<COMPNAME>_DEPENDS.

Is there something else I need to do?


Sorry for the two-fer, but I’m also seeing that enabling CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS produces many warnings of the form:

CMake Warning (dev) at /snap/cmake/793/share/cmake-3.19/Modules/Internal/CPack/CPackDeb.cmake:641 (message):
  Shared library './usr/bin/weightsdir_to_weightsfile' is missing soname or
  soversion.  Library will not be added to DEBIAN/shlibs control file.
Call Stack (most recent call first):
  /snap/cmake/793/share/cmake-3.19/Modules/Internal/CPack/CPackDeb.cmake:774 (cpack_deb_prepare_package_vars)
This warning is for project developers.  Use -Wno-dev to suppress it.

But weightsdir_to_weightsfile is an executable, not a shared library. What’s causing this?

Cc: @kyle.edwards

1 Like

Sorry for the two-fer, but I’m also seeing that enabling CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS produces many warnings of the form:

Well, I understand part of this issue. My executables are position-independent (PIE) so the file command—which CPackDeb.cmake uses to determine file types—claims they are shared libraries. I guess that warning is therefore benign, but the check itself is bogus. I don’t see why CMake shouldn’t be able to communicate these details to CPack much more directly.

For reference, here’s some console output showing the file command output:

alex@alex-ubuntu:~/Development/halide$ file ../halide-ubuntu/shared-Release/src/autoschedulers/adams2019/weightsdir_to_weightsfile 
../halide-ubuntu/shared-Release/src/autoschedulers/adams2019/weightsdir_to_weightsfile:
ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=d5488bb87ce7b3b99cf36480504683a27b0cd46b, for GNU/Linux 3.2.0, not stripped
alex@alex-ubuntu:~/Development/halide$ file ../halide-ubuntu/shared-Release/src/libHalide.so.12.0.0 
../halide-ubuntu/shared-Release/src/libHalide.so.12.0.0:
ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, BuildID[sha1]=30bcdd56ddaf5eb48200f6ce7c02341651d35204, with debug_info, not stripped

I think you can distinguish PIEs by whether they have interpreter in the output.

It pains me to say this, but I worked around the file detection by providing my own file command that awks the original file output and removes “shared object” from the output when “interpreter” is present.

# This is a horrible, ugly, hack to patch around
# CPack breaking on PIE executables.
real_file=$(which file)
mkdir -p "$halide_build_root/_shims"
cat <<EOM >"$halide_build_root/_shims/file"
#!/bin/bash -e
$real_file "\$*" | awk -f <(cat - <<'AWK'
  /ELF.*interpreter/ { sub("shared object","",\$0) }
  { print }
AWK
)
EOM
chmod +x "$halide_build_root/_shims/file"

Can someone please suggest an alternative? Why is this so broken?

Because CPack may be used without CMake.
So CPack generators do not make too strong assumption about informations that may comes from a CMake build.

Let me rephrase: why aren’t there CPack variables, which CMake could helpfully set when running include(CPack), that would communicate the list of executables and libraries explicitly, such that the determination suggested by those variables was not overridden by incorrectly parsing the output of file on each file globbed in the staging directory?

The culprit seems to be there:
https://gitlab.kitware.com/cmake/cmake/-/blob/master/Modules/Internal/CPack/CPackDeb.cmake#L163
as you said the executable type detection is not robust.

I suppose (not sure though) that CPackDeb needs to rediscover what are the list of executable from the list of (all) installed file because if ones tries to execute dkpg-shlibdeps without any executable it’ll fail?

So I guess a proper way to do that would be to add some way to force the execution of dkpg-shlibdeps by CPackDeb and by-pass the not so robust “is there an executable in the installed file”.

My suggestion is to patch and fix CPackDeb along this line.

I opened an issue: https://gitlab.kitware.com/cmake/cmake/-/issues/21831

Just to give you more detail on how CPack does not rely on CMake provided information.
There is already a mechanism of communication between CMake and CPack.
The example is the way CMake and CPack handle. “Absolute Install path”.

  1. CMake knows that some file are installed with absolute destination so it populates the CMAKE_ABSOLUTE_DESTINATION_FILES variable and write it to install.cmake when installing.

  2. CPack knows when the installation comes from a CMake build so it detect whether if CMAKE_ABSOLUTE_DESTINATION_FILES is defined in corresponding install.cmake and populate CPACK_ABSOLUTE_DESTINATION_FILES. See: https://gitlab.kitware.com/cmake/cmake/-/blob/master/Source/CPack/cmCPackGenerator.cxx#L909

  3. Now all CPack generators (mainly CPackDeb and CPackRPM) knows that fact and can do whatever is needed to handle those files.

So:

  • informations goes from CMake to CPack only in the case where the project is installed by CMake
  • if ones want to use CPack without CMake he can still populate CPACK_ABSOLUTE_DESTINATION_FILES by some other mean.

You could design the same kind of informations flow in order to provide CPackDeb with the needed information in some CPACK_INSTALLED_EXECUTABLES computed from yet to be defined CMAKE_xxx variable.

Note however that the cmake_install.cmake files produced by CMake may already contain the informations. In fact the generated command for installing an executable should look like:

file(INSTALL DESTINATION "/path/to/install/dir" TYPE EXECUTABLE MESSAGE_LAZY FILES "/path/to/build/dir/executable_name")

so we know that this installs an executable.

1 Like

This is very detailed and constructive. Thank you! :slight_smile:

This is roughly what I had in mind. Using the information in the cmake_install.cmake script seems even more promising.