Order of defining variables and including CPack

I am a bit confused regarding cpack_add_component() and various CPACK_COMPONENT_ in comparison to when CPack is included. I am just looking for some clarity here.

It seems that cpack_add_component() essentially defines some CPACK_COMPONENT_. It seems that this cpack_add_component()

cpack_add_component(qwunits_dev
  DISPLAY_NAME "QW Units Development"
  DESCRIPTION "Development package for QW Units"
  DEPENDS qwunits_runtime

Is more or less equivalent to

set(CPACK_COMPONENT_QWUNITS_DEV_NAME qwunits_dev)
set(CPACK_COMPONENT_QWUNITS_DEV_DISPLAY_NAME "QW Units Development")
set(CPACK_COMPONENT_QWUNITS_DEV_DESCRIPTION "Development package for qwunits")
set(CPACK_COMPONENT_QWUNITS_DEV_DEPENDS qwunits_runtime)

In my case I want to rename the debian package file name that gets generated. So, I have a couple of CPACK_DEBIAN_ defines.

set(CPACK_DEBIAN_QWUNITS_DEV_PACKAGE_NAME libqwunits-dev)
set(CPACK_DEBIAN_QWUNITS_DEV_FILE_NAME "libqwunits-dev_${CPACK_DEBIAN_QWUNITS_PACKAGE_VERSION}-${CPACK_DEBIAN_QWUNITS_PACKAGE_RELEASE}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")

What I have found is that if I try to use cpack_add_component() prior to including CPack I get an error that I can’t use cpack_add_component() until after I include CPack.

If I define the CPACK_DEBIAN_QWUNITS_DEV_FILE_NAME after include CPACK it doesn’t seem to change the file name. So, it appears that CPACK_DEBIAN_ values need to be defined prior to include(CPack).

If I don’t use cpack_add_component() and set the variables directly before including CPack then I do seem to get the file names changed.

#cpack_add_component(qwunits_dev
#  DISPLAY_NAME "QW Units Development"
#  DESCRIPTION "Development package for QW Units"
#  DEPENDS qwunits_runtime
#)
set(CPACK_COMPONENT_QWUNITS_DEV_NAME qwunits_dev)
set(CPACK_COMPONENT_QWUNITS_DEV_DISPLAY_NAME "QW Units Development")
set(CPACK_COMPONENT_QWUNITS_DEV_DESCRIPTION "Development package for qwunits")
set(CPACK_COMPONENT_QWUNITS_DEV_DEPENDS qwunits_runtime)
set(CPACK_DEBIAN_QWUNITS_DEV_PACKAGE_NAME libqwunits-dev)
set(CPACK_DEBIAN_QWUNITS_DEV_FILE_NAME "libqwunits-dev_${CPACK_DEBIAN_QWUNITS_PACKAGE_VERSION}-${CPACK_DEBIAN_QWUNITS_PACKAGE_RELEASE}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")

include(CPack)

This seems to do what I want and set the filename to what I want.

So, if I want to keep my CPACK_COMPONENT_ definitions and CPACK_DEBIAN_ definitions together I need to set them directly prior to include(CPack) line. I would not be able to use cpack_add_component() unless I put the CPACK_DEBIAN_ definitions prior to include(CPack) and then I could use cpack_add_component() after include(CPack). They could not be put together if I want to use cpack_add_component().

Do I have that correct?

Also, do I have it correct that cpack_add_component just sets the corresponding CPACK_COMPONENT_ values. So I don’t really lose anything by directly setting the CPACK_COMPONENT_ instead of using cpack_add_component()?

Thanks

Chris

I think the intention was that the functions cpack_add_component(), cpack_add_component_group(), etc. could be called before or after the include(CPack). The implementation of those functions each have a block like the following near the end:

  # Backward compatibility issue.
  # Write to config iff the macros is used after CPack.cmake has been
  # included, other it's not necessary because the variables
  # will be encoded by cpack_encode_variables.
  if(CPack_CMake_INCLUDED)
    file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" "${_CPACK_ADDGRP_STR}")
  endif()

This suggests placement shouldn’t matter, but I found long ago that trying to use them before include(CPack) didn’t seem to work properly. I’ve always put them after include(CPack) as a result, which is also what my Professional CMake book recommends. It has been a very long time since I last investigated that behavior. I no longer recall the exact details of what the problems are.

I do recommend using the commands over setting the raw variables directly. The commands more clearly express the intent and are generally more readable when defining many components and groups.

Thanks for the response,

This is what I get if I have something like this:

195: cpack_add_component(Test_component
196:   DISPLAY_NAME "Test Component"
197:   DESCRIPTION "This is a test component"
198:   DEPENDS qwunits_runtime
199: )
200:
201: include(CPack)

Here is the output:

[proc] Executing command: /usr/local/bin/cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=/home/chrisk/Projects/src/qwunits/cmake/arm64_toolchain.cmake -S /home/chrisk/Projects/src/qwunits -B /home/chrisk/Projects/src/qwunits/build/arm64-debug -G Ninja
[cmake] CMake Error at CMakeLists.txt:195 (cpack_add_component):
[cmake]   Unknown CMake command "cpack_add_component".
[cmake] 
[cmake] 
[cmake] -- Configuring incomplete, errors occurred!
[proc] The command: /usr/local/bin/cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=/home/chrisk/Projects/src/qwunits/cmake/arm64_toolchain.cmake -S /home/chrisk/Projects/src/qwunits -B /home/chrisk/Projects/src/qwunits/build/arm64-debug -G Ninja exited with code: 1

Putting the include(Cpack) first and it succeeds

include(CPack)
cpack_add_component(Test_component
  DISPLAY_NAME "Test Component"
  DESCRIPTION "This is a test component"
  DEPENDS qwunits_runtime
)

Result:

[main] Configuring project: qwunits 
[proc] Executing command: /usr/local/bin/cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=/home/chrisk/Projects/src/qwunits/cmake/arm64_toolchain.cmake -S /home/chrisk/Projects/src/qwunits -B /home/chrisk/Projects/src/qwunits/build/arm64-debug -G Ninja
[cmake] -- Configuring done (0.1s)
[cmake] -- Generating done (0.0s)
[cmake] -- Build files have been written to: /home/chrisk/Projects/src/qwunits/build/arm64-debug

I would like to use cpack_add_component() for all the individual libraries. But then I’ll have the CPACK_DEBIAN definitions that go with them in a far off place. I am not sure if order is important. I haven’t tested yet if the CPACK_DEBIAN__* is defined prior to the defining of the component itself matters. But having them not close to each other makes for more difficult maintenance.

I’ll have to think about this a bit.

Thanks

Chris

If you want to call commands like cpack_add_component() before include(CPack), you’ll need to put an include(CPackComponent) before the call.

[Edited]

Oops! I am sorry. In my haste I misspelled CPack with a lower case ‘p’. As you recommended this works:

include(CPackComponent)
cpack_add_component(Test_component
  DISPLAY_NAME "Test Component"
  DESCRIPTION "This is a test component"
  DEPENDS qwunits_runtime
)
include(CPack)

Results:

[proc] Executing command: /usr/local/bin/cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=/home/chrisk/Projects/src/qwunits/cmake/arm64_toolchain.cmake -S /home/chrisk/Projects/src/qwunits -B /home/chrisk/Projects/src/qwunits/build/arm64-debug -G Ninja
[cmake] -- Configuring done (0.0s)
[cmake] -- Generating done (0.0s)
[cmake] -- Build files have been written to: /home/chrisk/Projects/src/qwunits/build/arm64-debug

That will work fine for me.

Forget everything below here.

If I do that it complains that it can’t find CPack:

include(CPackComponent)
cpack_add_component(Test_component
  DISPLAY_NAME "Test Component"
  DESCRIPTION "This is a test component"
  DEPENDS qwunits_runtime
)
include(Cpack)

Result:

proc] Executing command: /usr/local/bin/cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=/home/chrisk/Projects/src/qwunits/cmake/arm64_toolchain.cmake -S /home/chrisk/Projects/src/qwunits -B /home/chrisk/Projects/src/qwunits/build/arm64-debug -G Ninja
[build] Starting build
[build] Build finished with exit code -1
[rollbar] Unhandled exception: Unhandled Promise rejection: cpack Error: Build failed. {}
[cmake] CMake Error at CMakeLists.txt:201 (include):
[cmake]   include could not find requested file:
[cmake] 
[cmake]     Cpack
[cmake] 
[cmake] 
[cmake] -- Configuring incomplete, errors occurred!
[proc] The command: /usr/local/bin/cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=/home/chrisk/Projects/src/qwunits/cmake/arm64_toolchain.cmake -S /home/chrisk/Projects/src/qwunits -B /home/chrisk/Projects/src/qwunits/build/arm64-debug -G Ninja exited with code: 1

