When I run cpack -G DEB, cpack always generates a deb file named like:
projectname-version-Linux.deb
I don't like the Linux.deb name, can I change it to architecture name like -arm64.deb or -amd64.deb?
Related
For the following CMakeLists.txt file
cmake_minimum_required(VERSION 3.15)
project(Testing)
include(CMakePackageConfigHelpers)
configure_package_config_file(FooConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake
INSTALL_DESTINATION lib/Goo/dmake
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake
DESTINATION lib/Foo/cmake )
and the FooConfig.cmake.in file
#PACKAGE_INIT#
check_required_components(Foo)
It would finally install FooConfig.cmake to lib/Foo/cmake:
$ cmake ..
$ cmake --build .
$ cmake --install . --prefix ../install/
$ ls -R ../install/
../install/:
lib
../install/lib:
Foo
../install/lib/Foo:
cmake
../install/lib/Foo/cmake:
FooConfig.cmake
It seems that whatever value I set to the INSTALL_DESTINATION option of configure_package_config_file, it won't change FooConfig.cmake's installation directory. But if I comment INSTALL_DESTINATION lib/Goo/dmake, CMake Error prompts
No INSTALL_DESTINATION given to CONFIGURE_PACKAGE_CONFIG_FILE()
Then, what is the use of the INSTALL_DESINATION option? What its value (specifically, the above setting lib/Goo/dmake) actually affects?
The documentation:
The <path> given to INSTALL_DESTINATION must be the destination where the FooConfig.cmake file will be installed to.
I know the right way is INSTALL_DESTINATION lib/Foo/cmake. But as I deliberately set it as lib/Goo/dmake, the FooConfig.cmake file still rests at the desired destination lib/Foo/cmake. So, why this option is designed as a must?
The function configure_package_config_file only generates the file specified as the second argument. This function neither installs the generated file nor affects on its installation. So, its arguments can only affect on the content of the generated file.
If you look into the generated script FooConfig.cmake, then you could find the line like
get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)
This is how the script calculates installation prefix based on the path to the FooConfig.cmake file.
E.g. when you install the package with prefix /usr/local and your FooConfig.cmake script will be located in the directory /usr/local/lib/Foo/cmake, then the quoted path will be expanded into /usr/local/lib/Foo/cmake/../../../, which corresponds to /usr/local/.
Number of components ../ in the script equals to the number of components in INSTALL_DESTINATION parameter.
Why 'PACKAGE_PREFIX_DIR' is needed
Assume a package installs all public headers into directory include/ (relative to installation prefix), and config script needs to deliver that directory to the user via variable FOO_INCLUDE_DIR.
The most direct way would be to write in the script following:
# FooConfig.cmake.in
...
set(FOO_INCLUDE_DIR #CMAKE_INSTALL_PREFIX#/include)
so configure_package_config_file would substitute real install prefix instead of #CMAKE_INSTALL_PREFIX#.
But embedding absolute path into the config file prevents the package to be relocatable. So, once installed, the package could be used only from the installation directory, and cannot be copied elsewhere.
For relocatable package a config file computes all installation paths relative to the path of the config file itself, because it is the only path known to the script when it is called by find_package. It is like an executable can compute paths to the files located near to that executable.
If the script is installed into lib/Foo/cmake/FooConfig.cmake, then relative path to the include directory would be ../../../include, so one could use following assignment in that script:
# FooConfig.cmake.in
...
set(FOO_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../include)
So, when find_package(Foo) will execute this script, it expands the variable CMAKE_CURRENT_LIST_DIR to the actual directory with the possibly relocated script.
Operating with relative paths requires much attention from the coder, so CMake allows to automate this task:
# CMakeLists.txt
...
# Path to the include directory in the installation tree
set(INCLUDE_DIR 'include')
configure_package_config_file(FooConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake
INSTALL_DESTINATION lib/Foo/cmake
# Tell CMake to handle variable `INCLUDE_DIR` as a path
# under installation tree.
PATH_VARS INCLUDE_DIR
)
# FooConfig.cmake.in
#PACKAGE_INIT#
# Here we could use `#PACKAGE_INCLUDE_DIR#` as reference
# to variable 'INCLUDE_DIR' set in the CMakeLists.txt.
set_and_check(FOO_INCLUDE_DIR "#PACKAGE_INCLUDE_DIR#")
If you look into the generated file, you will find that #PACKAGE_INCLUDE_DIR#
is expanded into ${PACKAGE_PREFIX_DIR}/include, which uses the variable PACKAGE_PREFIX_DIR.
I'm using CMake v3.21.0 to invoke Qt's windeployqt during the install stage by the means of the install(CODE) command as follows:
install(
CODE "
execute_process(
COMMAND \"${CMAKE_COMMAND}\" -E
env PATH=\"${windeployqt_ROOT_DIR}\"
\"${windeployqt_EXECUTABLE}\"
# TODO(2021-08-25 by wolters): This is a different path when CPack is`
# used. How to check for this case and obtain the correct output path?
--dir \"${CMAKE_INSTALL_PREFIX}/${args_INSTALL_SUFFIX}\"
--no-quick-import
--no-system-d3d-compiler
--no-virtualkeyboard
--no-compiler-runtime
--no-webkit2
--no-angle
--no-opengl-sw
--verbose 0
\"\$<TARGET_FILE:${args_TARGET}>\"
)
"
COMPONENT runtime
)
This works fine if installing the project:
cmake --build . --config RelWithDebInfo --target install
But when creating a CPack package the files created by windeployqt are not part of the package (ZIP in this case):
cpack -G ZIP -C RelWithDebInfo -D CPACK_COMPONENTS_ALL="runtime"
I know that the issue is the usage of ${CMAKE_INSTALL_PREFIX} in the CODE.
For the install target this is correct.
For the package target this is not correct. Instead the build directory for the current CPack generator should be used, e.g. ${CMAKE_CURRENT_BINARY_DIR}/_CPack_Packages/win64/ZIP/${CPACK_PACKAGE_FILE_NAME}.
My questions are:
Is there a way to differentiate between install and package target in the CODE section? (pseudo-code: if(CMAKE_IS_PACKAGING))
If there is a way: Is it possible to obtain or dynamically build the directory path to the actual CPack temporary "install" directory?
If both problems can be solved the files generated by windeployqt should be part of the packages generated by CPack.
The variable CMAKE_INSTALL_PREFIX should not be expanded in the CMakeLists.txt, as you are doing. Its actual value at invocation time is available inside the install(CODE) fragments.
Consider the following snippet:
cmake_minimum_required(VERSION 3.21)
project(test NONE)
install(CODE [[message(STATUS "HERE: ${CMAKE_INSTALL_PREFIX}")]])
Note that [[ ... ]] escapes variable expansions (you could also use backslashes). Now if you configure this project with -DCMAKE_INSTALL_PREFIX=/tmp/install, you'll see the message print as you expect.
$ cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/tmp/install
-- Configuring done
-- Generating done
-- Build files have been written to: /home/alex/test/build
$ cmake --build build/ --target install
[0/1] Install the project...
-- Install configuration: ""
-- HERE: /tmp/install
If you now run the install script again without reconfiguring or rebuilding, it will still work:
$ cmake --install build/ --prefix /tmp/other-prefix
-- Install configuration: ""
-- HERE: /tmp/other-prefix
This is how CPack runs your install rules. It does not use the configuration-time value of CMAKE_INSTALL_PREFIX. It expects your project to be relocatable (i.e. bug-free).
I've got CMake (3.02) installing to a DESTDIR when I invoke:
$ make -C build DESTDIR=$(pwd)/build/rootfs install
This results in a file layout that I'm happy with: binaries are located in the .../build/rootfs/usr/local/bin directory and the init scripts are in .../build/rootfs/etc/init.d. To accomplish that, I used a mixture of relative and absolute paths in my CMakeLists.txt file:
set(CPACK_SET_DESTDIR ON)
...
INCLUDE(CPack)
...
set(ROOTFS_BIN_DIR bin)
set(ROOTFS_ETC_INITD_DIR /etc/init.d)
...
INSTALL(TARGETS myDaemon DESTINATION ${ROOTFS_BIN_DIR})
INSTALL(PROGRAMS myDaemon.sh RENAME myDaemon DESTINATION ${ROOTFS_ETC_INITD_DIR})
With that, I think 'working', I'm trying to create a simple tarball package which will eventually become a debian package (with pre/post install/remove scripts) but when I invoke:
$ make -C build DESTDIR=$(pwd)/build/rootfs package
I'm getting errors because cpack is attempting to write my init scripts to the system's /etc/init.d directory (instead of $(pwd)/build/rootfs/etc/init.d). If I wanted that, then $sudo !! would solve the problem. The error (replaced full path with ...):
CMake Error at .../build_src/cmdServer/cmake_install.cmake:44 (file):
file INSTALL cannot copy file
".../src/cmdServer/cmdServer.sh" to
"/etc/init.d/cmdServer".
I'm not using a lot of CPACK directives: in my top level CMakeLists.txt file I have:
SET(CPACK_SET_DESTDIR ON)
SET(CPACK_GENERATOR TGZ)
INCLUDE(CPack)
How can I package my init scripts correctly?
I've been referencing:
https://cmake.org/pipermail/cmake/2008-April/020833.html
and https://cmake.org/pipermail/cmake/2006-November/011890.html
I've seen many linux applications packaged with their binaries in some path like /opt/mypkg/myexecutable and a symlink to it in /usr/bin. I've seen these symlinks in the packaged files.
I want to do the same while packaging my software with cpack, creating deb and rpm packages with CPackDEB and CPackRPM.
Is it possible to create a symlink to an arbitrary, possibly non existent path?
Could I then use INSTALL(FILES "mysymlink" DESTINATION /usr/bin/myapp COMPONENT MyComponent)? (Would there be problems with symlinks being followed when the destination actually exists?)
Could I change the link destination with something like CONFIGURE_FILE()
Or am I just missing a cpack directive that does the job correctly?
Have a look at the following example:
cmake_minimum_required(VERSION 3.0)
project(myls NONE)
execute_process(COMMAND ln -s /opt/myapp/superls myls)
install(FILES ${CMAKE_BINARY_DIR}/myls DESTINATION /usr/bin/myapp COMPONENT MyComponent)
SET(CPACK_PACKAGE_CONTACT dmarquant)
include(CPack)
You can simply create a symlink to a non existing location and as you have written install it with install(FILES ...).
I would like to run configure_file() whose input file is generated using add_custom_command, through a custom dependency, before installing the output of configure_file.
I'm in reality using a ruby script to read a cmake formatted file, to extract
a few definitions which i can convert to Ruby constants in a separate library. Thus, i require the configure_file such that cmake can replace its internal variables in the ruby generated file, whose goal is to export these variables.
Thus far, I've attempted the following:
# Custom command to build the out.rb.in
add_custom_command (
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/output.rb.in"
COMMAND ruby ${CMAKE_CURRENT_SOURCE_DIR}/build_ruby_output.rb
-i ${CMAKE_CURRENT_SOURCE_DIR}/input.cmake
-o ${CMAKE_CURRENT_BINARY_DIR}/output.rb.in
)
# Custom target is required to build it
add_custom_target (
dummy_target_xxx ALL DEPENDS
"${CMAKE_CURRENT_BINARY_DIR}/output.rb.in"
)
configure_file (
"${CMAKE_CURRENT_BINARY_DIR}/output.rb.in"
"${CMAKE_CURRENT_BINARY_DIR}/output.rb"
)
install (
FILES "${CMAKE_CURRENT_BINARY_DIR}/output.rb"
DESTINATION "${RUBY_VENDOR_LIBDIR}/myvendor"
)
CMake complains with the error
CMake Error: File /home/user/myproject/build/output.rb.in does not exist.
CMake Error at CMakeLists.txt:35 (configure_file):
configure_file Problem configuring file
when running an out-of-tree build. Any ideas?
configure_file() is executed immediately at configuration step, while add_custom_command() add command to be executed(and dependency to be evaluated) at build step.
You may either replace add_custom_command with appropriate execute_process call, so your ruby script will be executed at configuration step, and its output file will be ready for configure_file.
Or you may replace configure_file with appropriate add_custom_command, so your file will be configured at build step, and will see dependencies. The problem here that you should explicitely pass CMake variables, used in "output.rb.in" file, to the configuration program, which can be, e.g.,
${CMAKE_COMMAND} [-D<var-definition>]+ -P <cmake-script-file-which-calls-configure_file>
In this particular case, it was sufficient to reorder to configuration operation, by performing configure_file() first, and pipe the output of this into the custom command.. I was merely thinking of the ordering all wrong.
I still do not have an answer for adding generated dependency to the input of configure_file()
Complete code
configure_file (
"${CMAKE_CURRENT_SOURCE_DIR}/input.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/output.rb.in"
)
# Custom command to build the output.rb
add_custom_command (
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/output.rb"
COMMAND ruby ${CMAKE_CURRENT_SOURCE_DIR}/build_ruby_output.rb
-i ${CMAKE_CURRENT_BINARY_DIR}/output.rb.in
-o ${CMAKE_CURRENT_BINARY_DIR}/output.rb
)
# Custom target is required to build it
add_custom_target (
dummy_target_xxx ALL DEPENDS
"${CMAKE_CURRENT_BINARY_DIR}/output.rb"
)
install (
FILES "${CMAKE_CURRENT_BINARY_DIR}/output.rb"
DESTINATION "${RUBY_VENDOR_LIBDIR}/myvendor"
)