Browse Source

Merge topic 'fat-ios'

a9b41195d2 Handle multi-arch sysroots on Apple platforms
372c89ea38 Refactor -arch and -isysroot code usage
7a44e16d7f Refactor SDK name to path into a function
777d364913 Use xcrun instead of xcodebuild for resolving SDK path

Acked-by: Kitware Robot <[email protected]>
Merge-request: !4125
Brad King 5 years ago
parent
commit
671ed5b123
3 changed files with 131 additions and 27 deletions
  1. 94 11
      Modules/Platform/Darwin-Initialize.cmake
  2. 3 0
      Source/cmCoreTryCompile.cxx
  3. 34 16
      Source/cmLocalGenerator.cxx

+ 94 - 11
Modules/Platform/Darwin-Initialize.cmake

@@ -122,7 +122,97 @@ endforeach()
 set(CMAKE_OSX_SYSROOT "${_CMAKE_OSX_SYSROOT_DEFAULT}" CACHE ${_CMAKE_OSX_SYSROOT_TYPE}
   "The product will be built against the headers and libraries located inside the indicated SDK.")
 
-# Transform the cached value to something we can use.
+# Resolves the SDK name into a path
+function(_apple_resolve_sdk_path sdk_name ret)
+  execute_process(
+    COMMAND xcrun -sdk ${sdk_name} --show-sdk-path
+    OUTPUT_VARIABLE _stdout
+    OUTPUT_STRIP_TRAILING_WHITESPACE
+    ERROR_VARIABLE _stderr
+    RESULT_VARIABLE _failed
+  )
+  set(${ret} "${_stdout}" PARENT_SCOPE)
+endfunction()
+# Handle multi-arch sysroots. Do this before CMAKE_OSX_SYSROOT is
+# transformed into a path, so that we know the sysroot name.
+function(_apple_resolve_multi_arch_sysroots)
+  if(CMAKE_APPLE_ARCH_SYSROOTS)
+    return() # Already cached
+  endif()
+
+  list(LENGTH CMAKE_OSX_ARCHITECTURES _num_archs)
+  if(NOT (_num_archs GREATER 1))
+    return() # Only apply to multi-arch
+  endif()
+
+  if(CMAKE_OSX_SYSROOT STREQUAL "macosx")
+    # macOS doesn't have a simulator sdk / sysroot, so there is no need to handle per-sdk arches.
+    return()
+  endif()
+
+  if(IS_DIRECTORY "${CMAKE_OSX_SYSROOT}")
+    if(NOT CMAKE_OSX_SYSROOT STREQUAL _CMAKE_OSX_SYSROOT_DEFAULT)
+      message(WARNING "Can not resolve multi-arch sysroots with CMAKE_OSX_SYSROOT set to path (${CMAKE_OSX_SYSROOT})")
+    endif()
+    return()
+  endif()
+
+  string(REPLACE "os" "simulator" _simulator_sdk ${CMAKE_OSX_SYSROOT})
+  set(_sdks "${CMAKE_OSX_SYSROOT};${_simulator_sdk}")
+  foreach(sdk ${_sdks})
+    _apple_resolve_sdk_path(${sdk} _sdk_path)
+    if(NOT IS_DIRECTORY "${_sdk_path}")
+      message(WARNING "Failed to resolve SDK path for '${sdk}'")
+      continue()
+    endif()
+
+    execute_process(
+      COMMAND plutil -extract SupportedTargets.${sdk}.Archs json ${_sdk_path}/SDKSettings.plist -o -
+      OUTPUT_VARIABLE _sdk_archs_json
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      ERROR_VARIABLE _stderr
+      RESULT_VARIABLE _failed
+      )
+    if(_failed)
+      # Failure to extract supported architectures for an SDK means that the installed SDK is old
+      # and does not provide such information (SDKs that come with Xcode >= 10.x started providing
+      # the information). In such a case, return early, and handle multi-arch builds the old way
+      # (no per-sdk arches).
+      return()
+    endif()
+
+    # Poor man's JSON decoding
+    string(REGEX REPLACE "[]\\[\"]" "" _sdk_archs ${_sdk_archs_json})
+    string(REPLACE "," ";" _sdk_archs ${_sdk_archs})
+
+    set(_sdk_archs_${sdk} ${_sdk_archs})
+    set(_sdk_path_${sdk} ${_sdk_path})
+  endforeach()
+
+  foreach(arch ${CMAKE_OSX_ARCHITECTURES})
+    set(_arch_sysroot "")
+    foreach(sdk ${_sdks})
+      list(FIND _sdk_archs_${sdk} ${arch} arch_index)
+      if(NOT arch_index EQUAL -1)
+        set(_arch_sysroot ${_sdk_path_${sdk}})
+        break()
+      endif()
+    endforeach()
+    if(_arch_sysroot)
+      list(APPEND _arch_sysroots ${_arch_sysroot})
+    else()
+      message(WARNING "No SDK found for architecture '${arch}'")
+      list(APPEND _arch_sysroots "") # Placeholder
+    endif()
+  endforeach()
+
+  set(CMAKE_APPLE_ARCH_SYSROOTS "${_arch_sysroots}" CACHE INTERNAL
+    "Architecture dependent sysroots, one per CMAKE_OSX_ARCHITECTURES")
+endfunction()
+
+_apple_resolve_multi_arch_sysroots()
+
+# Transform CMAKE_OSX_SYSROOT to absolute path
 set(_CMAKE_OSX_SYSROOT_PATH "")
 if(CMAKE_OSX_SYSROOT)
   if("x${CMAKE_OSX_SYSROOT}" MATCHES "/")