AI Overview in google says this:


The issue encountered when including CPackComponent before include(CPack) arises because CPackComponent relies on the CPack module being loaded and initialized. CPackComponent provides functions like cpack_add_component, which are part of CPack's component-based packaging system.
When include(CPack) is executed, it loads the main CPack module, which sets up the necessary variables, functions, and infrastructure for CPack to operate, including the component-related functionalities. If CPackComponent or its functions are called before include(CPack), CMake will report an error because the required definitions are not yet available.

To resolve this, ensure that include(CPack) is called before any use of CPackComponent or its related commands, such as cpack_add_component.
A typical order in a CMakeLists.txt file would be:
Code

# ... other CMake commands and project setup ...

# Set CPack variables and options (optional, but often done before including CPack)
set(CPACK_PACKAGE_NAME "MyProject")
set(CPACK_PACKAGE_VENDOR "MyCompany")
# ... other CPack variables ...

# Include the main CPack module
include(CPack)

# Now, use CPackComponent functions if needed
cpack_add_component(applications DISPLAY_NAME "My Application" DESCRIPTION "The main application files")
cpack_add_component(docs DISPLAY_NAME "Documentation" DESCRIPTION "User documentation and manuals")

# ... other CPack-related commands or installation rules ...

So it seems a whole bunch of stuff is defined in CPack that you can’t use before it gets loaded. AI overview’s recommendation is to set the variables directory prior to include then use cpack_add_component() after.

