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.
Related
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'm having problems convincing cmake/cpack to generate a debian package that contains a single executable quine stored in a specific folder named /absolute/path.
According to https://cmake.org/cmake/help/v2.8.0/cmake.html#command:install I should be able to use an absolute path:
DESTINATION arguments specify the directory on disk to which a file
will be installed. If a full path (with a leading slash or drive
letter) is given it is used directly. If a relative path is given it
is interpreted relative to the value of CMAKE_INSTALL_PREFIX.
Here is my C file quine.c:
char*s="char*s=%c%s%c;main(){printf(s,34,s,34);}";main(){printf(s,34,s,34);}
and my CMakeLists.txt file:
cmake_minimum_required(VERSION 2.8)
project(quine)
file(GLOB SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.c)
add_executable(quine ${SOURCES})
set(CPACK_GENERATOR "DEB")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Nobody")
install(
TARGETS quine
RUNTIME DESTINATION /absolute/path
)
include(CPack)
In an empty subdirectory called build I invoke the following:
$ cmake ..
$ make package
and the resulting package is only 512 bytes in length, and a:
$ dpkg -c quine-0.1.1-Linux.deb
confirms that the package is empty.
What am I doing wrong?
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 ...).
Describe difference between these two command lines:
C:\xxxxx> cmake -help
Usage
$ cmake [options] <path-to-source>
$ cmake [options] <path-to-existing-build>
Specify a source directory to (re-)generate a build system for it in the
current working directory. Specify an existing build directory to
re-generate its build system.
The last description does not give me how to use the first, or the second.
Could you explain it to me?
When you use you do an in-tree build (cmake .), there is no difference.
When you do an out-of-tree build, there is a difference.
Suppose your project lives in ~/foo and your current directory is ~/foo/build
You have to run cmake .. for the first build. But for subsequent reconfigures, you can use cmake . because there is already a build there.
This command:
cmake [options] <path>
works as follows:
if <path> is not a valid (that is, already configured) CMake build directory, it is assumed to contain a CMakeList.txt. CMake will configure the current working directory as a build directory using <path>/CMakeLists.txt for source directory.
if <path> is a valid CMake build directory, the command reconfigures that directory using the source directory assigned when you first configured that build directory
So the common usage patterns are:
initial configuration:
mkdir my-build-dir
cd my-build-dir
cmake [options] my-source-dir
subsequent (re)configurations:
cmake [options] my-build-dir # current-work-dir is not important
alternative (initial) configuration using undocumented options:
cmake -Hmy-source-dir -Bmy-build-dir [options] # cwd is not important
I wrote a very simple HelloWorld.c program and ran Cmake. It created a cmake_install.cmake file in my build directory. Can somebody explain to me why CMake generated the file cmake_install.cmake? What is it's purpose and how can I use it?
CMakelists.txt :
cmake_minimum_required(VERSION 3.0)
PROJECT(FirstExample)
add_executable(prog first.c)
Thanks!
You generally don't use cmake_install.cmake directly. From the v3.12 page it states:
The install() command generates a file, cmake_install.cmake, inside
the build directory, which is used internally by the generated install
target and by CPack.
With your current CMakeLists.txt, the generated file doesn't do much. To create a useful install you would need to add more INSTALL commands to your CMakeLists.txt using the syntax below.
INSTALL(TARGETS targets... [EXPORT <export-name>]
[[ARCHIVE|LIBRARY|RUNTIME|FRAMEWORK|BUNDLE|
PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]
[DESTINATION <dir>]
[INCLUDES DESTINATION [<dir> ...]]
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[OPTIONAL] [NAMELINK_ONLY|NAMELINK_SKIP]
] [...])
For further reading on this command, check out the documentation site and wiki.
If it's desired to manually execute the script as stated by Nic30g the 3.12 page states that cmake -P accepts the following variables:
COMPONENT
Set this variable to install only a single CPack component as opposed to all of them. For example, if you only want to install the Development component, run
cmake -DCOMPONENT=Development -P cmake_install.cmake
BUILD_TYPE
Set this variable to change the build type if you are using a multi-config generator. For example, to install with the Debug configuration, run
cmake -DBUILD_TYPE=Debug -P cmake_install.cmake.
DESTDIR
This is an environment variable rather than a CMake variable. It allows you to change the installation prefix on UNIX systems. See DESTDIR for details.
As previous answer tells, the cmake_install.cmake contains the commands generated by install command from your CMakeLists.txt.
You can execute it by cmake -P cmake_install.cmake and it performs the installation of your project even on windows.
https://cmake.org/pipermail/cmake/2007-April/013657.html