Browse Source

macOS: Restore support for LLVM/Clang without explicit CMAKE_OSX_SYSROOT

In commit 7b19531291 (macOS: Do not pass any SDK/-isysroot to compilers
by default, 2024-11-06, v4.0.0-rc1~511^2) we broke support for using
upstream LLVM/Clang to build for macOS because the compiler has no
default sysroot.  Handle empty `CMAKE_OSX_SYSROOT` with LLVM/Clang by
falling back to the macOS SDK reported by `xcrun --show-sdk-path` .

Fixes: #26863
Brad King 8 months ago
parent
commit
bf1bb62e74

+ 27 - 11
Help/release/4.0.rst

@@ -229,17 +229,24 @@ Other Changes
   behavior can override user-specified compiler paths.  Therefore, this
   behavior has been reverted.
 
-* Builds targeting macOS no longer choose any SDK or pass an ``-isysroot``
-  flag to the compiler by default.  Instead, compilers are expected to
-  choose a default macOS SDK on their own.  In order to use a compiler that
-  does not do this, users must now specify :variable:`CMAKE_OSX_SYSROOT`
-  when configuring their build, e.g., ``-DCMAKE_OSX_SYSROOT=macosx``.
-
-  Note that Xcode's compilers, when not invoked with ``-isysroot``, search
-  for headers in ``/usr/local/include`` before system SDK paths, matching the
-  convention on many platforms.  Users on macOS-x86_64 hosts with Homebrew
-  installed in ``/usr/local`` should pass ``-DCMAKE_OSX_SYSROOT=macosx``,
-  or ``export SDKROOT=macosx``, when not building with Homebrew tools.
+* In builds targeting macOS, :variable:`CMAKE_OSX_SYSROOT` now defaults to
+  empty, deferring to the compiler's default macOS SDK selection.  In order
+  to pass an explicit macOS SDK via the compiler's ``-isysroot`` flag, users
+  may configure their build tree with ``-DCMAKE_OSX_SYSROOT=macosx``, or
+  ``export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)"`` in their
+  environment.
+
+  Notes:
+
+  * macOS compilers in ``/usr/bin``, when not invoked with ``-isysroot``,
+    search for headers in ``/usr/local/include`` before system SDK paths,
+    matching the convention on many platforms.  Users on macOS-x86_64 hosts
+    with Homebrew installed in ``/usr/local`` should pass an explicit SDK,
+    as described above, when not building with Homebrew tools.
+
+  * Some Clang compilers have no default macOS SDK selection.  For these,
+    if :variable:`CMAKE_OSX_SYSROOT` is empty, CMake will automatically pass
+    ``-isysroot`` with the macOS SDK printed by ``xcrun --show-sdk-path``.
 
 * On Windows, file paths named in project code, e.g., in ``CMakeLists.txt``,
   are no longer automatically converted to their on-disk upper/lower case.
@@ -273,3 +280,12 @@ Changes made since CMake 4.0.0 include the following.
 * This version made no changes to documented features or interfaces.
   Some implementation updates were made to support ecosystem changes
   and/or fix regressions.
+
+.. 4.0.2 (unreleased)
+
+  * When building for macOS with a Clang that has no default macOS SDK,
+    if :variable:`CMAKE_OSX_SYSROOT` is empty, CMake now automatically passes
+    ``-isysroot`` with the macOS SDK printed by ``xcrun --show-sdk-path``.
+    This restores support for using LLVM/Clang on macOS without manually
+    setting ``CMAKE_OSX_SYSROOT``, which was broken by CMake 4.0.0's
+    removal of a default value.

+ 16 - 11
Help/variable/CMAKE_OSX_SYSROOT.rst

@@ -2,25 +2,30 @@ CMAKE_OSX_SYSROOT
 -----------------
 
 Specify the location or name of the macOS platform SDK to be used.
-CMake uses this value to compute the value of the ``-isysroot`` flag
-or equivalent and to help the ``find_*`` commands locate files in
-the SDK.
 
 If not set explicitly, the value is initialized by the ``SDKROOT``
 environment variable, if set.  Otherwise, the value defaults to empty,
-so no explicit ``-isysroot`` flag is passed, and the compiler's default
-sysroot is used.
+and the compiler is expected to choose a default macOS SDK on its own.
 
 .. versionchanged:: 4.0
   The default is now empty.  Previously a default was computed based on
   the :variable:`CMAKE_OSX_DEPLOYMENT_TARGET` or the host platform.
 
