[cmake-developers] RFC: standard (and not so standard) install dirs
Alexander Neundorf
neundorf at kde.org
Tue Jan 10 16:16:00 EST 2012
Hi,
here comes a quite lengthy mail on issues I see in KDE but also in general
with install dirs and CMake.
in KDE we define a set of variables which hold the install destinations for
several different file types:
EXEC_INSTALL_PREFIX (${CMAKE_INSTALL_PREFIX})
SHARE_INSTALL_PREFIX (share)
BIN_INSTALL_DIR (${EXEC_INSTALL_PREFIX}/bin)
SBIN_INSTALL_DIR (${EXEC_INSTALL_PREFIX}/sbin)
LIB_INSTALL_DIR (${EXEC_INSTALL_PREFIX}/lib${LIB_SUFFIX})
LIBEXEC_INSTALL_DIR (${LIB_INSTALL_DIR}/kde4/libexec)
INCLUDE_INSTALL_DIR (include)
PLUGIN_INSTALL_DIR (${LIB_INSTALL_DIR}/kde4)
IMPORTS_INSTALL_DIR (${PLUGIN_INSTALL_DIR}/imports)
CONFIG_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/config)
DATA_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/apps)
HTML_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/doc/HTML)
ICON_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/icons)
KCFG_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/config.kcfg)
LOCALE_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/locale)
MIME_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/mimelnk)
SERVICES_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/kde4/services)
SERVICETYPES_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/kde4/servicetypes)
SOUND_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/sounds)
TEMPLATES_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/templates)
WALLPAPER_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/wallpapers)
DEMO_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/demos)
KCONF_UPDATE_INSTALL_DIR (${DATA_INSTALL_DIR}/kconf_update)
AUTOSTART_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/autostart)
XDG_APPS_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/applications/kde4)
XDG_DIRECTORY_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/desktop-directories)
XDG_MIME_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/mime/packages)
SYSCONF_INSTALL_DIR (${CMAKE_INSTALL_PREFIX}/etc)
MAN_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/man)
INFO_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/info)
DBUS_INTERFACES_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/dbus-1/interfaces)
DBUS_SERVICES_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/dbus-1/services)
DBUS_SYSTEM_SERVICES_INSTALL_DIR (${SHARE_INSTALL_PREFIX}/dbus-1/system-
services)
As you can see, some of them are very generic, and make sense for about any
package, like LIB_INSTALL_DIR and BIN_INSTALL_DIR, some are quite KDE-
specific, like SERVICETYPES_INSTALL_DIR and KCONF_UPDATE_INSTALL_DIR, some are
related to other packages, like e.g. XDG_DIRECTORY_INSTALL_DIR and
DBUS_SERVICES_INSTALL_DIR.
These variables are defined in FindKDE4Internal.cmake, so any package doing
find_package(KDE4)
can make use of these variables for installing its stuff.
Which features/advantages does this bring:
1) all these variables can be adjusted via the cache, so users/packagers can
tweak where stuff is installed to
2) the variables which can be tweaked have standard names, so it's the same
for all KDE4-packages
3) and a special extra feature: if a project which uses kdelibs is installed
to the same CMAKE_INSTALL_PREFIX as kdelibs, all these variables are
initialized to the values from kdelibs.
E.g. if kdelibs is installed in /opt/kde, and SYSCONF_INSTALL_DIR was set to
"/etc" for kdelibs, for any application which does find_package(KDE4) and
where CMAKE_INSTALL_PREFIX is also set to /opt/kde, SYSCONF_INSTALL_DIR will
be set to the value from kdelibs, i.e. "/etc".
So far, so good.
With the ongoing modularization of kdelibs we'd like to standardize this a bit
more and using a more generic, non KDE-specific solution.
Now since a few releases CMake has GNUInstallDirs.cmake.
This module serves a similar purpose. Unfortunately it introduced different
names for these variables, but ok.
It provides the following install destinations:
CMAKE_INSTALL_BINDIR (bin)
CMAKE_INSTALL_SBINDIR (sbin)
CMAKE_INSTALL_LIBEXECDIR (libexec)
CMAKE_INSTALL_SYSCONFDIR (etc)
CMAKE_INSTALL_SHAREDSTATEDIR (com)
CMAKE_INSTALL_LOCALSTATEDIR (var)
CMAKE_INSTALL_LIBDIR (lib or lib64)
CMAKE_INSTALL_INCLUDEDIR (include)
CMAKE_INSTALL_OLDINCLUDEDIR (/usr/include)
CMAKE_INSTALL_DATAROOTDIR (share)
CMAKE_INSTALL_DATADIR (DATAROOTDIR)
CMAKE_INSTALL_INFODIR (DATAROOTDIR/info)
CMAKE_INSTALL_LOCALEDIR (DATAROOTDIR/locale)
CMAKE_INSTALL_MANDIR (DATAROOTDIR/man)
CMAKE_INSTALL_DOCDIR (DATAROOTDIR/doc/PROJECT_NAME)
This is mostly a subset of the variables defined by KDE.
There are some additional variables (CMAKE_INSTALL_OLDINCLUDEDIR,
CMAKE_INSTALL_SHAREDSTATEDIR, CMAKE_INSTALL_LOCALSTATEDIR) which do not exist
in the KDE set of variables.
For simply using GNUInstallDirs.cmake for KDE instead of the KDE-defined
variables shown above, there are two issues:
* it does not provide all variables provided by KDE
* it does not provide feature 3), i.e. picking up the initial value of an
install variable from an already installed base package
This is where it's very unclear to me how to progress.
Where should the missing variables be added ?
Should they simply all be added to GNUInstallDirs.cmake ?
Does it make sense to gather all kinds of install dir variables in one place ?
This serves features 1) and 2), i.e. defines a standard set of user-modifiable
variables, but is bad wrt. locality.
One could argue that e.g. DBUS_SERVICES_INSTALL_DIR should be defined in
FindDBUS.cmake, since it is DBUS-related. OTOH, FindDBUS.cmake only provides
information about the DBUS which is installed on the system, and it is in
general completely up to the user where he wants to install this DBUS service
files. If he wants to install into his home dir, then those files shall go
there, no matter where DBUS is installed on the system. From that point of
view those install dir variables do not belong in a Find-module, but into the
using project (or at least in some central place to avoid copy'n paste, e.g.
in GNUINstallDirs.cmake/FindKDE4Internal.cmake).
So, any comments about this ?
And the second issue, initializing the install dirs variables.
With FindKDE4Internal.cmake, this is simply. For any KDE-application these
variables will be initialized from the kdelibs settings.
With a modularized kdelibs there is single one KDE library anymore which makes
a project a KDE project.
So "who" should install a file which serves as initialization file for later
projects ?
Example: let's say we (KDE) switch to using GNUInstallDirs.cmake, and every
KDE application should set CMAKE_INSTALL_LIBEXECDIR to
${LIB_INSTALL_DIR}/kde4/libexec/ instead of libexec/.
This would be necessary to make those projects work, so it would be very
desirable that some base package would install some file into some install
prefix which sets CMAKE_INSTALL_LIBEXECDIR accordingly, and so the using
project would get its install dir variable initialized correctly
automatically.
I have actually no idea how to do this.
Is there a way to add this as a generic feature to GNUInstallDirs.cmake ? But
then GNUInstallDirs.cmake would also have to define those more specialized
variables, like the DBUS ones mentioned above.
Maybe GNUInstallDirs.cmake could take an argument, or use some variable like
set(GNU_INSTALL_DIRS_INITIALIZE_FROM KDE4),
and if set, it could look e.g. in ${CMAKE_INSTALL_PREFIX}/lib/cmake/ for a
file like KDE4InstallDirs.cmake, which would be included in order to
initialize the install dir variables ?
This way a distro could e.g. install a BaseInstallDirs.cmake into
/usr/lib/cmake/, and all using project would pick up the install dirs defined
there.
Does that sound sensible ? It's just a rough idea, not sure whether it makes
sense or is just confusing...
And there is one additional question I have:
Is it actually necessary to make all those install dir variable editable for
the user ?
It comes with a cost, especially when we want people to start installing
FooConfig.cmake files.
If I know in a project, that the libraries go into CMAKE_INSTALL_PREFIX/lib/,
the headers into CMAKE_INSTALL_PREFIX/include/ and the Config.cmake file will
be in CMAKE_INSTALL_PREFIX/lib/cmake/foo/, then I can simply put into the
FooConfig.cmake file something like:
set(FOO_INCLUDE_DIR ${CMAKE_CURRENT_LISTFILE_DIR}/../../../include )
and it will be correct, no matter how CMAKE_INSTALL_PREFIX is set (i.e. it
will also work under Windows).
The other solution is to configure the full absolute INCLUDE_INSTALL_DIR into
the Config.cmake file. This works fine, but only as long as the library is
also installed to the location for which it has been compiled.
This is usually the case under Linux/UNIX, but in general not the case under
Windows, where the user (not a compiling user) decided at install time instead
of cmake time where he'll install the library. In that case full absolute
configured paths break the Config.cmake file.
To support the fully flexible version, the developer must calculate the
relative path from the configured CONFIG_INSTALL_DIR (where the Config.cmake
file goes) to the configured INCLUDE_INSTALL_DIR.
The easiest way I could come up with to do this is the following:
set(INCLUDE_INSTALL_DIR include)
set(LIB_INSTALL_DIR lib)
set(CMAKECONFIG_INSTALL_DIR ${LIB_INSTALL_DIR}/cmake/foo )
file(RELATIVE_PATH relInstallDir
${CMAKE_INSTALL_PREFIX}/${CMAKECONFIG_INSTALL_DIR}
${CMAKE_INSTALL_PREFIX} )
and then in the Config.cmake file:
get_filename_component(myDir ${CMAKE_CURRENT_LIST_FILE} PATH)
get_filename_component(rootDir ${myDir}/@relInstallDir@ ABSOLUTE)
set(FOO_INCLUDES "${rootDir}/@INCLUDE_INSTALL_DIR@")
This does not even yet support modifiable LIB_ or INCLUDE_INSTALL_DIRS, and is
already quite complicated.
If LIB_INSTALL_DIR and INCLUDE_INSTALL_DIR can be user-modifiable, I have to
add code to check for handling whether they are relative or absolute paths,
and I'm actually not sure what happens if under Windows LIB_INSTALL_DIR and
INCLUDE_INSTALL_DIR would be set to be on different drives.
And all that for making it possible for the user to change INCLUDE_INSTALL_DIR
from include/ to something else.
Is that worth it ?
The same for the library install dir. GNUInstallDirs.cmake should be quite
good now at determining the desired directory. It would be already better if I
could rely on that CMAKE_INSTALL_INCLUDEDIR is always only a relative path.
So, do you think it is actually a good thing to make *all* those install
locations user-modifiable ?
And if so, do you have suggestions how to make the code needed in the
Config.cmake files easier ?
Thanks for reading
Alex
More information about the cmake-developers
mailing list