Inconsistencies with install() and relative path to GNUInstallDirs
CMake implementation of install() seems inconsistent with what the documentation recommends.
Current documentation
The documentation of install() specifies that:
DESTINATION <dir>
Specify the directory on disk to which a file will be installed. <dir> should be a relative path. An absolute path is allowed, but not recommended.
[…]
To make packages compliant with distribution filesystem layout policies, if projects must specify a DESTINATION, it is strongly recommended that they use a path that begins with the appropriate relative GNUInstallDirs variable.
and the documentation of GNUInstallDirs specifies that:
CMAKE_INSTALL_<dir>
Destination for files of a given type. This value may be passed to the DESTINATION options of install() commands for the corresponding file type. It should be a path relative to the installation prefix so that it can be converted to an absolute path in a relocatable way.
While absolute paths are allowed, they are not recommended as they do not work with the cmake --install command's --prefix option, or with the cpack installer generators. In particular, there is no need to make paths absolute by prepending CMAKE_INSTALL_PREFIX; this prefix is used by default if the DESTINATION is a relative path.
GNUInstallDirs with different CMAKE_INSTALL_PREFIX
Here is a table of the install directories computed by GNUInstallDirs depending on CMAKE_INSTALL_PREFIX on a Debian machine:
| Prefix/Dir | /usr | /usr/local | /home/foo |
|---|---|---|---|
| BINDIR | relative=bin, full=/usr/bin | relative=bin, full=/usr/local/bin | relative=bin, full=/home/foo/bin |
| SBINDIR | relative=sbin, full=/usr/sbin | relative=sbin, full=/usr/local/sbin | relative=sbin, full=/home/foo/sbin |
| LIBEXECDIR | relative=libexec, full=/usr/libexec | relative=libexec, full=/usr/local/libexec | relative=libexec, full=/home/foo/libexec |
| SYSCONFDIR | relative=etc, full=/etc | relative=etc, full=/usr/local/etc | relative=etc, full=/home/foo/etc |
| SHAREDSTATEDIR | relative=com, full=/usr/com | relative=com, full=/usr/local/com | relative=com, full=/home/foo/com |
| LOCALSTATEDIR | relative=var, full=/var | relative=var, full=/usr/local/var | relative=var, full=/home/foo/var |
| RUNSTATEDIR | relative=var/run, full=/var/run | relative=var/run, full=/usr/local/var/run | relative=var/run, full=/home/foo/var/run |
| LIBDIR | relative=lib/x86_64-linux-gnu, full=/usr/lib/x86_64-linux-gnu | relative=lib, full=/usr/local/lib | relative=lib, full=/home/foo/lib |
| INCLUDEDIR | relative=include, full=/usr/include | relative=include, full=/usr/local/include | relative=include, full=/home/foo/include |
| OLDINCLUDEDIR | relative=/usr/include, full=/usr/include | relative=/usr/include, full=/usr/include | relative=/usr/include, full=/usr/include |
| DATAROOTDIR | relative=share, full=/usr/share | relative=share, full=/usr/local/share | relative=share, full=/home/foo/share |
| DATADIR | relative=share, full=/usr/share | relative=share, full=/usr/local/share | relative=share, full=/home/foo/share |
| INFODIR | relative=share/info, full=/usr/share/info | relative=share/info, full=/usr/local/share/info | relative=share/info, full=/home/foo/share/info |
| LOCALEDIR | relative=share/locale, full=/usr/share/locale | relative=share/locale, full=/usr/local/share/locale | relative=share/locale, full=/home/foo/share/locale |
| MANDIR | relative=share/man, full=/usr/share/man | relative=share/man, full=/usr/local/share/man | relative=share/man, full=/home/foo/share/man |
| DOCDIR | relative=share/doc/test, full=/usr/share/doc/test | relative=share/doc/test, full=/usr/local/share/doc/test | relative=share/doc/test, full=/home/foo/share/doc/test |
Problem
The problem is that when the prefix is /usr, it is not possible to use a relative path to install in SYSCONFDIR.
install(
FILES foo.txt
TYPE SYSCONF # or DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}
)
It will install in /usr/etc instead of /etc. It means that we have to use CMAKE_INSTALL_FULL_<dir> for this case which:
- is contrary to the documentation
- prevents usage of the
--prefixoption