Explorar el Código

cmake_host_system_information: Add MSYSTEM_PREFIX query

Add a query on Windows hosts for the installation prefix of a
MSYS or MinGW development environment.

Issue: #24216
Brad King hace 2 años
padre
commit
84a25fc263

+ 3 - 0
.gitlab/ci/configure_mingw_osdn_io_common.cmake

@@ -1,5 +1,8 @@
 set(CMake_TEST_Java OFF CACHE BOOL "")
 
+get_filename_component(mingw_dir "${CMAKE_CURRENT_LIST_DIR}/../mingw" ABSOLUTE)
+set(CMake_TEST_MSYSTEM_PREFIX "${mingw_dir}" CACHE STRING "")
+
 set(configure_no_sccache 1)
 
 include("${CMAKE_CURRENT_LIST_DIR}/configure_external_test.cmake")

+ 7 - 0
Help/command/cmake_host_system_information.rst

@@ -146,6 +146,13 @@ queried.  The list of queried values is stored in ``<variable>``.
 
   See :variable:`CMAKE_HOST_SYSTEM_PROCESSOR`
 
+``MSYSTEM_PREFIX``
+  .. versionadded:: 3.28
+
+  Available only on Windows hosts.  In a MSYS or MinGW development
+  environment that sets the ``MSYSTEM`` environment variable, this
+  is its installation prefix.  Otherwise, this is the empty string.
+
 ``DISTRIB_INFO``
   .. versionadded:: 3.22
 

+ 6 - 0
Help/release/dev/host-msystem-prefix.rst

@@ -0,0 +1,6 @@
+host-msystem-prefix
+-------------------
+
+* The :command:`cmake_host_system_information` command gained a
+  ``MSYSTEM_PREFIX`` query for the installation prefix of a MSYS
+  or MinGW development environment on Windows hosts.

+ 97 - 0
Source/cmCMakeHostSystemInformationCommand.cxx

@@ -414,6 +414,86 @@ cm::optional<std::string> GetDistribValue(cmExecutionStatus& status,
 }
 
 #ifdef _WIN32
+std::string FindMSYSTEM_PREFIX(std::vector<std::string> prefixes)
+{
+  for (std::string const& prefix : prefixes) {
+    std::string out;
+    std::string err;
+    int ret;
+    // In a modern MSYSTEM environment we expect cygpath to be in PATH.
+    std::vector<std::string> cygpath_cmd{ "cygpath", "-w", prefix };
+    if (cmSystemTools::RunSingleCommand(cygpath_cmd, &out, &err, &ret, nullptr,
+                                        cmSystemTools::OUTPUT_NONE)) {
+      if (ret == 0) {
+        out = cmTrimWhitespace(out);
+        cmSystemTools::ConvertToUnixSlashes(out);
+        if (cmSystemTools::FileIsDirectory(out)) {
+          return out;
+        }
+      }
+    } else {
+      // In a legacy MSYSTEM environment (MinGW/MSYS 1.0) there is no
+      // cygpath but we expect 'sh' to be in PATH.
+      std::vector<std::string> sh_cmd{
+        "sh", "-c", cmStrCat("cd \"", prefix, "\" && cmd //c cd")
+      };
+      if (cmSystemTools::RunSingleCommand(sh_cmd, &out, &err, &ret, nullptr,
+                                          cmSystemTools::OUTPUT_NONE)) {
+        if (ret == 0) {
+          out = cmTrimWhitespace(out);
+          cmSystemTools::ConvertToUnixSlashes(out);
+          if (cmSystemTools::FileIsDirectory(out)) {
+            return out;
+          }
+        }
+      }
+    }
+  }
+  return {};
+}
+
+std::string FallbackMSYSTEM_PREFIX(cm::string_view msystem)
+{
+  // These layouts are used by distributions such as
+  // * MSYS2: https://www.msys2.org/docs/environments/
+  // * MinGW/MSYS 1.0: http://mingw.osdn.io/
+  if (msystem == "MSYS"_s) {
+    static std::string const msystem_msys = FindMSYSTEM_PREFIX({ "/usr" });
+    return msystem_msys;
+  }
+  if (msystem == "MINGW32"_s) {
+    static std::string const msystem_mingw32 =
+      FindMSYSTEM_PREFIX({ "/mingw32", "/mingw" });
+    return msystem_mingw32;
+  }
+  if (msystem == "MINGW64"_s) {
+    static std::string const msystem_mingw64 =
+      FindMSYSTEM_PREFIX({ "/mingw64" });
+    return msystem_mingw64;
+  }
+  if (msystem == "UCRT64"_s) {
+    static std::string const msystem_ucrt64 =
+      FindMSYSTEM_PREFIX({ "/ucrt64" });
+    return msystem_ucrt64;
+  }
+  if (msystem == "CLANG32"_s) {
+    static std::string const msystem_clang32 =
+      FindMSYSTEM_PREFIX({ "/clang32" });
+    return msystem_clang32;
+  }
+  if (msystem == "CLANG64"_s) {
+    static std::string const msystem_clang64 =
+      FindMSYSTEM_PREFIX({ "/clang64" });
+    return msystem_clang64;
+  }
+  if (msystem == "CLANGARM64"_s) {
+    static std::string const msystem_clangarm64 =
+      FindMSYSTEM_PREFIX({ "/clangarm64" });
+    return msystem_clangarm64;
+  }
+  return {};
+}
+
 cm::optional<std::string> GetWindowsValue(cmExecutionStatus& status,
                                           std::string const& key)
 {
@@ -446,6 +526,23 @@ cm::optional<std::string> GetWindowsValue(cmExecutionStatus& status,
     return vs10gen->FindMSBuildCommandEarly(&status.GetMakefile());
   }
 
+  if (key == "MSYSTEM_PREFIX") {
+    // MSYSTEM_PREFIX is meaningful only under a MSYSTEM environment.
+    cm::optional<std::string> ms = cmSystemTools::GetEnvVar("MSYSTEM");
+    if (!ms || ms->empty()) {
+      return std::string();
+    }
+    // Prefer the MSYSTEM_PREFIX environment variable.
+    if (cm::optional<std::string> msp =
+          cmSystemTools::GetEnvVar("MSYSTEM_PREFIX")) {
+      cmSystemTools::ConvertToUnixSlashes(*msp);
+      if (cmSystemTools::FileIsDirectory(*msp)) {
+        return msp;
+      }
+    }
+    // Fall back to known distribution layouts.
+    return FallbackMSYSTEM_PREFIX(*ms);
+  }
   return {};
 }
 #endif