-.. note::
+In order to pass an explicit macOS SDK via the compiler's ``-isysroot`` flag,
+users may configure their build tree with ``-DCMAKE_OSX_SYSROOT=macosx``,
+or ``export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)"`` in their
+environment.
 
-  Xcode's compilers, when not invoked with ``-isysroot``, search for
-  headers in ``/usr/local/include`` before system SDK paths, matching the
-  convention on many platforms.  Users on macOS-x86_64 hosts with Homebrew
-  installed in ``/usr/local`` should pass ``-DCMAKE_OSX_SYSROOT=macosx``,
-  or ``export SDKROOT=macosx``, when not building with Homebrew tools.
+Notes:
+
+* macOS compilers in ``/usr/bin``, when not invoked with ``-isysroot``,
+  search for headers in ``/usr/local/include`` before system SDK paths,
+  matching the convention on many platforms.  Users on macOS-x86_64 hosts
+  with Homebrew installed in ``/usr/local`` should pass an explicit SDK,
+  as described above, when not building with Homebrew tools.
+
+* Some Clang compilers have no default macOS SDK selection.  For these,
+  if :variable:`CMAKE_OSX_SYSROOT` is empty, CMake will automatically pass
+  ``-isysroot`` with the macOS SDK printed by ``xcrun --show-sdk-path``.
 
 .. include:: CMAKE_OSX_VARIABLE.txt

+ 1 - 0
Modules/CMakeCCompiler.cmake.in

@@ -17,6 +17,7 @@ set(CMAKE_C23_COMPILE_FEATURES "@CMAKE_C23_COMPILE_FEATURES@")
 set(CMAKE_C_PLATFORM_ID "@CMAKE_C_PLATFORM_ID@")
 set(CMAKE_C_SIMULATE_ID "@CMAKE_C_SIMULATE_ID@")
 set(CMAKE_C_COMPILER_FRONTEND_VARIANT "@CMAKE_C_COMPILER_FRONTEND_VARIANT@")
+set(CMAKE_C_COMPILER_APPLE_SYSROOT "@CMAKE_C_COMPILER_APPLE_SYSROOT@")
 set(CMAKE_C_SIMULATE_VERSION "@CMAKE_C_SIMULATE_VERSION@")
 @_SET_CMAKE_C_COMPILER_ARCHITECTURE_ID@
 @_SET_CMAKE_C_COMPILER_SYSROOT@

+ 1 - 0
Modules/CMakeCXXCompiler.cmake.in

@@ -19,6 +19,7 @@ set(CMAKE_CXX26_COMPILE_FEATURES "@CMAKE_CXX26_COMPILE_FEATURES@")
 set(CMAKE_CXX_PLATFORM_ID "@CMAKE_CXX_PLATFORM_ID@")
 set(CMAKE_CXX_SIMULATE_ID "@CMAKE_CXX_SIMULATE_ID@")
 set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "@CMAKE_CXX_COMPILER_FRONTEND_VARIANT@")
+set(CMAKE_CXX_COMPILER_APPLE_SYSROOT "@CMAKE_CXX_COMPILER_APPLE_SYSROOT@")
 set(CMAKE_CXX_SIMULATE_VERSION "@CMAKE_CXX_SIMULATE_VERSION@")
 @_SET_CMAKE_CXX_COMPILER_ARCHITECTURE_ID@
 @_SET_CMAKE_CXX_COMPILER_SYSROOT@

+ 41 - 0
Modules/CMakeDetermineCompilerId.cmake

@@ -256,6 +256,46 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
     set(CMAKE_${lang}_CL_SHOWINCLUDES_PREFIX "")
   endif()
 
