diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst index 8f28cf6042..821adc930f 100644 --- a/Help/manual/cmake-policies.7.rst +++ b/Help/manual/cmake-policies.7.rst @@ -98,6 +98,7 @@ Policies Introduced by CMake 4.1 .. toctree:: :maxdepth: 1 + CMP0193: GNUInstallDirs caches CMAKE_INSTALL_* with leading 'usr/' for install prefix '/'. CMP0192: GNUInstallDirs uses absolute SYSCONFDIR, LOCALSTATEDIR, and RUNSTATEDIR in special prefixes. CMP0191: The FindCABLE module is removed. CMP0190: FindPython enforce consistency in cross-compiling mode. diff --git a/Help/policy/CMP0193.rst b/Help/policy/CMP0193.rst new file mode 100644 index 0000000000..633291e41b --- /dev/null +++ b/Help/policy/CMP0193.rst @@ -0,0 +1,31 @@ +CMP0193 +------- + +.. versionadded:: 4.1 + +:module:`GNUInstallDirs` caches ``CMAKE_INSTALL_*`` with leading ``usr/`` for +install prefix ``/``. + +When :variable:`CMAKE_INSTALL_PREFIX` is ``/``, the ``CMAKE_INSTALL_`` +variables, for ```` equal to ``BINDIR``, ``SBINDIR``, ``LIBEXECDIR``, +``SHAREDSTATEDIR``, ``INCLUDEDIR``, ``OLDINCLUDEDIR``, ``DATAROOTDIR``, and +``LIBDIR``, are prepended with a leading ``usr/`` as documented among the +:ref:`special cases `. +In CMake 4.0 and below, these ``CMAKE_INSTALL_`` variables were cached +without their leading ``usr/``, and it was prepended in normal variables that +shadow their cache entries. +CMake 4.1 and above prefer to cache ``CMAKE_INSTALL_`` with their leading +``usr/``. Consequently, the :command:`GNUInstallDirs_get_absolute_install_dir` +command no longer alters the relative ``var`` input variable. This policy +provides compatibility for projects that have not been updated to expect +the new behavior. + +The ``OLD`` behavior for this policy is to cache ``CMAKE_INSTALL_`` +variables without the leading ``usr/``. The ``NEW`` behavior for this +policy is to cache ``CMAKE_INSTALL_`` variables with the leading ``usr/``. + +.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 4.1 +.. |WARNS_OR_DOES_NOT_WARN| replace:: does *not* warn +.. include:: include/STANDARD_ADVICE.rst + +.. include:: include/DEPRECATED.rst diff --git a/Help/release/dev/GNUInstallDirs-special-cases.rst b/Help/release/dev/GNUInstallDirs-special-cases.rst index 05c1a740ed..b21841038f 100644 --- a/Help/release/dev/GNUInstallDirs-special-cases.rst +++ b/Help/release/dev/GNUInstallDirs-special-cases.rst @@ -5,3 +5,7 @@ GNUInstallDirs-special-cases ``SYSCONFDIR``, ``LOCALSTATEDIR``, and ``RUNSTATEDIR`` to absolute paths when installing to special prefixes. See policy :policy:`CMP0192`. + +* The :module:`GNUInstallDirs` module now caches ``CMAKE_INSTALL_*`` + variables with their leading ``usr/`` for install prefix ``/``. + See policy :policy:`CMP0193`. diff --git a/Modules/GNUInstallDirs.cmake b/Modules/GNUInstallDirs.cmake index ef9b530cf4..a730764713 100644 --- a/Modules/GNUInstallDirs.cmake +++ b/Modules/GNUInstallDirs.cmake @@ -129,6 +129,10 @@ The following values of :variable:`CMAKE_INSTALL_PREFIX` are special: When building the complete GNU system, the prefix will be empty and ``/usr`` will be a symbolic link to ``/``. + .. versionchanged:: 4.1 + The ``CMAKE_INSTALL_`` variables are cached with the ``usr/`` prefix. + See policy :policy:`CMP0193`. + ``/usr`` For ```` equal to ``SYSCONFDIR``, ``LOCALSTATEDIR`` or @@ -186,6 +190,9 @@ Functions .. versionchanged:: 3.20 Added the ```` parameter. Previous versions of CMake passed this value through the variable ``${dir}``. + + .. versionchanged:: 4.1 + The ``var`` variable is no longer altered. See policy :policy:`CMP0193`. #]=======================================================================] cmake_policy(SET CMP0140 NEW) @@ -330,6 +337,20 @@ function(__GNUInstallDirs_default_in_root out_var original_path install_prefix) return(PROPAGATE ${out_var}) endfunction() +# Common handler for defaults that should be in usr/ +function(__GNUInstallDirs_default_in_usr out_var initial_value install_prefix) + set(${out_var} "${initial_value}") + if(install_prefix STREQUAL "/") + cmake_policy(GET CMP0193 cmp0193 + PARENT_SCOPE # undocumented, do not use outside of CMake + ) + if(cmp0193 STREQUAL "NEW") + set(${out_var} "usr/${${out_var}}") + endif() + endif() + return(PROPAGATE ${out_var}) +endfunction() + # Installation directories # @@ -388,6 +409,7 @@ function(_GNUInstallDirs_LIBDIR_get_default out_var install_prefix) endif() endif() endif() + __GNUInstallDirs_default_in_usr(${out_var} "${${out_var}}" "${install_prefix}") return(PROPAGATE ${out_var}) endfunction() @@ -423,6 +445,31 @@ function(_GNUInstallDirs_RUNSTATEDIR_get_default out_var install_prefix) return(PROPAGATE ${out_var}) endfunction() +# All of the other (primitive) dirs are typically in usr/. +# A special handling is needed for the `/` install_prefix +foreach(dir IN ITEMS + BINDIR + SBINDIR + LIBEXECDIR + SHAREDSTATEDIR + INCLUDEDIR + OLDINCLUDEDIR + DATAROOTDIR + # Except all the previous ones that had a special handling: + # LIBDIR, SYSCONFDIR, LOCALSTATEDIR, OLDINCLUDEDIR +) + # Cannot call function() directly because `dir` would not be accessible inside the function + # Using cmake_language(EVAL) to call a short wrapper function instead + cmake_language(EVAL CODE " + function(_GNUInstallDirs_${dir}_get_default out_var install_prefix) + set(\${out_var} \"\${_GNUInstallDirs_${dir}_DEFAULT}\") + __GNUInstallDirs_default_in_usr(\${out_var} \"\${\${out_var}}\" \"\${install_prefix}\") + return(PROPAGATE \${out_var}) + endfunction() + " + ) +endforeach() + _GNUInstallDirs_cache_path(BINDIR "User executables") _GNUInstallDirs_cache_path(SBINDIR @@ -571,7 +618,14 @@ function(GNUInstallDirs_get_absolute_install_dir absvar var) set(${absvar} "${${var}}") endif() - return(PROPAGATE ${var} ${absvar}) + set(return_vars ${absvar}) + cmake_policy(GET CMP0193 cmp0193 + PARENT_SCOPE # undocumented, do not use outside of CMake + ) + if(NOT cmp0193 STREQUAL "NEW") + list(APPEND return_vars ${var}) + endif() + return(PROPAGATE ${return_vars}) endfunction() # Result directories diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index c91fec6410..0d65c49f89 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -574,6 +574,10 @@ class cmMakefile; SELECT(POLICY, CMP0192, \ "GNUInstallDirs uses absolute SYSCONFDIR, LOCALSTATEDIR, and " \ "RUNSTATEDIR in special prefixes.", \ + 4, 1, 0, WARN) \ + SELECT(POLICY, CMP0193, \ + "GNUInstallDirs caches CMAKE_INSTALL_* with leading 'usr/' for " \ + "install prefix '/'.", \ 4, 1, 0, WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) diff --git a/Tests/RunCMake/GNUInstallDirs/CMakeLists.txt b/Tests/RunCMake/GNUInstallDirs/CMakeLists.txt index 0f0de84a83..38ff9b3fb3 100644 --- a/Tests/RunCMake/GNUInstallDirs/CMakeLists.txt +++ b/Tests/RunCMake/GNUInstallDirs/CMakeLists.txt @@ -1,4 +1,5 @@ cmake_minimum_required(VERSION 3.10) cmake_policy(SET CMP0192 NEW) +cmake_policy(SET CMP0193 NEW) project(${RunCMake_TEST} NONE) include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/GNUInstallDirs/GetAbs-stderr.txt b/Tests/RunCMake/GNUInstallDirs/GetAbs-stderr.txt index 1c2f0846eb..f0378c49f9 100644 --- a/Tests/RunCMake/GNUInstallDirs/GetAbs-stderr.txt +++ b/Tests/RunCMake/GNUInstallDirs/GetAbs-stderr.txt @@ -6,7 +6,7 @@ CMake Warning \(dev\) at [^ below. Call Stack \(most recent call first\): GetAbs.cmake:10 \(GNUInstallDirs_get_absolute_install_dir\) - CMakeLists.txt:4 \(include\) + CMakeLists.txt:5 \(include\) This warning is for project developers. Use -Wno-dev to suppress it. + PROJ2_FULL_BINDIR='/usr/bin'$