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
--prefix
option