I could put my CPACK_DEBIAN_ settings to get the deb file name defined prior to include(CPack) and then use cpack_add_component() a few directories down where I use the install commands for each component. With some kind of comment stating that if you make changes here you may need to change CPACK_DEBIAN settings in a CMakeLists.txt file a few directories up. Essentially, rely on comments, instead of proximity, to keep the CPACK_DEBIAN and CPACK_COMPONENT settings in sync.

I am sure I can live with either using direct settings prior to include(CPack) or using cpack_add_components after include(CPack) and connecting settings using comments. Just have to sleep on it and decide which I like better.

Thanks

Chris

In the end I created a ${CMAKE_SOURCE_DIR}/cmake/cpack_debian.cmake file. It has the include(CPackComponent) in it. It uses the cpack_add_component() and defines all the debian specific settings.

include(CPackComponent)  # This allows me to use cpack_add_component()
# Define qwunits versioning
set(CPACK_PACKAGE_QWUNITS_VERSION_MAJOR "0")
set(CPACK_PACKAGE_QWUNITS_VERSION_MINOR "1")
set(CPACK_PACKAGE_QWUNITS_VERSION_PATCH "1")
set(CPACK_DEBIAN_QWUNITS_PACKAGE_VERSION ${CPACK_PACKAGE_QWUNITS_VERSION_MAJOR}.${CPACK_PACKAGE_QWUNITS_VERSION_MINOR}.${CPACK_PACKAGE_QWUNITS_VERSION_PATCH})
set(CPACK_DEBIAN_QWUNITS_PACKAGE_RELEASE "2")
# Set the CPACK_COMPONENTS for qwunits
cpack_add_component(qwunits_runtime
  DISPLAY_NAME "QW Units Runtime"
  DESCRIPTION "Runtime package for QW Units"
  # DEPENDS this does not depend on any other component
)
# set the CPACK_DEBIAN values
set(CPACK_DEBIAN_QWUNITS_RUNTIME_PACKAGE_DEPENDS "libstdc++6 (>= 12.2.0-14)" "libfmt9")
set(CPACK_DEBIAN_QWUNITS_RUNTIME_PACKAGE_NAME libqwunits)
set(CPACK_DEBIAN_QWUNITS_RUNTIME_FILE_NAME "libqwunits_${CPACK_DEBIAN_QWUNITS_PACKAGE_VERSION}-${CPACK_DEBIAN_QWUNITS_PACKAGE_RELEASE}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")

Rather than directly include it I set it to the CPACK_PROPERTIES_FILE before calling include(CPack). This is apparently a file that allows you to override the defaults and add non-standard settings.

set(CPACK_PROPERTIES_FILE ${CMAKE_SOURCE_DIR}/cmake/cpack_debian.cmake)
include(CPack)

This works fine and seems like the best way to implement things.

Thanks for being patient with me. Sorry about the typo that I realized I had made that sent me down a tangent.

Thanks

Chris

The CPACK_PROPERTIES_FILE variable is not documented. Software archaeology reveals that the file CPackProperties.cmake is generated by CMake when you set properties on installed files. This was added in 15a8af21.

There are usecases that you break by setting this variable manually.

Thanks for letting me know!

I switched back to using include.

include(${CMAKE_SOURCE_DIR}/cmake/cpack_debian.cmake)
include(CPack)

It still works fine.

Thanks

Chris