+ 3 - 0
Tests/RunCMake/CMakeLists.txt

@@ -474,6 +474,9 @@ if(NOT CMake_TEST_EXTERNAL_CMAKE)
 endif()
 add_RunCMake_test(execute_process)
 add_RunCMake_test(export)
+if(CMake_TEST_MSYSTEM_PREFIX)
+  list(APPEND cmake_host_system_information_ARGS -DCMake_TEST_MSYSTEM_PREFIX=${CMake_TEST_MSYSTEM_PREFIX})
+endif()
 add_RunCMake_test(cmake_host_system_information)
 add_RunCMake_test(cmake_language)
 add_RunCMake_test(cmake_minimum_required)

+ 1 - 0
Tests/RunCMake/cmake_host_system_information/MSYSTEM_PREFIX-Empty-stdout.txt

@@ -0,0 +1 @@
+MSYSTEM_PREFIX=''

+ 3 - 0
Tests/RunCMake/cmake_host_system_information/MSYSTEM_PREFIX-Empty.cmake

@@ -0,0 +1,3 @@
+unset(ENV{MSYSTEM})
+cmake_host_system_information(RESULT result QUERY MSYSTEM_PREFIX)
+message(STATUS "MSYSTEM_PREFIX='${result}'")

+ 1 - 0
Tests/RunCMake/cmake_host_system_information/MSYSTEM_PREFIX-Missing-result.txt

@@ -0,0 +1 @@
+1

+ 3 - 0
Tests/RunCMake/cmake_host_system_information/MSYSTEM_PREFIX-Missing-stderr.txt

@@ -0,0 +1,3 @@
+^CMake Error at [^
+]*/Tests/RunCMake/cmake_host_system_information/MSYSTEM_PREFIX-Missing.cmake:[0-9]+ \(cmake_host_system_information\):
+  cmake_host_system_information does not recognize <key> MSYSTEM_PREFIX$

+ 2 - 0
Tests/RunCMake/cmake_host_system_information/MSYSTEM_PREFIX-Missing.cmake

@@ -0,0 +1,2 @@
+unset(ENV{MSYSTEM})
+cmake_host_system_information(RESULT result QUERY MSYSTEM_PREFIX)

+ 2 - 0
Tests/RunCMake/cmake_host_system_information/MSYSTEM_PREFIX-stdout.txt

@@ -0,0 +1,2 @@
+-- MSYSTEM_PREFIX='[^
+]+'

+ 7 - 0
Tests/RunCMake/cmake_host_system_information/MSYSTEM_PREFIX.cmake

@@ -0,0 +1,7 @@
+cmake_host_system_information(RESULT result QUERY MSYSTEM_PREFIX)
+message(STATUS "MSYSTEM_PREFIX='${result}'")
+if(CMake_TEST_MSYSTEM_PREFIX)
+  if(NOT "${result}" STREQUAL "${CMake_TEST_MSYSTEM_PREFIX}")
+    message(FATAL_ERROR "Actual result:\n ${result}\nis not expected result:\n ${CMake_TEST_MSYSTEM_PREFIX}")
+  endif()
+endif()

+ 11 - 0
Tests/RunCMake/cmake_host_system_information/RunCMakeTest.cmake

@@ -22,6 +22,17 @@ else()
   run_cmake(VsMSBuildMissing)
 endif()
 
+if(CMAKE_HOST_WIN32)
+  run_cmake_script(MSYSTEM_PREFIX-Empty)
+  if("$ENV{MSYSTEM}" MATCHES "(MSYS|MINGW32|MINGW64|UCRT64)")
+    set(RunCMake_TEST_VARIANT_DESCRIPTION "-$ENV{MSYSTEM}")
+    run_cmake_script(MSYSTEM_PREFIX -DCMake_TEST_MSYSTEM_PREFIX=${CMake_TEST_MSYSTEM_PREFIX})
+    unset(RunCMake_TEST_VARIANT_DESCRIPTION)
+  endif()
+else()
+  run_cmake_script(MSYSTEM_PREFIX-Missing)
+endif()
+
 # WINDOWS_REGISTRY tests
 run_cmake(Registry_NoArgs)
 run_cmake(Registry_BadQuery1)