@@ -134,16 +224,9 @@ if(CMAKE_OSX_SYSROOT)
     endif()
     set(_CMAKE_OSX_SYSROOT_PATH "${CMAKE_OSX_SYSROOT}")
   else()
-    # Transform the sdk name into a path.
-    execute_process(
-      COMMAND xcodebuild -sdk ${CMAKE_OSX_SYSROOT} -version Path
-      OUTPUT_VARIABLE _stdout
-      OUTPUT_STRIP_TRAILING_WHITESPACE
-      ERROR_VARIABLE _stderr
-      RESULT_VARIABLE _failed
-      )
-    if(NOT _failed AND IS_DIRECTORY "${_stdout}")
-      set(_CMAKE_OSX_SYSROOT_PATH "${_stdout}")
+    _apple_resolve_sdk_path(${CMAKE_OSX_SYSROOT} _sdk_path)
+    if(IS_DIRECTORY "${_sdk_path}")
+      set(_CMAKE_OSX_SYSROOT_PATH "${_sdk_path}")
       # For non-Xcode generators use the path.
       if(NOT "${CMAKE_GENERATOR}" MATCHES "Xcode")
         set(CMAKE_OSX_SYSROOT "${_CMAKE_OSX_SYSROOT_PATH}")

+ 3 - 0
Source/cmCoreTryCompile.cxx

@@ -51,6 +51,8 @@ static std::string const kCMAKE_OSX_ARCHITECTURES = "CMAKE_OSX_ARCHITECTURES";
 static std::string const kCMAKE_OSX_DEPLOYMENT_TARGET =
   "CMAKE_OSX_DEPLOYMENT_TARGET";
 static std::string const kCMAKE_OSX_SYSROOT = "CMAKE_OSX_SYSROOT";
+static std::string const kCMAKE_APPLE_ARCH_SYSROOTS =
+  "CMAKE_APPLE_ARCH_SYSROOTS";
 static std::string const kCMAKE_POSITION_INDEPENDENT_CODE =
   "CMAKE_POSITION_INDEPENDENT_CODE";
 static std::string const kCMAKE_SYSROOT = "CMAKE_SYSROOT";
@@ -723,6 +725,7 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv,
       vars.insert(kCMAKE_OSX_ARCHITECTURES);
       vars.insert(kCMAKE_OSX_DEPLOYMENT_TARGET);
       vars.insert(kCMAKE_OSX_SYSROOT);
