The module documentation mentions some special cases, where, for example, when the install prefix is /usr, the CMAKE_INSTALL_FULL_SYSCONFDIR becomes /etc instead of the /usr/etc, and similar.
However, the CMake’s install() command doesn’t adjust the destination according to these special cases.
Is this considered a CMake bug, or is this something that projects should adapt by themselves, or is this something that the installation phase should adapt via the CMAKE_INSTALL_* variables by themselves?
I did. Exactly these special cases aren’t taken into consideration when using the install() command and the installation prefix is set at the install phase (cmake --install ... --prefix /usr). In this case the libraries will be installed to “lib” instead of “lib/x86_64-linux-gnu”. If the install prefix is set at the configuration phase (-DCMAKE_INSTALL_PREFIX=/usr) then they are installed to “lib/x86_64-linux-gnu”, which makes the entire special cases inconsistent in CMake.
For what it’s worth, the CMAKE_INSTALL_LIBDIR is relative path (not related here to the CMAKE_INSTALL_FULL_LIBDIR) and it gets changed based on the install prefix. But only if the install prefix is set during the configuration phase. It is not changed if the install prefix is set at the install phase. Meaning, I don’t use these CMAKE_INSTALL_FULL_* variables either. But I do get different but inconsistent CMAKE_INSTALL_* relative path variables.
bash-5.2$ cmake --preset default --fresh
Preset CMake variables:
BUILD_SHARED_LIBS="NO"
CMAKE_BUILD_TYPE="Release"
CMAKE_CXX_STANDARD="20"
CMAKE_DEBUG_POSTFIX="D"
CMAKE_INSTALL_PREFIX="/usr"
CMAKE_PREFIX_PATH:STRING="/Users/clausklein/Workspace/cpp/ModernCmakeStarter/stagedir"
Preset environment variables:
CPM_USE_LOCAL_PACKAGES="YES"
-- The CXX compiler identification is AppleClang 16.0.0.16000026
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found Git: /usr/local/bin/git (found version "2.46.2")
-- CPM: Adding package project_options@0.30.0 (v0.30.0 at /Users/clausklein/.cache/CPM/project_options/2de06ed3a4c11a5a7ebda8b90d2dd05882bbb095)
-- CPM: Adding package PackageProject.cmake@1.10.0 (v1.10.0 at /Users/clausklein/.cache/CPM/packageproject.cmake/41b1a5028ad2c8d2c6bb64eb6beff8b090d304e5)
-- CPM: Using local package fmt@10.0.0
-- Developer mode is OFF. For developement, use `-DENABLE_DEVELOPER_MODE:BOOL=ON`. Building the project for the end-user...
-- The default CMAKE_C_STANDARD used by external targets and tools is not set yet. Using the latest supported C standard that is 90
-- /usr/local/bin/ccache found and enabled
-- Configuring done (0.5s)
-- Generating done (0.0s)
-- Build files have been written to: /Users/clausklein/Workspace/cpp/ModernCmakeStarter/build/user
bash-5.2$ DESTDIR=/tmp/test cmake --install build/user
-- Install configuration: "Release"
-- Up-to-date: /tmp/test/usr/etc/test.cfg
-- Up-to-date: /tmp/test/usr/include/greeter
-- Up-to-date: /tmp/test/usr/include/greeter/greeter
-- Up-to-date: /tmp/test/usr/include/greeter/greeter/version.h
-- Installing: /tmp/test/usr/lib/greeter/libgreeter.a
-- Installing: /tmp/test/usr/lib/cmake/greeter/greeterTargets.cmake
-- Installing: /tmp/test/usr/lib/cmake/greeter/greeterTargets-release.cmake
-- Up-to-date: /tmp/test/usr/lib/cmake/greeter/greeterConfigVersion.cmake
-- Up-to-date: /tmp/test/usr/lib/cmake/greeter/greeterConfig.cmake
-- Up-to-date: /tmp/test/usr/include/greeter
-- Up-to-date: /tmp/test/usr/include/greeter/greeter
-- Up-to-date: /tmp/test/usr/include/greeter/greeter/greeter.h
bash-5.2$ sudo cmake --install build/user
Password:
-- Install configuration: "Release"
CMake Error at build/user/cmake_install.cmake:41 (file):
file cannot create directory: /usr/etc. Maybe need administrative
privileges.
bash-5.2$
# CMakeLists.txt
cmake_minimum_required(VERSION 3.25 FATAL_ERROR)
project(TestingInstallation LANGUAGES C)
include(GNUInstallDirs)
add_library(testinginstallation SHARED lib.c)
include(GNUInstallDirs)
install(
TARGETS testinginstallation
)
/* lib.c */
int foo(void) { return 0; }
Then here the first installation sets the installation prefix to /usr in the configuration step, which sets the CMAKE_INSTALL_LIBDIR to lib/x86_64-linux-gnu on Debian-based machines (Ubuntu included):
Same issue happens with all these mentioned special cases in the GNUInstallDirs module.
I think I’ll start resolving this for now by creating a custom install module that overrides the CMake’s install commands that I use and have all the CMAKE_INSTALL_* variables available in their adjusted form in the install() scripts. Another option would be to not use the --prefix option in the cmake --install phase and warn about this in the documentation. But I would probably miss something then here for the CPack etc.
It would be kind of good for CMake to address these issues in the CMake code directly instead of users needing to do this kind of adjustments or that the packager needs to set all the CMAKE_INSTALL_* variables when packaging the software.
Because this is too difficult to get right and it makes the installation phase too cumbersome to use for the projects.