[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