+  if(CMAKE_EFFECTIVE_SYSTEM_NAME STREQUAL "Apple" AND CMAKE_${lang}_COMPILER_ID MATCHES "Clang$")
+    cmake_path(GET src EXTENSION LAST_ONLY ext)
+    set(apple_sdk_dir "${CMAKE_${lang}_COMPILER_ID_DIR}")
+    set(apple_sdk_src "apple-sdk${ext}")
+    file(WRITE "${apple_sdk_dir}/${apple_sdk_src}" "#include <AvailabilityMacros.h>\n")
+    set(apple_sdk_cmd
+      "${CMAKE_${lang}_COMPILER}"
+        ${CMAKE_${lang}_COMPILER_ID_ARG1}
+        ${CMAKE_${lang}_COMPILER_ID_FLAGS_LIST}
+        -E ${apple_sdk_src}
+    )
+    execute_process(
+      COMMAND ${apple_sdk_cmd}
+      WORKING_DIRECTORY ${apple_sdk_dir}
+      OUTPUT_VARIABLE apple_sdk_out
+      ERROR_VARIABLE apple_sdk_out
+      RESULT_VARIABLE apple_sdk_res
+    )
+    string(JOIN "\" \"" apple_sdk_cmd ${apple_sdk_cmd})
+    if(apple_sdk_res EQUAL 0 AND apple_sdk_out MATCHES [["([^"]*)/usr/include/AvailabilityMacros\.h"]])
+      if(CMAKE_MATCH_1)
+        set(CMAKE_${lang}_COMPILER_APPLE_SYSROOT "${CMAKE_MATCH_1}")
+      else()
+        set(CMAKE_${lang}_COMPILER_APPLE_SYSROOT "/")
+      endif()
+      set(apple_sdk_msg "Found apple sysroot: ${CMAKE_${lang}_COMPILER_APPLE_SYSROOT}")
+    else()
+      set(CMAKE_${lang}_COMPILER_APPLE_SYSROOT "")
+      set(apple_sdk_msg "No apple sysroot found.")
+    endif()
+    string(REPLACE "\n" "\n  " apple_sdk_out "  ${apple_sdk_out}")
+    message(CONFIGURE_LOG
+      "Detecting ${lang} compiler apple sysroot: \"${apple_sdk_cmd}\"\n"
+      "${apple_sdk_out}\n"
+      "${apple_sdk_msg}"
+    )
+  else()
+    set(CMAKE_${lang}_COMPILER_APPLE_SYSROOT "")
+  endif()
+
   set(_variant "")
   if("x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xClang"
     OR "x${CMAKE_${lang}_COMPILER_ID}" STREQUAL "xIntelLLVM")
@@ -392,6 +432,7 @@ function(CMAKE_DETERMINE_COMPILER_ID lang flagvar src)
   set(CMAKE_${lang}_COMPILER_PRODUCED_FILES "${COMPILER_${lang}_PRODUCED_FILES}" PARENT_SCOPE)
   set(CMAKE_${lang}_COMPILER_CLANG_RESOURCE_DIR "${CMAKE_${lang}_COMPILER_CLANG_RESOURCE_DIR}" PARENT_SCOPE)
   set(CMAKE_${lang}_STANDARD_LIBRARY "${CMAKE_${lang}_STANDARD_LIBRARY}" PARENT_SCOPE)
+  set(CMAKE_${lang}_COMPILER_APPLE_SYSROOT "${CMAKE_${lang}_COMPILER_APPLE_SYSROOT}" PARENT_SCOPE)
 endfunction()
 
 include(CMakeCompilerIdDetection)

+ 1 - 0
Modules/CMakeOBJCCompiler.cmake.in

@@ -17,6 +17,7 @@ set(CMAKE_OBJC23_COMPILE_FEATURES "@CMAKE_OBJC23_COMPILE_FEATURES@")
 set(CMAKE_OBJC_PLATFORM_ID "@CMAKE_OBJC_PLATFORM_ID@")
 set(CMAKE_OBJC_SIMULATE_ID "@CMAKE_OBJC_SIMULATE_ID@")
 set(CMAKE_OBJC_COMPILER_FRONTEND_VARIANT "@CMAKE_OBJC_COMPILER_FRONTEND_VARIANT@")
+set(CMAKE_OBJC_COMPILER_APPLE_SYSROOT "@CMAKE_OBJC_COMPILER_APPLE_SYSROOT@")
 set(CMAKE_OBJC_SIMULATE_VERSION "@CMAKE_OBJC_SIMULATE_VERSION@")
 @_SET_CMAKE_OBJC_COMPILER_ARCHITECTURE_ID@
 @SET_CMAKE_XCODE_ARCHS@

+ 1 - 0
Modules/CMakeOBJCXXCompiler.cmake.in

@@ -18,6 +18,7 @@ set(CMAKE_OBJCXX23_COMPILE_FEATURES "@CMAKE_OBJCXX23_COMPILE_FEATURES@")
 set(CMAKE_OBJCXX_PLATFORM_ID "@CMAKE_OBJCXX_PLATFORM_ID@")
 set(CMAKE_OBJCXX_SIMULATE_ID "@CMAKE_OBJCXX_SIMULATE_ID@")
 set(CMAKE_OBJCXX_COMPILER_FRONTEND_VARIANT "@CMAKE_OBJCXX_COMPILER_FRONTEND_VARIANT@")
+set(CMAKE_OBJCXX_COMPILER_APPLE_SYSROOT "@CMAKE_OBJCXX_COMPILER_APPLE_SYSROOT@")
 set(CMAKE_OBJCXX_SIMULATE_VERSION "@CMAKE_OBJCXX_SIMULATE_VERSION@")
 @_SET_CMAKE_OBJCXX_COMPILER_ARCHITECTURE_ID@
 @SET_CMAKE_XCODE_ARCHS@

+ 4 - 0
Modules/Platform/Apple-Clang.cmake

@@ -26,6 +26,10 @@ macro(__apple_compiler_clang lang)
   set(CMAKE_${lang}_USING_LINKER_MOLD "-fuse-ld=mold")
   set(CMAKE_${lang}_USING_LINKER_SOLD "-fuse-ld=sold")
 
+  if(NOT CMAKE_${lang}_COMPILER_APPLE_SYSROOT)
+    set(CMAKE_${lang}_COMPILER_APPLE_SYSROOT_REQUIRED 1)
+  endif()
+
   if(_CMAKE_OSX_SYSROOT_PATH MATCHES "/iPhoneOS")
     set(CMAKE_${lang}_OSX_DEPLOYMENT_TARGET_FLAG "-miphoneos-version-min=")
   elseif(_CMAKE_OSX_SYSROOT_PATH MATCHES "/iPhoneSimulator")

+ 5 - 0
Source/cmLocalGenerator.cxx

@@ -2014,6 +2014,11 @@ void cmLocalGenerator::AddArchitectureFlags(std::string& flags,
     }
 
     cmValue sysroot = this->Makefile->GetDefinition("CMAKE_OSX_SYSROOT");
+    if (sysroot.IsEmpty() &&
+        this->Makefile->IsOn(
+          cmStrCat("CMAKE_", lang, "_COMPILER_APPLE_SYSROOT_REQUIRED"))) {
+      sysroot = this->Makefile->GetDefinition("_CMAKE_OSX_SYSROOT_PATH");
+    }
     if (sysroot && *sysroot == "/") {
       sysroot = nullptr;
     }

+ 3 - 0
Tests/RunCMake/AppleSDK/CMakeLists.txt

@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 4.0)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)