+      vars.insert(kCMAKE_APPLE_ARCH_SYSROOTS);
       vars.insert(kCMAKE_POSITION_INDEPENDENT_CODE);
       vars.insert(kCMAKE_SYSROOT);
       vars.insert(kCMAKE_SYSROOT_COMPILE);

+ 34 - 16
Source/cmLocalGenerator.cxx

@@ -1777,10 +1777,18 @@ void cmLocalGenerator::AddArchitectureFlags(std::string& flags,
                                             const std::string& lang,
                                             const std::string& config)
 {
-  // Only add macOS specific flags on Darwin platforms (macOS and iOS):
+  // Only add Apple specific flags on Apple platforms
   if (this->Makefile->IsOn("APPLE") && this->EmitUniversalBinaryFlags) {
     std::vector<std::string> archs;
     target->GetAppleArchs(config, archs);
+    if (!archs.empty() && !lang.empty() &&
+        (lang[0] == 'C' || lang[0] == 'F' || lang[0] == 'O')) {
+      for (std::string const& arch : archs) {
+        flags += " -arch ";
+        flags += arch;
+      }
+    }
+
     const char* sysroot = this->Makefile->GetDefinition("CMAKE_OSX_SYSROOT");
     if (sysroot && sysroot[0] == '/' && !sysroot[1]) {
       sysroot = nullptr;
@@ -1788,27 +1796,37 @@ void cmLocalGenerator::AddArchitectureFlags(std::string& flags,
     std::string sysrootFlagVar =
       std::string("CMAKE_") + lang + "_SYSROOT_FLAG";
     const char* sysrootFlag = this->Makefile->GetDefinition(sysrootFlagVar);
+    if (sysrootFlag && *sysrootFlag) {
+      std::vector<std::string> arch_sysroots;
+      if (const char* arch_sysroots_str =
+            this->Makefile->GetDefinition("CMAKE_APPLE_ARCH_SYSROOTS")) {
+        cmExpandList(std::string(arch_sysroots_str), arch_sysroots, true);
+      }
+      if (!arch_sysroots.empty()) {
+        assert(arch_sysroots.size() == archs.size());
+        for (size_t i = 0; i < archs.size(); ++i) {
+          if (arch_sysroots[i].empty()) {
+            continue;
+          }
+          flags += " -Xarch_" + archs[i] + " ";
+          // Combine sysroot flag and path to work with -Xarch
+          std::string arch_sysroot = sysrootFlag + arch_sysroots[i];
+          flags += this->ConvertToOutputFormat(arch_sysroot, SHELL);
+        }
+      } else if (sysroot && *sysroot) {
+        flags += " ";
+        flags += sysrootFlag;
+        flags += " ";
+        flags += this->ConvertToOutputFormat(sysroot, SHELL);
+      }
+    }
+
     const char* deploymentTarget =
       this->Makefile->GetDefinition("CMAKE_OSX_DEPLOYMENT_TARGET");
     std::string deploymentTargetFlagVar =
       std::string("CMAKE_") + lang + "_OSX_DEPLOYMENT_TARGET_FLAG";
     const char* deploymentTargetFlag =
       this->Makefile->GetDefinition(deploymentTargetFlagVar);
-    if (!archs.empty() && !lang.empty() &&
-        (lang[0] == 'C' || lang[0] == 'F' || lang[0] == 'O')) {
-      for (std::string const& arch : archs) {
-        flags += " -arch ";
-        flags += arch;
-      }
-    }
-
-    if (sysrootFlag && *sysrootFlag && sysroot && *sysroot) {
-      flags += " ";
-      flags += sysrootFlag;
-      flags += " ";
-      flags += this->ConvertToOutputFormat(sysroot, SHELL);
-    }
-
     if (deploymentTargetFlag && *deploymentTargetFlag && deploymentTarget &&
         *deploymentTarget) {
       flags += " ";