+ 4 - 0
Tests/RunCMake/AppleSDK/NoSDK-stdout.txt

@@ -0,0 +1,4 @@
+-- CMAKE_C_COMPILER_APPLE_SYSROOT=''
+-- CMAKE_CXX_COMPILER_APPLE_SYSROOT=''
+-- CMAKE_OBJC_COMPILER_APPLE_SYSROOT=''
+-- CMAKE_OBJCXX_COMPILER_APPLE_SYSROOT=''

+ 5 - 0
Tests/RunCMake/AppleSDK/NoSDK.cmake

@@ -0,0 +1,5 @@
+enable_language(C CXX OBJC OBJCXX)
+message(STATUS "CMAKE_C_COMPILER_APPLE_SYSROOT='${CMAKE_C_COMPILER_APPLE_SYSROOT}'")
+message(STATUS "CMAKE_CXX_COMPILER_APPLE_SYSROOT='${CMAKE_CXX_COMPILER_APPLE_SYSROOT}'")
+message(STATUS "CMAKE_OBJC_COMPILER_APPLE_SYSROOT='${CMAKE_OBJC_COMPILER_APPLE_SYSROOT}'")
+message(STATUS "CMAKE_OBJCXX_COMPILER_APPLE_SYSROOT='${CMAKE_OBJCXX_COMPILER_APPLE_SYSROOT}'")

+ 47 - 0
Tests/RunCMake/AppleSDK/RunCMakeTest.cmake

@@ -0,0 +1,47 @@
+include(RunCMake)
+
+# Isolate from caller's environment.
+unset(ENV{CMAKE_OSX_ARCHITECTURES})
+unset(ENV{CMAKE_OSX_DEPLOYMENT_TARGET})
+unset(ENV{SDKROOT})
+
+function(run_xcode_cc)
+  set(RunCMake_TEST_VARIANT_DESCRIPTION "-xcode")
+  if(EXISTS "/usr/include/AvailabilityMacros.h")
+    run_cmake(SDK)
+  else()
+    run_cmake(NoSDK)
+  endif()
+endfunction()
+
+if(RunCMake_GENERATOR STREQUAL "Xcode")
+  run_xcode_cc()
+else()
+  set(system_cc "/usr/bin/cc")
+  set(system_cxx "/usr/bin/c++")
+  if(EXISTS "${system_cc}" AND EXISTS "${system_cxx}")
+    set(ENV{CC} "${system_cc}")
+    set(ENV{CXX} "${system_cxx}")
+    set(ENV{OBJC} "${system_cc}")
+    set(ENV{OBJCXX} "${system_cxx}")
+    set(RunCMake_TEST_VARIANT_DESCRIPTION "-system")
+    run_cmake(SDK)
+  endif()
+
+  execute_process(COMMAND xcrun --find cc OUTPUT_VARIABLE xcode_cc OUTPUT_STRIP_TRAILING_WHITESPACE)
+  execute_process(COMMAND xcrun --find c++ OUTPUT_VARIABLE xcode_cxx OUTPUT_STRIP_TRAILING_WHITESPACE)
+  execute_process(COMMAND xcrun --show-sdk-path OUTPUT_VARIABLE xcode_sdk OUTPUT_STRIP_TRAILING_WHITESPACE)
+  if(EXISTS "${xcode_cc}" AND EXISTS "${xcode_cxx}")
+    set(ENV{CC} "${xcode_cc}")
+    set(ENV{CXX} "${xcode_cxx}")
+    set(ENV{OBJC} "${xcode_cc}")
+    set(ENV{OBJCXX} "${xcode_cxx}")
+    run_xcode_cc()
+    if(EXISTS "${xcode_sdk}")
+      set(RunCMake_TEST_VARIANT_DESCRIPTION "-xcode-SDKROOT")
+      set(ENV{SDKROOT} "${xcode_sdk}")
+      run_cmake(SDK)
+      unset(ENV{SDKROOT})
+    endif()
+  endif()
+endif()

+ 4 - 0
Tests/RunCMake/AppleSDK/SDK-stdout.txt

@@ -0,0 +1,4 @@
+-- CMAKE_C_COMPILER_APPLE_SYSROOT='/([^']*/SDKs/MacOSX[0-9.]*\.sdk)?'
+-- CMAKE_CXX_COMPILER_APPLE_SYSROOT='/([^']*/SDKs/MacOSX[0-9.]*\.sdk)?'
+-- CMAKE_OBJC_COMPILER_APPLE_SYSROOT='/([^']*/SDKs/MacOSX[0-9.]*\.sdk)?'
+-- CMAKE_OBJCXX_COMPILER_APPLE_SYSROOT='/([^']*/SDKs/MacOSX[0-9.]*\.sdk)?'

+ 5 - 0
Tests/RunCMake/AppleSDK/SDK.cmake

@@ -0,0 +1,5 @@
+enable_language(C CXX OBJC OBJCXX)
+message(STATUS "CMAKE_C_COMPILER_APPLE_SYSROOT='${CMAKE_C_COMPILER_APPLE_SYSROOT}'")
+message(STATUS "CMAKE_CXX_COMPILER_APPLE_SYSROOT='${CMAKE_CXX_COMPILER_APPLE_SYSROOT}'")
+message(STATUS "CMAKE_OBJC_COMPILER_APPLE_SYSROOT='${CMAKE_OBJC_COMPILER_APPLE_SYSROOT}'")
+message(STATUS "CMAKE_OBJCXX_COMPILER_APPLE_SYSROOT='${CMAKE_OBJCXX_COMPILER_APPLE_SYSROOT}'")

+ 1 - 0
Tests/RunCMake/CMakeLists.txt

@@ -665,6 +665,7 @@ add_RunCMake_test(BundleUtilities)
 if(APPLE)
   add_RunCMake_test(INSTALL_NAME_DIR)
   add_RunCMake_test(MacOSVersions)
+  add_RunCMake_test(AppleSDK)
   add_RunCMake_test(AppleTextStubs)
 endif()