From 63ce2434377d8abbde881a80bbb6ffc0627055ad Mon Sep 17 00:00:00 2001 From: Devin Coughlin Date: Sun, 5 Jan 2020 21:25:47 -0800 Subject: [PATCH 1/6] [CMake] Add initial build system support for macCatalyst This commit adds initial build system support for macCatalyst, an Apple technology that enables code targeting iOS to be recompiled so that it can be executed on macOS while still using iOS APIs. This is the first in a series of commits building out support for macCatalyst in the compiler, runtime, standard library, and overlays. Swift for macCatalyst represents the work of multiple people, including Devin Coughlin, Ross Bayer, and Brent Royal-Gordon. Under macCatalyst, compiler-provided shared libraries (including overlays) are built as one of four kinds (or "flavors") of libraries, each with different install names and Mach-O load commands. This commit adds the build system infrastructure to produce these different library flavors. **macOS-like Libraries** A "macOS-like" library (such as the GLKit overlay) is a plain-old macOS library that can only be loaded into regular macOS processes. It has a macOS slice with a single load command allowing it to be loaded into normal macOS processes. **iOS-like Libraries** An "iOS-like" library, such as the UIKit overlay, is a library with a macOS slice but with a load command that only allows it be loaded into macCatalyst processes. iOS-like libraries are produced by passing a new target tuple to the compiler: swiftc ... -target x86_64-apple-ios13.0-macabi ... Here 'ios' (and an iOS version number) is used for OS portion of the triple, but the 'macabi' environment tells the compiler that the library is intended for macCatalyst. **Zippered Libraries** A "zippered" library can be loaded into either a macCatalyst process or a standard macOS process. Since macCatalyst does not introduce a new Mach-O slice, the same code is shared between both processes. Zippered libraries are usually relatively low level and with an API surface that is similar between macOS and iOS (for example, both the Foundation overlay and the Swift Standard Library/Runtime itself are zippered). Zippered libraries are created by passing both the usual `-target` flag to the compiler and an additional `-target-variant` flag: swiftc ... -target x86_64-apple-macos10.15 \ -target-variant x86_64-apple-ios13.0-macabi Just like the -target flag, -target-variant takes a target tuple. This tells the compiler to compile the library for the -target tuple but to add an extra load command, allowing the library to be loaded into processes of the -target-variant flavor as well. While a single zippered library and slice is shared between macOS and macCatalyst, zippered libraries require two separate .swiftinterface/.swiftmodule files, one for macOS and one for macCatalyst. When a macOS or macCatalyst client imports the library, it will use module file for its flavor to determine what symbols are present. This enables a zippered library to expose a subset of its target APIs to its target-variant. **Unzippered-Twin Libraries** "Unzippered Twins" are pairs of libraries with the same name but different contents and install locations, one for use from macOS processes and one for use from macCatalyst processes. Unzippered twins are usually libraries that depend on AppKit on macOS and UIKit on iOS (for example, the MapKit overlay) and so do not share a common implementation between macOS and macCatalyst. The macCatalyst version of an unzippered twin is installed in a parallel directory hierarchy rooted at /System/iOSSupport/. So, for example, while macOS and zippered Swift overlays are installed in /usr/lib/swift/, iOS-like and the macCatalyst side of unzippered twins are installed in /System/iOSSupport/usr/lib/swift. When building for macCatalyst, the build system passes additional search paths so that the macCatalyst version of libraries is found before macOS versions. The add_swift_target_library() funciton now take an optional MACCATALYST_BUILD_FLAVOR, which enables swift libraries to indicate which flavor of library they are. --- cmake/modules/AddSwift.cmake | 343 +++++++++++++++--- cmake/modules/StandaloneOverlay.cmake | 6 + cmake/modules/SwiftConfigureSDK.cmake | 16 +- cmake/modules/SwiftSource.cmake | 175 ++++++++- cmake/modules/macCatalystUtils.cmake | 100 +++++ stdlib/public/runtime/CMakeLists.txt | 1 + utils/build-script | 4 + utils/build-script-impl | 1 + .../build_swift/driver_arguments.py | 3 + utils/build_swift/tests/expected_options.py | 4 + .../tests/test_host_specific_configuration.py | 2 + 11 files changed, 601 insertions(+), 54 deletions(-) create mode 100644 cmake/modules/macCatalystUtils.cmake diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake index 2be88f8b615be..ed5e164144f87 100644 --- a/cmake/modules/AddSwift.cmake +++ b/cmake/modules/AddSwift.cmake @@ -1,3 +1,4 @@ +include(macCatalystUtils) include(SwiftList) include(SwiftXcodeSupport) include(SwiftWindowsSupport) @@ -30,7 +31,7 @@ endfunction() # Compute the library subdirectory to use for the given sdk and # architecture, placing the result in 'result_var_name'. function(compute_library_subdir result_var_name sdk arch) - if(sdk IN_LIST SWIFT_APPLE_PLATFORMS) + if(sdk IN_LIST SWIFT_APPLE_PLATFORMS OR sdk STREQUAL "MACCATALYST") set("${result_var_name}" "${SWIFT_SDK_${sdk}_LIB_SUBDIR}" PARENT_SCOPE) else() set("${result_var_name}" "${SWIFT_SDK_${sdk}_LIB_SUBDIR}/${arch}" PARENT_SCOPE) @@ -89,6 +90,7 @@ endfunction() # ANALYZE_CODE_COVERAGE analyze_code_coverage # RESULT_VAR_NAME result_var_name # DEPLOYMENT_VERSION_OSX version # If provided, overrides the default value of the OSX deployment target set by the Swift project for this compilation only. +# DEPLOYMENT_VERSION_MACCATALYST version # DEPLOYMENT_VERSION_IOS version # DEPLOYMENT_VERSION_TVOS version # DEPLOYMENT_VERSION_WATCHOS version @@ -96,20 +98,29 @@ endfunction() # ) function(_add_variant_c_compile_link_flags) set(oneValueArgs SDK ARCH BUILD_TYPE RESULT_VAR_NAME ENABLE_LTO ANALYZE_CODE_COVERAGE - DEPLOYMENT_VERSION_OSX DEPLOYMENT_VERSION_IOS DEPLOYMENT_VERSION_TVOS DEPLOYMENT_VERSION_WATCHOS) + DEPLOYMENT_VERSION_OSX DEPLOYMENT_VERSION_MACCATALYST DEPLOYMENT_VERSION_IOS DEPLOYMENT_VERSION_TVOS DEPLOYMENT_VERSION_WATCHOS + MACCATALYST_BUILD_FLAVOR + ) cmake_parse_arguments(CFLAGS "" "${oneValueArgs}" "" ${ARGN}) + get_maccatalyst_build_flavor(maccatalyst_build_flavor + "${CFLAGS_SDK}" "${CFLAGS_MACCATALYST_BUILD_FLAVOR}") + set(result ${${CFLAGS_RESULT_VAR_NAME}}) is_darwin_based_sdk("${CFLAGS_SDK}" IS_DARWIN) if(IS_DARWIN) # Check if there's a specific OS deployment version needed for this invocation if("${CFLAGS_SDK}" STREQUAL "OSX") - set(DEPLOYMENT_VERSION ${CFLAGS_DEPLOYMENT_VERSION_OSX}) + if(DEFINED maccatalyst_build_flavor) + set(DEPLOYMENT_VERSION ${CFLAGS_DEPLOYMENT_VERSION_MACCATALYST}) + else() + set(DEPLOYMENT_VERSION ${CFLAGS_DEPLOYMENT_VERSION_OSX}) + endif() elseif("${CFLAGS_SDK}" STREQUAL "IOS" OR "${CFLAGS_SDK}" STREQUAL "IOS_SIMULATOR") set(DEPLOYMENT_VERSION ${CFLAGS_DEPLOYMENT_VERSION_IOS}) elseif("${CFLAGS_SDK}" STREQUAL "TVOS" OR "${CFLAGS_SDK}" STREQUAL "TVOS_SIMULATOR") @@ -126,7 +137,13 @@ function(_add_variant_c_compile_link_flags) # MSVC, clang-cl, gcc don't understand -target. if(CMAKE_C_COMPILER_ID MATCHES "^Clang|AppleClang$" AND NOT SWIFT_COMPILER_IS_MSVC_LIKE) - list(APPEND result "-target" "${SWIFT_SDK_${CFLAGS_SDK}_ARCH_${CFLAGS_ARCH}_TRIPLE}${DEPLOYMENT_VERSION}") + get_target_triple(target target_variant "${CFLAGS_SDK}" "${CFLAGS_ARCH}" + MACCATALYST_BUILD_FLAVOR "${maccatalyst_build_flavor}" + DEPLOYMENT_VERSION "${DEPLOYMENT_VERSION}") + list(APPEND result "-target" "${target}") + if(target_variant) + list(APPEND result "-target-variant" "${target_variant}") + endif() endif() set(_sysroot "${SWIFT_SDK_${CFLAGS_SDK}_ARCH_${CFLAGS_ARCH}_PATH}") @@ -148,8 +165,21 @@ function(_add_variant_c_compile_link_flags) if(IS_DARWIN) list(APPEND result "-arch" "${CFLAGS_ARCH}" - "-F" "${SWIFT_SDK_${CFLAGS_SDK}_PATH}/../../../Developer/Library/Frameworks" - "-m${SWIFT_SDK_${CFLAGS_SDK}_VERSION_MIN_NAME}-version-min=${DEPLOYMENT_VERSION}") + "-F" "${SWIFT_SDK_${CFLAGS_SDK}_PATH}/../../../Developer/Library/Frameworks") + + set(add_explicit_version TRUE) + + # iOS-like and zippered libraries get their deployment version from the + # target triple + if(maccatalyst_build_flavor STREQUAL "ios-like" OR + maccatalyst_build_flavor STREQUAL "zippered") + set(add_explicit_version FALSE) + endif() + + if(add_explicit_version) + list(APPEND result + "-m${SWIFT_SDK_${CFLAGS_SDK}_VERSION_MIN_NAME}-version-min=${DEPLOYMENT_VERSION}") + endif() endif() if(CFLAGS_ANALYZE_CODE_COVERAGE) @@ -165,10 +195,12 @@ function(_add_variant_c_compile_link_flags) set("${CFLAGS_RESULT_VAR_NAME}" "${result}" PARENT_SCOPE) endfunction() + function(_add_variant_c_compile_flags) set(oneValueArgs SDK ARCH BUILD_TYPE ENABLE_ASSERTIONS ANALYZE_CODE_COVERAGE - DEPLOYMENT_VERSION_OSX DEPLOYMENT_VERSION_IOS DEPLOYMENT_VERSION_TVOS DEPLOYMENT_VERSION_WATCHOS - RESULT_VAR_NAME ENABLE_LTO) + DEPLOYMENT_VERSION_OSX DEPLOYMENT_VERSION_MACCATALYST DEPLOYMENT_VERSION_IOS DEPLOYMENT_VERSION_TVOS DEPLOYMENT_VERSION_WATCHOS + RESULT_VAR_NAME ENABLE_LTO + MACCATALYST_BUILD_FLAVOR) cmake_parse_arguments(CFLAGS "FORCE_BUILD_OPTIMIZED" "${oneValueArgs}" @@ -185,10 +217,12 @@ function(_add_variant_c_compile_flags) ENABLE_LTO "${CFLAGS_ENABLE_LTO}" ANALYZE_CODE_COVERAGE FALSE DEPLOYMENT_VERSION_OSX "${CFLAGS_DEPLOYMENT_VERSION_OSX}" + DEPLOYMENT_VERSION_MACCATALYST "${CFLAGS_DEPLOYMENT_VERSION_MACCATALYST}" DEPLOYMENT_VERSION_IOS "${CFLAGS_DEPLOYMENT_VERSION_IOS}" DEPLOYMENT_VERSION_TVOS "${CFLAGS_DEPLOYMENT_VERSION_TVOS}" DEPLOYMENT_VERSION_WATCHOS "${CFLAGS_DEPLOYMENT_VERSION_WATCHOS}" - RESULT_VAR_NAME result) + RESULT_VAR_NAME result + MACCATALYST_BUILD_FLAVOR "${CFLAGS_MACCATALYST_BUILD_FLAVOR}") is_build_type_optimized("${CFLAGS_BUILD_TYPE}" optimized) if(optimized OR CFLAGS_FORCE_BUILD_OPTIMIZED) @@ -370,6 +404,13 @@ function(_add_variant_swift_compile_flags sdk arch build_type enable_assertions result_var_name) set(result ${${result_var_name}}) + cmake_parse_arguments( + VARIANT # prefix + "" # options + "MACCATALYST_BUILD_FLAVOR" # single-value args + "" # multi-value args + ${ARGN}) + # On Windows, we don't set SWIFT_SDK_WINDOWS_PATH_ARCH_{ARCH}_PATH, so don't include it. # On Android the sdk is split to two different paths for includes and libs, so these # need to be set manually. @@ -379,8 +420,15 @@ function(_add_variant_swift_compile_flags is_darwin_based_sdk("${sdk}" IS_DARWIN) if(IS_DARWIN) - list(APPEND result - "-target" "${SWIFT_SDK_${sdk}_ARCH_${arch}_TRIPLE}${SWIFT_SDK_${sdk}_DEPLOYMENT_VERSION}") + set(sdk_deployment_version "${SWIFT_SDK_${sdk}_DEPLOYMENT_VERSION}") + get_target_triple(target target_variant "${sdk}" "${arch}" + MACCATALYST_BUILD_FLAVOR "${VARIANT_MACCATALYST_BUILD_FLAVOR}" + DEPLOYMENT_VERSION "${sdk_deployment_version}") + + list(APPEND result "-target" "${target}") + if(target_variant) + list(APPEND result "-target-variant" "${target_variant}") + endif() else() list(APPEND result "-target" "${SWIFT_SDK_${sdk}_ARCH_${arch}_TRIPLE}") @@ -431,8 +479,10 @@ endfunction() function(_add_variant_link_flags) set(oneValueArgs SDK ARCH BUILD_TYPE ENABLE_ASSERTIONS ANALYZE_CODE_COVERAGE - DEPLOYMENT_VERSION_OSX DEPLOYMENT_VERSION_IOS DEPLOYMENT_VERSION_TVOS DEPLOYMENT_VERSION_WATCHOS - RESULT_VAR_NAME ENABLE_LTO LTO_OBJECT_NAME LINK_LIBRARIES_VAR_NAME LIBRARY_SEARCH_DIRECTORIES_VAR_NAME) + DEPLOYMENT_VERSION_OSX DEPLOYMENT_VERSION_MACCATALYST DEPLOYMENT_VERSION_IOS DEPLOYMENT_VERSION_TVOS DEPLOYMENT_VERSION_WATCHOS + RESULT_VAR_NAME ENABLE_LTO LTO_OBJECT_NAME LINK_LIBRARIES_VAR_NAME LIBRARY_SEARCH_DIRECTORIES_VAR_NAME + MACCATALYST_BUILD_FLAVOR + ) cmake_parse_arguments(LFLAGS "" "${oneValueArgs}" @@ -454,11 +504,12 @@ function(_add_variant_link_flags) ENABLE_LTO "${LFLAGS_ENABLE_LTO}" ANALYZE_CODE_COVERAGE "${LFLAGS_ANALYZE_CODE_COVERAGE}" DEPLOYMENT_VERSION_OSX "${LFLAGS_DEPLOYMENT_VERSION_OSX}" + DEPLOYMENT_VERSION_MACCATALYST "${LFLAGS_DEPLOYMENT_VERSION_MACCATALYST}" DEPLOYMENT_VERSION_IOS "${LFLAGS_DEPLOYMENT_VERSION_IOS}" DEPLOYMENT_VERSION_TVOS "${LFLAGS_DEPLOYMENT_VERSION_TVOS}" DEPLOYMENT_VERSION_WATCHOS "${LFLAGS_DEPLOYMENT_VERSION_WATCHOS}" - RESULT_VAR_NAME result) - + RESULT_VAR_NAME result + MACCATALYST_BUILD_FLAVOR "${LFLAGS_MACCATALYST_BUILD_FLAVOR}") if("${LFLAGS_SDK}" STREQUAL "LINUX") list(APPEND link_libraries "pthread" "atomic" "dl") elseif("${LFLAGS_SDK}" STREQUAL "FREEBSD") @@ -557,6 +608,9 @@ function(_add_variant_link_flags) endif() endif() + get_maccatalyst_build_flavor(maccatalyst_build_flavor + "${LFLAGS_SDK}" "${LFLAGS_MACCATALYST_BUILD_FLAVOR}") + set("${LFLAGS_RESULT_VAR_NAME}" "${result}" PARENT_SCOPE) set("${LFLAGS_LINK_LIBRARIES_VAR_NAME}" "${link_libraries}" PARENT_SCOPE) set("${LFLAGS_LIBRARY_SEARCH_DIRECTORIES_VAR_NAME}" "${library_search_directories}" PARENT_SCOPE) @@ -662,7 +716,7 @@ endfunction() # _add_swift_library_single( # target # name -# [MODULE_TARGET] +# [MODULE_TARGETS] # [SHARED] # [STATIC] # [SDK sdk] @@ -682,6 +736,7 @@ endfunction() # [IS_STDLIB_CORE] # [IS_SDK_OVERLAY] # INSTALL_IN_COMPONENT comp +# MACCATALYST_BUILD_FLAVOR flavor # source1 [source2 source3 ...]) # # target @@ -690,8 +745,8 @@ endfunction() # name # Name of the library (e.g., swiftParse). # -# MODULE_TARGET -# Name of the module target (e.g., swiftParse-swiftmodule-IOS-armv7). +# MODULE_TARGETS +# Names of the module target (e.g., swiftParse-swiftmodule-IOS-armv7). # # SHARED # Build a shared library. @@ -747,6 +802,9 @@ endfunction() # INSTALL_IN_COMPONENT comp # The Swift installation component that this library belongs to. # +# MACCATALYST_BUILD_FLAVOR +# Possible values are 'ios-like', 'macos-like', 'zippered', 'unzippered-twin' +# # source1 ... # Sources to add into this library function(_add_swift_library_single target name) @@ -770,8 +828,9 @@ function(_add_swift_library_single target name) DEPLOYMENT_VERSION_WATCHOS INSTALL_IN_COMPONENT DARWIN_INSTALL_NAME_DIR - MODULE_TARGET - SDK) + SDK + DEPLOYMENT_VERSION_MACCATALYST + MACCATALYST_BUILD_FLAVOR) set(SWIFTLIB_SINGLE_multiple_parameter_options C_COMPILE_FLAGS DEPENDS @@ -785,13 +844,19 @@ function(_add_swift_library_single target name) LINK_LIBRARIES LLVM_LINK_COMPONENTS PRIVATE_LINK_LIBRARIES - SWIFT_COMPILE_FLAGS) + SWIFT_COMPILE_FLAGS + MODULE_TARGETS) cmake_parse_arguments(SWIFTLIB_SINGLE "${SWIFTLIB_SINGLE_options}" "${SWIFTLIB_SINGLE_single_parameter_options}" "${SWIFTLIB_SINGLE_multiple_parameter_options}" ${ARGN}) + + # Determine macCatalyst build flavor + get_maccatalyst_build_flavor(maccatalyst_build_flavor + "${SWIFTLIB_SINGLE_SDK}" "${SWIFTLIB_SINGLE_MACCATALYST_BUILD_FLAVOR}") + set(SWIFTLIB_SINGLE_SOURCES ${SWIFTLIB_SINGLE_UNPARSED_ARGUMENTS}) translate_flags(SWIFTLIB_SINGLE "${SWIFTLIB_SINGLE_options}") @@ -812,6 +877,12 @@ function(_add_swift_library_single target name) set(SWIFTLIB_SINGLE_SUBDIR "${SWIFT_SDK_${SWIFTLIB_SINGLE_SDK}_LIB_SUBDIR}/${SWIFTLIB_SINGLE_ARCHITECTURE}") + # macCatalyst ios-like builds are installed in the maccatalyst/x86_64 directory + if(maccatalyst_build_flavor STREQUAL "ios-like") + set(SWIFTLIB_SINGLE_SUBDIR + "${SWIFT_SDK_MACCATALYST_LIB_SUBDIR}/${SWIFTLIB_SINGLE_ARCHITECTURE}") + endif() + # Include LLVM Bitcode slices for iOS, Watch OS, and Apple TV OS device libraries. set(embed_bitcode_arg) if(SWIFT_EMBED_BITCODE_SECTION AND NOT SWIFTLIB_SINGLE_DONT_EMBED_BITCODE) @@ -925,17 +996,24 @@ function(_add_swift_library_single target name) ${SWIFTLIB_SINGLE_IS_STDLIB_CORE_keyword} ${SWIFTLIB_SINGLE_IS_SDK_OVERLAY_keyword} ${embed_bitcode_arg} - INSTALL_IN_COMPONENT "${SWIFTLIB_SINGLE_INSTALL_IN_COMPONENT}") + INSTALL_IN_COMPONENT "${SWIFTLIB_SINGLE_INSTALL_IN_COMPONENT}" + MACCATALYST_BUILD_FLAVOR "${SWIFTLIB_SINGLE_MACCATALYST_BUILD_FLAVOR}") add_swift_source_group("${SWIFTLIB_SINGLE_EXTERNAL_SOURCES}") # If there were any swift sources, then a .swiftmodule may have been created. # If that is the case, then add a target which is an alias of the module files. set(VARIANT_SUFFIX "-${SWIFT_SDK_${SWIFTLIB_SINGLE_SDK}_LIB_SUBDIR}-${SWIFTLIB_SINGLE_ARCHITECTURE}") - if(NOT "${SWIFTLIB_SINGLE_MODULE_TARGET}" STREQUAL "" AND NOT "${swift_module_dependency_target}" STREQUAL "") - add_custom_target("${SWIFTLIB_SINGLE_MODULE_TARGET}" - DEPENDS ${swift_module_dependency_target}) - set_target_properties("${SWIFTLIB_SINGLE_MODULE_TARGET}" PROPERTIES - FOLDER "Swift libraries/Modules") + if(maccatalyst_build_flavor STREQUAL "ios-like") + set(VARIANT_SUFFIX "-${SWIFT_SDK_MACCATALYST_LIB_SUBDIR}-${SWIFTLIB_SINGLE_ARCHITECTURE}") + endif() + + if(NOT "${SWIFTLIB_SINGLE_MODULE_TARGETS}" STREQUAL "" AND NOT "${swift_module_dependency_target}" STREQUAL "") + foreach(module_target ${SWIFTLIB_SINGLE_MODULE_TARGETS}) + add_custom_target("${module_target}" + DEPENDS ${swift_module_dependency_target}) + set_target_properties("${module_target}" PROPERTIES + FOLDER "Swift libraries/Modules") + endforeach() endif() # For standalone overlay builds to work @@ -1082,6 +1160,13 @@ function(_add_swift_library_single target name) if(SWIFTLIB_SINGLE_IS_STDLIB) set(install_name_dir "${SWIFT_DARWIN_STDLIB_INSTALL_NAME_DIR}") + + # iOS-like overlays are installed in a separate directory so that + # unzippered twins do not conflict. + if(maccatalyst_build_flavor STREQUAL "ios-like" + AND DEFINED SWIFT_DARWIN_MACCATALYST_STDLIB_INSTALL_NAME_DIR) + set(install_name_dir "${SWIFT_DARWIN_MACCATALYST_STDLIB_INSTALL_NAME_DIR}") + endif() endif() # Always use @rpath for XCTest @@ -1295,11 +1380,13 @@ function(_add_swift_library_single target name) ANALYZE_CODE_COVERAGE "${analyze_code_coverage}" ENABLE_LTO "${lto_type}" DEPLOYMENT_VERSION_OSX "${SWIFTLIB_DEPLOYMENT_VERSION_OSX}" + DEPLOYMENT_VERSION_MACCATALYST "${SWIFTLIB_DEPLOYMENT_VERSION_MACCATALYST}" DEPLOYMENT_VERSION_IOS "${SWIFTLIB_DEPLOYMENT_VERSION_IOS}" DEPLOYMENT_VERSION_TVOS "${SWIFTLIB_DEPLOYMENT_VERSION_TVOS}" DEPLOYMENT_VERSION_WATCHOS "${SWIFTLIB_DEPLOYMENT_VERSION_WATCHOS}" "${SWIFTLIB_SINGLE_FORCE_BUILD_OPTIMIZED_keyword}" RESULT_VAR_NAME c_compile_flags + MACCATALYST_BUILD_FLAVOR "${SWIFTLIB_SINGLE_MACCATALYST_BUILD_FLAVOR}" ) if(SWIFTLIB_IS_STDLIB) @@ -1324,12 +1411,14 @@ function(_add_swift_library_single target name) ENABLE_LTO "${lto_type}" LTO_OBJECT_NAME "${target}-${SWIFTLIB_SINGLE_SDK}-${SWIFTLIB_SINGLE_ARCHITECTURE}" DEPLOYMENT_VERSION_OSX "${SWIFTLIB_DEPLOYMENT_VERSION_OSX}" + DEPLOYMENT_VERSION_MACCATALYST "${SWIFTLIB_DEPLOYMENT_VERSION_MACCATALYST}" DEPLOYMENT_VERSION_IOS "${SWIFTLIB_DEPLOYMENT_VERSION_IOS}" DEPLOYMENT_VERSION_TVOS "${SWIFTLIB_DEPLOYMENT_VERSION_TVOS}" DEPLOYMENT_VERSION_WATCHOS "${SWIFTLIB_DEPLOYMENT_VERSION_WATCHOS}" RESULT_VAR_NAME link_flags LINK_LIBRARIES_VAR_NAME link_libraries LIBRARY_SEARCH_DIRECTORIES_VAR_NAME library_search_directories + MACCATALYST_BUILD_FLAVOR "${SWIFTLIB_SINGLE_MACCATALYST_BUILD_FLAVOR}" ) # Configure plist creation for OS X. @@ -1565,9 +1654,11 @@ endfunction() # [INSTALL_WITH_SHARED] # INSTALL_IN_COMPONENT comp # DEPLOYMENT_VERSION_OSX version +# DEPLOYMENT_VERSION_MACCATALYST version # DEPLOYMENT_VERSION_IOS version # DEPLOYMENT_VERSION_TVOS version # DEPLOYMENT_VERSION_WATCHOS version +# MACCATALYST_BUILD_FLAVOR flavor # source1 [source2 source3 ...]) # # name @@ -1591,6 +1682,14 @@ endfunction() # SWIFT_MODULE_DEPENDS_OSX # Swift modules this library depends on when built for OS X. # +# SWIFT_MODULE_DEPENDS_MACCATALYST +# Zippered Swift modules this library depends on when built for macCatalyst. +# For example, Foundation. +# +# SWIFT_MODULE_DEPENDS_MACCATALYST_UNZIPPERED +# Unzippered Swift modules this library depends on when built for macCatalyst. +# For example, UIKit +# # SWIFT_MODULE_DEPENDS_IOS # Swift modules this library depends on when built for iOS. # @@ -1648,7 +1747,6 @@ endfunction() # # IS_SDK_OVERLAY # Treat the library as a part of the Swift SDK overlay. -# IS_SDK_OVERLAY implies IS_STDLIB. # # INSTALL_IN_COMPONENT comp # The Swift installation component that this library belongs to. @@ -1656,6 +1754,9 @@ endfunction() # DEPLOYMENT_VERSION_OSX # The minimum deployment version to build for if this is an OSX library. # +# DEPLOYMENT_VERSION_MACCATALYST +# The minimum deployment version to build for if this is an macCatalyst library. +# # DEPLOYMENT_VERSION_IOS # The minimum deployment version to build for if this is an iOS library. # @@ -1668,6 +1769,11 @@ endfunction() # INSTALL_WITH_SHARED # Install a static library target alongside shared libraries # +# MACCATALYST_BUILD_FLAVOR +# Possible values are 'ios-like', 'macos-like', 'zippered', 'unzippered-twin' +# Presence of a build flavor requires SWIFT_MODULE_DEPENDS_MACCATALYST to be +# defined and have values. +# # source1 ... # Sources to add into this library. function(add_swift_target_library name) @@ -1689,7 +1795,9 @@ function(add_swift_target_library name) DEPLOYMENT_VERSION_TVOS DEPLOYMENT_VERSION_WATCHOS INSTALL_IN_COMPONENT - DARWIN_INSTALL_NAME_DIR) + DARWIN_INSTALL_NAME_DIR + DEPLOYMENT_VERSION_MACCATALYST + MACCATALYST_BUILD_FLAVOR) set(SWIFTLIB_multiple_parameter_options C_COMPILE_FLAGS DEPENDS @@ -1722,7 +1830,10 @@ function(add_swift_target_library name) SWIFT_MODULE_DEPENDS_WATCHOS SWIFT_MODULE_DEPENDS_WINDOWS SWIFT_MODULE_DEPENDS_FROM_SDK - TARGET_SDKS) + TARGET_SDKS + SWIFT_COMPILE_FLAGS_MACCATALYST + SWIFT_MODULE_DEPENDS_MACCATALYST + SWIFT_MODULE_DEPENDS_MACCATALYST_UNZIPPERED) cmake_parse_arguments(SWIFTLIB "${SWIFTLIB_options}" @@ -1731,6 +1842,15 @@ function(add_swift_target_library name) ${ARGN}) set(SWIFTLIB_SOURCES ${SWIFTLIB_UNPARSED_ARGUMENTS}) + # Ensure it's impossible to build for macCatalyst without module dependencies + if(SWIFT_ENABLE_MACCATALYST AND SWIFTLIB_MACCATALYST_BUILD_FLAVOR) + if((NOT SWIFTLIB_MACCATALYST_BUILD_FLAVOR STREQUAL "zippered") OR + SWIFTLIB_SWIFT_MODULE_DEPENDS_OSX) + precondition(SWIFTLIB_SWIFT_MODULE_DEPENDS_MACCATALYST + MESSAGE "SWIFT_MODULE_DEPENDS_MACCATALYST is required when building for macCatalyst") + endif() + endif() + # Infer arguments. if(SWIFTLIB_IS_SDK_OVERLAY) @@ -1802,11 +1922,50 @@ function(add_swift_target_library name) continue() endif() + # Skip building library for macOS if macCatalyst support is not enabled and the + # library only builds for macOS when macCatalyst is enabled. + if(NOT SWIFT_ENABLE_MACCATALYST AND + sdk STREQUAL "OSX" AND + SWIFTLIB_MACCATALYST_BUILD_FLAVOR STREQUAL "ios-like") + message(STATUS "Skipping OSX SDK for module ${name}") + continue() + endif() + + # Determine if/what macCatalyst build flavor we are + get_maccatalyst_build_flavor(maccatalyst_build_flavor + "${sdk}" "${SWIFTLIB_MACCATALYST_BUILD_FLAVOR}") + + set(maccatalyst_build_flavors) + if(NOT DEFINED maccatalyst_build_flavor) + list(APPEND maccatalyst_build_flavors "none") + elseif(maccatalyst_build_flavor STREQUAL "unzippered-twin") + list(APPEND maccatalyst_build_flavors "macos-like" "ios-like") + else() + list(APPEND maccatalyst_build_flavors "${maccatalyst_build_flavor}") + endif() + + # Loop over the build flavors for the this library. If it is an unzippered + # twin we'll build it twice: once for "macos-like" and once for "ios-like" + # flavors. + foreach(maccatalyst_build_flavor ${maccatalyst_build_flavors}) + if(maccatalyst_build_flavor STREQUAL "none") + unset(maccatalyst_build_flavor) + endif() + set(THIN_INPUT_TARGETS) # Collect architecture agnostic SDK module dependencies set(swiftlib_module_depends_flattened ${SWIFTLIB_SWIFT_MODULE_DEPENDS}) if(${sdk} STREQUAL OSX) + if(DEFINED maccatalyst_build_flavor AND NOT maccatalyst_build_flavor STREQUAL "macos-like") + list(APPEND swiftlib_module_depends_flattened + ${SWIFTLIB_SWIFT_MODULE_DEPENDS_MACCATALYST}) + list(APPEND swiftlib_module_depends_flattened + ${SWIFTLIB_SWIFT_MODULE_DEPENDS_MACCATALYST_UNZIPPERED}) + else() + list(APPEND swiftlib_module_depends_flattened + ${SWIFTLIB_SWIFT_MODULE_DEPENDS_OSX}) + endif() list(APPEND swiftlib_module_depends_flattened ${SWIFTLIB_SWIFT_MODULE_DEPENDS_OSX}) elseif(${sdk} STREQUAL IOS OR ${sdk} STREQUAL IOS_SIMULATOR) @@ -1923,6 +2082,15 @@ function(add_swift_target_library name) set(MODULE_VARIANT_SUFFIX "-swiftmodule${VARIANT_SUFFIX}") set(MODULE_VARIANT_NAME "${name}${MODULE_VARIANT_SUFFIX}") + # Configure macCatalyst flavor variables + if(DEFINED maccatalyst_build_flavor) + set(maccatalyst_variant_suffix "-${SWIFT_SDK_MACCATALYST_LIB_SUBDIR}-${arch}") + set(maccatalyst_variant_name "${name}${maccatalyst_variant_suffix}") + + set(maccatalyst_module_variant_suffix "-swiftmodule${maccatalyst_variant_suffix}") + set(maccatalyst_module_variant_name "${name}${maccatalyst_module_variant_suffix}") + endif() + # Map dependencies over to the appropriate variants. set(swiftlib_link_libraries) foreach(lib ${SWIFTLIB_LINK_LIBRARIES}) @@ -1940,6 +2108,44 @@ function(add_swift_target_library name) if(NOT BUILD_STANDALONE) foreach(mod ${swiftlib_module_depends_flattened}) + if(DEFINED maccatalyst_build_flavor) + if(maccatalyst_build_flavor STREQUAL "zippered") + # Zippered libraries are dependent on both the macCatalyst and normal macOS + # modules of their dependencies (which themselves must be zippered). + list(APPEND swiftlib_module_dependency_targets + "swift${mod}${maccatalyst_module_variant_suffix}") + list(APPEND swiftlib_module_dependency_targets + "swift${mod}${MODULE_VARIANT_SUFFIX}") + + # Zippered libraries link against their zippered library targets, which + # live (and are built in) the same location as normal macOS libraries. + list(APPEND swiftlib_private_link_libraries_targets + "swift${mod}${VARIANT_SUFFIX}") + elseif(maccatalyst_build_flavor STREQUAL "ios-like") + # iOS-like libraries depend on the macCatalyst modules of their dependencies + # regardless of whether the target is zippered or macCatalyst only. + list(APPEND swiftlib_module_dependency_targets + "swift${mod}${maccatalyst_module_variant_suffix}") + + # iOS-like libraries can link against either iOS-like library targets + # or zippered targets. + if(mod IN_LIST SWIFTLIB_SWIFT_MODULE_DEPENDS_MACCATALYST_UNZIPPERED) + list(APPEND swiftlib_private_link_libraries_targets + "swift${mod}${maccatalyst_variant_suffix}") + else() + list(APPEND swiftlib_private_link_libraries_targets + "swift${mod}${VARIANT_SUFFIX}") + endif() + else() + list(APPEND swiftlib_module_dependency_targets + "swift${mod}${MODULE_VARIANT_SUFFIX}") + + list(APPEND swiftlib_private_link_libraries_targets + "swift${mod}${VARIANT_SUFFIX}") + endif() + continue() + endif() + list(APPEND swiftlib_module_dependency_targets "swift${mod}${MODULE_VARIANT_SUFFIX}") @@ -1959,6 +2165,25 @@ function(add_swift_target_library name) # Add PrivateFrameworks, rdar://28466433 set(swiftlib_c_compile_flags_all ${SWIFTLIB_C_COMPILE_FLAGS}) + set(swiftlib_link_flags_all ${SWIFTLIB_LINK_FLAGS}) + + # Add flags to prepend framework search paths for the parallel framework + # hierarchy rooted at /System/iOSSupport/... + # These paths must come before their normal counterparts so that when compiling + # macCatalyst-only or unzippered-twin overlays the macCatalyst version + # of a framework is found and not the Mac version. + if(maccatalyst_build_flavor STREQUAL "ios-like" + OR (name STREQUAL "swiftXCTest" + AND maccatalyst_build_flavor STREQUAL "zippered")) + + # The path to find iOS-only frameworks (such as UIKit) under macCatalyst. + set(ios_support_frameworks_path "${SWIFT_SDK_${sdk}_PATH}/System/iOSSupport/System/Library/Frameworks/") + + list(APPEND swiftlib_swift_compile_flags_all "-Fsystem" "${ios_support_frameworks_path}") + list(APPEND swiftlib_c_compile_flags_all "-iframework" "${ios_support_frameworks_path}") + list(APPEND swiftlib_link_flags_all "-F" "${ios_support_frameworks_path}") + endif() + if(sdk IN_LIST SWIFT_APPLE_PLATFORMS AND SWIFTLIB_IS_SDK_OVERLAY) set(swiftlib_swift_compile_private_frameworks_flag "-Fsystem" "${SWIFT_SDK_${sdk}_ARCH_${arch}_PATH}/System/Library/PrivateFrameworks/") foreach(tbd_lib ${SWIFTLIB_SWIFT_MODULE_DEPENDS_FROM_SDK}) @@ -1966,11 +2191,22 @@ function(add_swift_target_library name) endforeach() endif() - list(APPEND swiftlib_c_compile_flags_all "-DSWIFT_TARGET_LIBRARY_NAME=${name}") + set(variant_name "${VARIANT_NAME}") + set(module_variant_names "${MODULE_VARIANT_NAME}") + if(maccatalyst_build_flavor STREQUAL "ios-like") + set(variant_name "${maccatalyst_variant_name}") + set(module_variant_names "${maccatalyst_module_variant_name}") + elseif(maccatalyst_build_flavor STREQUAL "zippered") + # Zippered libraries produce two modules: one for macCatalyst and one for macOS + # and so need two module targets. + list(APPEND module_variant_names "${maccatalyst_module_variant_name}") + endif() + + list(APPEND swiftlib_c_compile_flags_all "-DSWIFT_TARGET_LIBRARY_NAME=${name}") # Add this library variant. _add_swift_library_single( - ${VARIANT_NAME} + ${variant_name} ${name} ${SWIFTLIB_SHARED_keyword} ${SWIFTLIB_STATIC_keyword} @@ -1978,7 +2214,7 @@ function(add_swift_target_library name) ${SWIFTLIB_INSTALL_WITH_SHARED_keyword} ${SWIFTLIB_SOURCES} TARGET_LIBRARY - MODULE_TARGET ${MODULE_VARIANT_NAME} + MODULE_TARGETS ${module_variant_names} SDK ${sdk} ARCHITECTURE ${arch} DEPENDS ${SWIFTLIB_DEPENDS} @@ -2002,9 +2238,12 @@ function(add_swift_target_library name) DARWIN_INSTALL_NAME_DIR "${SWIFTLIB_DARWIN_INSTALL_NAME_DIR}" INSTALL_IN_COMPONENT "${SWIFTLIB_INSTALL_IN_COMPONENT}" DEPLOYMENT_VERSION_OSX "${SWIFTLIB_DEPLOYMENT_VERSION_OSX}" + DEPLOYMENT_VERSION_MACCATALYST "${SWIFTLIB_DEPLOYMENT_VERSION_MACCATALYST}" DEPLOYMENT_VERSION_IOS "${SWIFTLIB_DEPLOYMENT_VERSION_IOS}" DEPLOYMENT_VERSION_TVOS "${SWIFTLIB_DEPLOYMENT_VERSION_TVOS}" DEPLOYMENT_VERSION_WATCHOS "${SWIFTLIB_DEPLOYMENT_VERSION_WATCHOS}" + MACCATALYST_BUILD_FLAVOR "${maccatalyst_build_flavor}" + GYB_SOURCES ${SWIFTLIB_GYB_SOURCES} ) if(NOT SWIFT_BUILT_STANDALONE AND NOT "${CMAKE_C_COMPILER_ID}" MATCHES "Clang") @@ -2076,27 +2315,32 @@ function(add_swift_target_library name) return() endif() + set(library_subdir "${SWIFT_SDK_${sdk}_LIB_SUBDIR}") + if(maccatalyst_build_flavor STREQUAL "ios-like") + set(library_subdir "${SWIFT_SDK_MACCATALYST_LIB_SUBDIR}") + endif() + if(NOT SWIFTLIB_OBJECT_LIBRARY) # Determine the name of the universal library. if(SWIFTLIB_SHARED) if("${sdk}" STREQUAL "WINDOWS") set(UNIVERSAL_LIBRARY_NAME - "${SWIFTLIB_DIR}/${SWIFT_SDK_${sdk}_LIB_SUBDIR}/${name}.dll") + "${SWIFTLIB_DIR}/${library_subdir}/${name}.dll") else() set(UNIVERSAL_LIBRARY_NAME - "${SWIFTLIB_DIR}/${SWIFT_SDK_${sdk}_LIB_SUBDIR}/${CMAKE_SHARED_LIBRARY_PREFIX}${name}${CMAKE_SHARED_LIBRARY_SUFFIX}") + "${SWIFTLIB_DIR}/${library_subdir}/${CMAKE_SHARED_LIBRARY_PREFIX}${name}${CMAKE_SHARED_LIBRARY_SUFFIX}") endif() else() if("${sdk}" STREQUAL "WINDOWS") set(UNIVERSAL_LIBRARY_NAME - "${SWIFTLIB_DIR}/${SWIFT_SDK_${sdk}_LIB_SUBDIR}/${name}.lib") + "${SWIFTLIB_DIR}/${library_subdir}/${name}.lib") else() set(UNIVERSAL_LIBRARY_NAME - "${SWIFTLIB_DIR}/${SWIFT_SDK_${sdk}_LIB_SUBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${name}${CMAKE_STATIC_LIBRARY_SUFFIX}") + "${SWIFTLIB_DIR}/${library_subdir}/${CMAKE_STATIC_LIBRARY_PREFIX}${name}${CMAKE_STATIC_LIBRARY_SUFFIX}") endif() endif() - set(lipo_target "${name}-${SWIFT_SDK_${sdk}_LIB_SUBDIR}") + set(lipo_target "${name}-${library_subdir}") if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin" AND SWIFTLIB_SHARED) set(codesign_arg CODESIGN) endif() @@ -2111,13 +2355,17 @@ function(add_swift_target_library name) ${THIN_INPUT_TARGETS}) # Cache universal libraries for dependency purposes - set(UNIVERSAL_LIBRARY_NAMES_${SWIFT_SDK_${sdk}_LIB_SUBDIR} - ${UNIVERSAL_LIBRARY_NAMES_${SWIFT_SDK_${sdk}_LIB_SUBDIR}} + set(UNIVERSAL_LIBRARY_NAMES_${library_subdir} + ${UNIVERSAL_LIBRARY_NAMES_${library_subdir}} ${lipo_target} - CACHE INTERNAL "UNIVERSAL_LIBRARY_NAMES_${SWIFT_SDK_${sdk}_LIB_SUBDIR}") + CACHE INTERNAL "UNIVERSAL_LIBRARY_NAMES_${library_subdir}") # Determine the subdirectory where this library will be installed. set(resource_dir_sdk_subdir "${SWIFT_SDK_${sdk}_LIB_SUBDIR}") + if(maccatalyst_build_flavor STREQUAL "ios-like") + set(resource_dir_sdk_subdir "${SWIFT_SDK_MACCATALYST_LIB_SUBDIR}") + endif() + precondition(resource_dir_sdk_subdir) if(SWIFTLIB_SHARED OR SWIFTLIB_INSTALL_WITH_SHARED) @@ -2183,6 +2431,10 @@ function(add_swift_target_library name) # Add the arch-specific library targets to the global exports. foreach(arch ${SWIFT_SDK_${sdk}_ARCHITECTURES}) set(_variant_name "${name}-${SWIFT_SDK_${sdk}_LIB_SUBDIR}-${arch}") + if(maccatalyst_build_flavor STREQUAL "ios-like") + set(_variant_name "${name}-${SWIFT_SDK_MACCATALYST_LIB_SUBDIR}-${arch}") + endif() + if(NOT TARGET "${_variant_name}") continue() endif() @@ -2199,6 +2451,10 @@ function(add_swift_target_library name) # Add the swiftmodule-only targets to the lipo target depdencies. foreach(arch ${SWIFT_SDK_${sdk}_MODULE_ARCHITECTURES}) set(_variant_name "${name}-${SWIFT_SDK_${sdk}_LIB_SUBDIR}-${arch}") + if(maccatalyst_build_flavor STREQUAL "ios-like") + set(_variant_name "${name}-${SWIFT_SDK_MACCATALYST_LIB_SUBDIR}-${arch}") + endif() + if(NOT TARGET "${_variant_name}") continue() endif() @@ -2224,9 +2480,9 @@ function(add_swift_target_library name) endif() set(lipo_target_static - "${name}-${SWIFT_SDK_${sdk}_LIB_SUBDIR}-static") + "${name}-${library_subdir}-static") set(UNIVERSAL_LIBRARY_NAME - "${universal_subdir}/${SWIFT_SDK_${sdk}_LIB_SUBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${name}${CMAKE_STATIC_LIBRARY_SUFFIX}") + "${universal_subdir}/${library_subdir}/${CMAKE_STATIC_LIBRARY_PREFIX}${name}${CMAKE_STATIC_LIBRARY_SUFFIX}") _add_swift_lipo_target(SDK ${sdk} TARGET @@ -2266,6 +2522,7 @@ function(add_swift_target_library name) endif() endforeach() endif() + endforeach() # maccatalyst_build_flavors endforeach() endfunction() diff --git a/cmake/modules/StandaloneOverlay.cmake b/cmake/modules/StandaloneOverlay.cmake index 5a886c931e94e..ed089097b8d19 100644 --- a/cmake/modules/StandaloneOverlay.cmake +++ b/cmake/modules/StandaloneOverlay.cmake @@ -93,6 +93,12 @@ set(SWIFT_BUILD_STANDALONE_OVERLAY TRUE) set(SWIFT_STDLIB_LIBRARY_BUILD_TYPES "SHARED") set(SWIFT_SDK_OVERLAY_LIBRARY_BUILD_TYPES "SHARED") +option(SWIFT_ENABLE_MACCATALYST + "Build the overlays with macCatalyst support" + FALSE) + +set(SWIFT_DARWIN_DEPLOYMENT_VERSION_MACCATALYST "13.0" CACHE STRING + "Minimum deployment target version for macCatalyst") # ----------------------------------------------------------------------------- diff --git a/cmake/modules/SwiftConfigureSDK.cmake b/cmake/modules/SwiftConfigureSDK.cmake index 3a87bfcd80bb2..52a3a4f3aeb0c 100644 --- a/cmake/modules/SwiftConfigureSDK.cmake +++ b/cmake/modules/SwiftConfigureSDK.cmake @@ -133,7 +133,7 @@ macro(configure_sdk_darwin endif() if(NOT EXISTS "${SWIFT_SDK_${prefix}_PATH}/System/Library/Frameworks/module.map") - message(FATAL_ERROR "${name} SDK not found at ${SWIFT_SDK_${prefix}_PATH}.") + message(FATAL_ERROR "${name} SDK not found at SWIFT_SDK_${prefix}_PATH.") endif() # Determine the SDK version we found. @@ -183,6 +183,20 @@ macro(configure_sdk_darwin set(SWIFT_SDK_${prefix}_ARCH_${arch}_TRIPLE "${arch}-apple-${SWIFT_SDK_${prefix}_TRIPLE_NAME}") + + if(SWIFT_ENABLE_MACCATALYST AND "${prefix}" STREQUAL "OSX") + # For macCatalyst append the '-macabi' environment to the target triple. + set(SWIFT_SDK_MACCATALYST_ARCH_${arch}_TRIPLE + "${SWIFT_SDK_${prefix}_ARCH_${arch}_TRIPLE}-macabi") + + # macCatalyst triple + set(SWIFT_MACCATALYST_TRIPLE + "x86_64-apple-ios${SWIFT_DARWIN_DEPLOYMENT_VERSION_MACCATALYST}-macabi") + + # For macCatalyst, the xcrun_name is "macosx" since it uses that sdk. + # Hard code the library subdirectory to "maccatalyst" in that case. + set(SWIFT_SDK_MACCATALYST_LIB_SUBDIR "maccatalyst") + endif() endforeach() # Add this to the list of known SDKs. diff --git a/cmake/modules/SwiftSource.cmake b/cmake/modules/SwiftSource.cmake index 25314d3e627d3..818a03c1e46cc 100644 --- a/cmake/modules/SwiftSource.cmake +++ b/cmake/modules/SwiftSource.cmake @@ -1,3 +1,4 @@ +include(macCatalystUtils) include(SwiftUtils) # Process the sources within the given variable, pulling out any Swift @@ -7,6 +8,9 @@ include(SwiftUtils) # # Usage: # handle_swift_sources(sourcesvar externalvar) +# +# MACCATALYST_BUILD_FLAVOR +# Possible values are 'ios-like', 'macos-like', 'zippered', 'unzippered-twin' function(handle_swift_sources dependency_target_out_var_name dependency_module_target_out_var_name @@ -16,7 +20,7 @@ function(handle_swift_sources sourcesvar externalvar name) cmake_parse_arguments(SWIFTSOURCES "IS_MAIN;IS_STDLIB;IS_STDLIB_CORE;IS_SDK_OVERLAY;EMBED_BITCODE" - "SDK;ARCHITECTURE;INSTALL_IN_COMPONENT" + "SDK;ARCHITECTURE;INSTALL_IN_COMPONENT;MACCATALYST_BUILD_FLAVOR" "DEPENDS;COMPILE_FLAGS;MODULE_NAME" ${ARGN}) translate_flag(${SWIFTSOURCES_IS_MAIN} "IS_MAIN" IS_MAIN_arg) @@ -63,6 +67,12 @@ function(handle_swift_sources if(swift_sources) set(objsubdir "/${SWIFTSOURCES_SDK}/${SWIFTSOURCES_ARCHITECTURE}") + get_maccatalyst_build_flavor(maccatalyst_build_flavor + "${SWIFTSOURCES_SDK}" "${SWIFTSOURCES_MACCATALYST_BUILD_FLAVOR}") + if(maccatalyst_build_flavor STREQUAL "ios-like") + set(objsubdir "/MACCATALYST/${SWIFTSOURCES_ARCHITECTURE}") + endif() + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}${objsubdir}") set(swift_obj @@ -91,7 +101,8 @@ function(handle_swift_sources ${IS_SDK_OVERLAY_arg} ${EMBED_BITCODE_arg} ${STATIC_arg} - INSTALL_IN_COMPONENT "${SWIFTSOURCES_INSTALL_IN_COMPONENT}") + INSTALL_IN_COMPONENT "${SWIFTSOURCES_INSTALL_IN_COMPONENT}" + MACCATALYST_BUILD_FLAVOR "${SWIFTSOURCES_MACCATALYST_BUILD_FLAVOR}") set("${dependency_target_out_var_name}" "${dependency_target}" PARENT_SCOPE) set("${dependency_module_target_out_var_name}" "${module_dependency_target}" PARENT_SCOPE) set("${dependency_sib_target_out_var_name}" "${sib_dependency_target}" PARENT_SCOPE) @@ -131,6 +142,7 @@ endfunction() # OUTPUT objfile # Name of the resulting object file # SOURCES swift_src [swift_src...] # Swift source files to compile # FLAGS -module-name foo # Flags to add to the compilation +# MACCATALYST_BUILD_FLAVOR flavor # macCatalyst flavor # [SDK sdk] # SDK to build for # [ARCHITECTURE architecture] # Architecture to build for # [DEPENDS cmake_target...] # CMake targets on which the object @@ -151,7 +163,7 @@ function(_compile_swift_files dependency_sibgen_target_out_var_name) cmake_parse_arguments(SWIFTFILE "IS_MAIN;IS_STDLIB;IS_STDLIB_CORE;IS_SDK_OVERLAY;EMBED_BITCODE" - "OUTPUT;MODULE_NAME;INSTALL_IN_COMPONENT" + "OUTPUT;MODULE_NAME;INSTALL_IN_COMPONENT;MACCATALYST_BUILD_FLAVOR" "SOURCES;FLAGS;DEPENDS;SDK;ARCHITECTURE;OPT_FLAGS;MODULE_DIR" ${ARGN}) @@ -175,6 +187,27 @@ function(_compile_swift_files precondition(SWIFTFILE_ARCHITECTURE MESSAGE "Should specify an architecture") precondition(SWIFTFILE_INSTALL_IN_COMPONENT MESSAGE "INSTALL_IN_COMPONENT is required") + # Determine if/what macCatalyst build variant we are + get_maccatalyst_build_flavor(maccatalyst_build_flavor + "${SWIFTFILE_SDK}" "${SWIFTFILE_MACCATALYST_BUILD_FLAVOR}") + + # Determine target triples + get_target_triple(target_triple ignored_target_variant_triple + "${SWIFTFILE_SDK}" + "${SWIFTFILE_ARCHITECTURE}" + DEPLOYMENT_VERSION "${SWIFT_SDK_${SWIFTFILE_SDK}_DEPLOYMENT_VERSION}") + + get_target_triple(maccatalyst_target_triple ignored_target_variant_triple + "${SWIFTFILE_SDK}" + "${SWIFTFILE_ARCHITECTURE}" + DEPLOYMENT_VERSION "${SWIFT_SDK_${SWIFTFILE_SDK}_DEPLOYMENT_VERSION}" + MACCATALYST_BUILD_FLAVOR "${maccatalyst_build_flavor}") + + # macCatalyst ios-like target triple + if(maccatalyst_build_flavor STREQUAL "ios-like") + set(target_triple "${maccatalyst_target_triple}") + endif() + if ("${SWIFTFILE_MODULE_NAME}" STREQUAL "") get_filename_component(SWIFTFILE_MODULE_NAME "${first_output}" NAME_WE) message(SEND_ERROR @@ -202,17 +235,18 @@ function(_compile_swift_files "${SWIFTFILE_ARCHITECTURE}" "${SWIFT_STDLIB_BUILD_TYPE}" "${SWIFT_STDLIB_ASSERTIONS}" - swift_flags) + swift_flags + MACCATALYST_BUILD_FLAVOR "${maccatalyst_build_flavor}" + ) # Determine the subdirectory where the binary should be placed. compute_library_subdir(library_subdir "${SWIFTFILE_SDK}" "${SWIFTFILE_ARCHITECTURE}") - # Allow import of other Swift modules we just built. - list(APPEND swift_flags - "-I" "${SWIFTLIB_DIR}/${library_subdir}") - # FIXME: should we use '-resource-dir' here? Seems like it has no advantage - # over '-I' in this case. + if(maccatalyst_build_flavor STREQUAL "ios-like") + compute_library_subdir(library_subdir + "MACCATALYST" "${SWIFTFILE_ARCHITECTURE}") + endif() # If we have a custom module cache path, use it. if (SWIFT_MODULE_CACHE_PATH) @@ -308,7 +342,8 @@ function(_compile_swift_files list(APPEND swift_flags "-parse-as-library") set(module_base "${module_dir}/${SWIFTFILE_MODULE_NAME}") - if(SWIFTFILE_SDK IN_LIST SWIFT_APPLE_PLATFORMS) + if(SWIFTFILE_SDK IN_LIST SWIFT_APPLE_PLATFORMS OR + SWIFTFILE_SDK STREQUAL "MACCATALYST") set(specific_module_dir "${module_base}.swiftmodule") set(specific_module_project_dir "${specific_module_dir}/Project") set(source_info_file "${specific_module_project_dir}/${SWIFTFILE_ARCHITECTURE}.swiftsourceinfo") @@ -338,6 +373,57 @@ function(_compile_swift_files "-Xfrontend" "-experimental-skip-non-inlinable-function-bodies") endif() + set(module_outputs "${module_file}" "${module_doc_file}") + + if(interface_file) + list(APPEND module_outputs "${interface_file}") + endif() + + set(optional_arg) + if(SWIFTFILE_SDK IN_LIST SWIFT_APPLE_PLATFORMS OR + SWIFTFILE_SDK STREQUAL "MACCATALYST") + # Allow installation of stdlib without building all variants on Darwin. + set(optional_arg "OPTIONAL") + endif() + + if(SWIFTFILE_SDK IN_LIST SWIFT_APPLE_PLATFORMS OR + SWIFTFILE_SDK STREQUAL "MACCATALYST") + swift_install_in_component(DIRECTORY "${specific_module_dir}" + DESTINATION "lib${LLVM_LIBDIR_SUFFIX}/swift/${library_subdir}" + COMPONENT "${SWIFTFILE_INSTALL_IN_COMPONENT}") + else() + swift_install_in_component(FILES ${module_outputs} + DESTINATION "lib${LLVM_LIBDIR_SUFFIX}/swift/${library_subdir}" + COMPONENT "${SWIFTFILE_INSTALL_IN_COMPONENT}") + endif() + + # macCatalyst zippered module setup + if(maccatalyst_build_flavor STREQUAL "zippered") + compute_library_subdir(maccatalyst_library_subdir + "MACCATALYST" "${SWIFTFILE_ARCHITECTURE}") + + if(SWIFTFILE_MODULE_DIR) + set(maccatalyst_module_dir "${SWIFTFILE_MODULE_DIR}") + elseif(SWIFTFILE_IS_STDLIB) + set(maccatalyst_module_dir "${SWIFTLIB_DIR}/${maccatalyst_library_subdir}") + else() + message(FATAL_ERROR "Don't know where to put the module files") + endif() + + set(maccatalyst_specific_module_dir + "${maccatalyst_module_dir}/${SWIFTFILE_MODULE_NAME}.swiftmodule") + set(maccatalyst_module_base "${maccatalyst_specific_module_dir}/${SWIFTFILE_ARCHITECTURE}") + set(maccatalyst_module_file "${maccatalyst_module_base}.swiftmodule") + set(maccatalyst_module_doc_file "${maccatalyst_module_base}.swiftdoc") + + set(maccatalyst_module_outputs "${maccatalyst_module_file}" "${maccatalyst_module_doc_file}") + + swift_install_in_component(DIRECTORY ${maccatalyst_specific_module_dir} + DESTINATION "lib${LLVM_LIBDIR_SUFFIX}/swift/${maccatalyst_library_subdir}" + COMPONENT "${SWIFTFILE_INSTALL_IN_COMPONENT}" + "${optional_arg}") + endif() + # If we have extra regexp flags, check if we match any of the regexps. If so # add the relevant flags to our swift_flags. if (SWIFT_EXPERIMENTAL_EXTRA_REGEXP_FLAGS OR SWIFT_EXPERIMENTAL_EXTRA_NEGATIVE_REGEXP_FLAGS) @@ -401,6 +487,26 @@ function(_compile_swift_files set(sibopt_outputs "${sibopt_file}") set(sibgen_outputs "${sibgen_file}") + # macCatalyst zippered swiftmodule + if(maccatalyst_build_flavor STREQUAL "zippered") + set(maccatalyst_swift_flags "${swift_flags}") + list(APPEND maccatalyst_swift_flags + "-I" "${SWIFTLIB_DIR}/${maccatalyst_library_subdir}") + set(maccatalyst_swift_module_flags ${swift_module_flags}) + elseif(maccatalyst_build_flavor STREQUAL "ios-like") + compute_library_subdir(maccatalyst_library_subdir + "MACCATALYST" "${SWIFTFILE_ARCHITECTURE}") + list(APPEND swift_flags + "-I" "${SWIFTLIB_DIR}/${maccatalyst_library_subdir}") + else() + # Allow import of other Swift modules we just built. + list(APPEND swift_flags + "-I" "${SWIFTLIB_DIR}/${library_subdir}") + + # FIXME: should we use '-resource-dir' here? Seems like it has no advantage + # over '-I' in this case. + endif() + if(XCODE) # HACK: work around an issue with CMake Xcode generator and the Swift # driver. @@ -424,6 +530,12 @@ function(_compile_swift_files COMMAND "${CMAKE_COMMAND}" -E touch ${sibopt_outputs}) set(command_touch_sibgen_outputs COMMAND "${CMAKE_COMMAND}" -E touch ${sibgen_outputs}) + + # macCatalyst zippered outputs + if(maccatalyst_build_flavor STREQUAL "zippered") + set(command_touch_maccatalyst_module_outputs + COMMAND "${CMAKE_COMMAND}" -E touch ${maccatalyst_module_outputs}) + endif() endif() # First generate the obj dirs @@ -516,6 +628,49 @@ function(_compile_swift_files COMMENT "Generating ${module_file}") set("${dependency_module_target_out_var_name}" "${module_dependency_target}" PARENT_SCOPE) + # macCatalyst zippered swiftmodule + if(maccatalyst_build_flavor STREQUAL "zippered") + get_target_triple(ios_like_target_triple ignored_target_variant + "${SWIFTFILE_SDK}" + "${SWIFTFILE_ARCHITECTURE}" + MACCATALYST_BUILD_FLAVOR "ios-like") + + # Remove previous -target and -target-variant flags from + # the zippered Swift flags and add an ios-like target. + remove_given_flag(maccatalyst_swift_flags "target") + remove_given_flag(maccatalyst_swift_flags "target-variant") + list(APPEND maccatalyst_swift_flags + "-target" "${ios_like_target_triple}") + + add_custom_command_target( + maccatalyst_module_dependency_target + COMMAND + "${CMAKE_COMMAND}" "-E" "remove" "-f" ${maccatalyst_module_outputs} + COMMAND + "${CMAKE_COMMAND}" "-E" "make_directory" ${maccatalyst_specific_module_dir} + COMMAND + "${PYTHON_EXECUTABLE}" "${line_directive_tool}" "@${file_path}" -- + "${swift_compiler_tool}" "-emit-module" "-o" "${maccatalyst_module_file}" + ${maccatalyst_swift_flags} ${maccatalyst_swift_module_flags} "@${file_path}" + ${command_touch_maccatalyst_module_outputs} + OUTPUT + ${maccatalyst_module_outputs} + DEPENDS + ${swift_compiler_tool_dep} + ${source_files} + ${SWIFTFILE_DEPENDS} + ${swift_ide_test_dependency} + ${obj_dirs_dependency_target} + COMMENT + "Generating ${maccatalyst_module_file}") + + # Piggy-back on the same out-var as the regular swiftmodule + set("${dependency_module_target_out_var_name}" + "${module_dependency_target}" + "${maccatalyst_module_dependency_target}" + PARENT_SCOPE) + endif() + # This is the target to generate the .sib files. It is not built by default. add_custom_command_target( sib_dependency_target diff --git a/cmake/modules/macCatalystUtils.cmake b/cmake/modules/macCatalystUtils.cmake new file mode 100644 index 0000000000000..d30177bc8682d --- /dev/null +++ b/cmake/modules/macCatalystUtils.cmake @@ -0,0 +1,100 @@ +# macCatalystUtils.cmake +# +# Utility functions for macCatalyst support in Swift. + + +# Include guard +if(MACCATALYST_UTILS_INCLUDED) + return() +endif() + +set(MACCATALYST_UTILS_INCLUDED TRUE) + + +# ----------------------------------------------------------------------------- + +# List of all valid macCatalyst build flavors +set(MACCATALYST_BUILD_FLAVORS "ios-like" "macos-like" "zippered" "unzippered-twin") + + +# Sets out_var with the macCatalyst build flavor if macCatalyst is enabled and building +# for the OSX sdk. +function(get_maccatalyst_build_flavor out_var sdk flavor) + if(SWIFT_ENABLE_MACCATALYST AND sdk STREQUAL "OSX") + if(flavor IN_LIST MACCATALYST_BUILD_FLAVORS) + set("${out_var}" "${flavor}" PARENT_SCOPE) + elseif(NOT flavor STREQUAL "") + message(FATAL_ERROR "Invalid MACCATALYST_BUILD_FLAVOR: ${flavor}") + else() + # Unset the variable to indicate the absence of a build flavor + unset("${out_var}" PARENT_SCOPE) + endif() + else() + # Unset the variable to indicate macCatalyst is not enabled + unset("${out_var}" PARENT_SCOPE) + endif() +endfunction() + + +# Sets target_out_var to the target triple for the given SDK and maccatalyst flavor. +# For zippered flavors also sets the target_variant_out_var. For other +# flavors the target_variant_out_var is unset, causing it to be undefined. +function(get_target_triple target_out_var target_variant_out_var sdk arch) + # parse args + set(option_args) + set(single_value_args MACCATALYST_BUILD_FLAVOR DEPLOYMENT_VERSION) + set(multi_value_args) + cmake_parse_arguments(TARGET + "${option_args}" + "${single_value_args}" + "${multi_value_args}" + ${ARGN}) + + set(deployment_version "${TARGET_DEPLOYMENT_VERSION}") + + # Default target triple + set(target "${SWIFT_SDK_${sdk}_ARCH_${arch}_TRIPLE}${deployment_version}") + set(target_variant) + + get_maccatalyst_build_flavor(maccatalyst_build_flavor + "${sdk}" "${TARGET_MACCATALYST_BUILD_FLAVOR}") + + if(maccatalyst_build_flavor STREQUAL "ios-like") + set(target "${arch}-apple-ios${SWIFT_DARWIN_DEPLOYMENT_VERSION_MACCATALYST}-macabi") + elseif(maccatalyst_build_flavor STREQUAL "macos-like") + # Use the default macOS triple. + elseif(maccatalyst_build_flavor STREQUAL "zippered") + set(target "${arch}-apple-macosx${SWIFT_DARWIN_DEPLOYMENT_VERSION_OSX}") + set(target_variant "${arch}-apple-ios${SWIFT_DARWIN_DEPLOYMENT_VERSION_MACCATALYST}-macabi") + elseif(maccatalyst_build_flavor STREQUAL "unzippered-twin") + # Use the default triple for now + endif() + + set(${target_out_var} "${target}" PARENT_SCOPE) + set(${target_variant_out_var} "${target_variant}" PARENT_SCOPE) +endfunction() + + +# Removes all instances of `-${flag} ` from an input list of flags +function(remove_given_flag flags_var flag_name) + set(output_flags) + + set(seen_flag FALSE) + foreach(flag ${${flags_var}}) + # Skip flag argument + if(seen_flag) + set(seen_flag FALSE) + continue() + endif() + + # Skip flag + if(flag STREQUAL "-${flag_name}") + set(seen_flag TRUE) + continue() + endif() + + list(APPEND output_flags "${flag}") + endforeach() + + set("${flags_var}" "${output_flags}" PARENT_SCOPE) +endfunction() diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt index 958bbd290a18d..7b0c16cc9245e 100644 --- a/stdlib/public/runtime/CMakeLists.txt +++ b/stdlib/public/runtime/CMakeLists.txt @@ -187,6 +187,7 @@ foreach(sdk ${SWIFT_CONFIGURED_SDKS}) endif() endforeach() + add_swift_target_library(swiftImageRegistrationObjectELF OBJECT_LIBRARY IS_STDLIB IS_STDLIB_CORE SwiftRT-ELF.cpp diff --git a/utils/build-script b/utils/build-script index 689355d07171d..5fffcd77b352b 100755 --- a/utils/build-script +++ b/utils/build-script @@ -596,6 +596,10 @@ class BuildScriptInvocation(object): "--extra-swift-args=%s" % ';'.join(args.extra_swift_args) ] + # Enable macCatalyst + if args.maccatalyst: + args.extra_cmake_options.append('-DSWIFT_ENABLE_MACCATALYST:BOOL=TRUE') + # If we have extra_cmake_options, combine all of them together and then # add them as one command. if args.extra_cmake_options: diff --git a/utils/build-script-impl b/utils/build-script-impl index c54e470557ebf..7ba978bc715c5 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -147,6 +147,7 @@ KNOWN_SETTINGS=( skip-build-llbuild "" "set to skip building llbuild" skip-build-lldb "" "set to skip building LLDB" skip-build-llvm "" "set to skip building LLVM/Clang" + skip-build-maccatalyst "" "set to skip building Swift stdlibs for macCatalyst" skip-build-osx "" "set to skip building Swift stdlibs for OS X" skip-build-playgroundsupport "" "set to skip building PlaygroundSupport" skip-build-static-foundation "" "set to skip building static Foundation" diff --git a/utils/build_swift/build_swift/driver_arguments.py b/utils/build_swift/build_swift/driver_arguments.py index e6cb284d27187..9f432a0150509 100644 --- a/utils/build_swift/build_swift/driver_arguments.py +++ b/utils/build_swift/build_swift/driver_arguments.py @@ -335,6 +335,9 @@ def create_argument_parser(): option('--skip-watchos', store_false('watchos'), help='set to skip everything watchOS-related') + option('--maccatalyst', toggle_true, + help='Enable building Swift with macCatalyst support') + option('--android', toggle_true, help='also build for Android') diff --git a/utils/build_swift/tests/expected_options.py b/utils/build_swift/tests/expected_options.py index cb7f87f061d75..f91a9c21a13da 100644 --- a/utils/build_swift/tests/expected_options.py +++ b/utils/build_swift/tests/expected_options.py @@ -172,6 +172,8 @@ 'tsan_libdispatch_test': False, 'long_test': False, 'lto_type': None, + 'maccatalyst': False, + 'maccatalyst_ios_tests': False, 'dump_config': False, 'show_sdks': False, 'skip_build': False, @@ -441,6 +443,8 @@ class BuildScriptImplOption(_BaseOption): SetTrueOption('--llbuild', dest='build_llbuild'), SetTrueOption('--lldb', dest='build_lldb'), SetTrueOption('--libcxx', dest='build_libcxx'), + SetTrueOption('--maccatalyst', dest='maccatalyst'), + SetTrueOption('--maccatalyst-ios-tests', dest='maccatalyst_ios_tests'), SetTrueOption('--playgroundsupport', dest='build_playgroundsupport'), SetTrueOption('--skip-build'), SetTrueOption('--swiftpm', dest='build_swiftpm'), diff --git a/utils/swift_build_support/tests/test_host_specific_configuration.py b/utils/swift_build_support/tests/test_host_specific_configuration.py index 136b8cc8a4fdc..5b8a6dd5f9e8c 100644 --- a/utils/swift_build_support/tests/test_host_specific_configuration.py +++ b/utils/swift_build_support/tests/test_host_specific_configuration.py @@ -616,6 +616,8 @@ def default_args(self): build_tvos_simulator=False, build_watchos_device=False, build_watchos_simulator=False, + maccatalyst=False, + maccatalyst_ios_tests=False, long_test=False, only_executable_test=False, stress_test=False, From 89e381ca664a5fd93ab04d7eeb82015374a3e6f1 Mon Sep 17 00:00:00 2001 From: Devin Coughlin Date: Sun, 5 Jan 2020 21:25:57 -0800 Subject: [PATCH 2/6] [CMake/Tests] CMake and lit.cfg support for running macCatalyst tests Add support for testing with macCatalyst to lit.cfg and the test CMake. This adds lit test features for whether the standard library and runtime was built with macCatalyst support: REQUIRES: maccatalyst_support The test suite can also be run in two modes: one where the macOS tests are run as usual (against a zippered standard library, runtime, and overlays) and another where iOS tests are compiled with the macCatalyst target triple and executed as macCatalyst processes. The iOS tests for macCatalyst can be run by passing `--maccatalyst-ios-tests` to build-script. There are new lit test features to enable a test to specify whether it supports that environment: REQUIRES: OS=maccatalyst UNSUPPORTED: OS=macCatalyst --- test/CMakeLists.txt | 32 ++++++- test/lit.cfg | 96 +++++++++++++++++-- test/lit.site.cfg.in | 7 ++ utils/build-script | 2 + utils/build-script-impl | 1 + .../build_swift/driver_arguments.py | 3 + .../host_specific_configuration.py | 11 ++- 7 files changed, 138 insertions(+), 14 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a6a06dfea4e24..796b9bf1da4cb 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -163,10 +163,28 @@ endif() foreach(SDK ${SWIFT_SDKS}) foreach(ARCH ${SWIFT_SDK_${SDK}_ARCHITECTURES}) + # macCatalyst needs to run two sets of tests: one with the normal macosx target triple + # and one with the the macCatalyst ios-macabi triple. The build_flavors list will + # have have only the "default" flavor for all SDKs and architectures except + # OSX when macCatalyst support is enabled. + set(build_flavors "default") + if(SWIFT_ENABLE_MACCATALYST AND "${SDK}" STREQUAL "OSX") + list(APPEND build_flavors "ios-like" ) + endif() + + foreach(BUILD_FLAVOR ${build_flavors}) # Configure variables for this subdirectory. set(VARIANT_SUFFIX "-${SWIFT_SDK_${SDK}_LIB_SUBDIR}-${ARCH}") set(VARIANT_TRIPLE "${SWIFT_SDK_${SDK}_ARCH_${ARCH}_TRIPLE}${SWIFT_SDK_${SDK}_DEPLOYMENT_VERSION}") set(VARIANT_SDK "${SWIFT_SDK_${SDK}_ARCH_${ARCH}_PATH}") + set(DEFAULT_OSX_VARIANT_SUFFIX "") + + if(BUILD_FLAVOR STREQUAL "ios-like") + set(DEFAULT_OSX_VARIANT_SUFFIX "${VARIANT_SUFFIX}") + # Use the macCatalyst target triple and compiler resources for the iOS-like build flavor. + set(VARIANT_SUFFIX "-${SWIFT_SDK_${SDK}_LIB_SUBDIR}-maccatalyst-${ARCH}") + set(VARIANT_TRIPLE "${ARCH}-apple-ios13.0-macabi") + endif() # A directory where to put the xUnit-style XML test results. set(SWIFT_TEST_RESULTS_DIR @@ -232,8 +250,17 @@ _Block_release(void) { }\n") if(SWIFT_BUILD_STDLIB AND SWIFT_INCLUDE_TESTS) list(APPEND test_dependencies "swift-test-stdlib-${SWIFT_SDK_${SDK}_LIB_SUBDIR}") - list(APPEND test_dependencies - "swift-reflection-test${VARIANT_SUFFIX}_signed") + + if(BUILD_FLAVOR STREQUAL "ios-like") + # When testing the iOS-like build flavor, use the the normal macOS + # swift-reflection-test-tool. That tool runs out of process so it + # doesn't need to be build for macCatalyst. + list(APPEND test_dependencies + "swift-reflection-test${DEFAULT_OSX_VARIANT_SUFFIX}") + else() + list(APPEND test_dependencies + "swift-reflection-test${VARIANT_SUFFIX}_signed") + endif() endif() if(NOT "${COVERAGE_DB}" STREQUAL "") @@ -391,6 +418,7 @@ _Block_release(void) { }\n") endforeach() endforeach() endforeach() + endforeach() endforeach() # Add shortcuts for the default variant. diff --git a/test/lit.cfg b/test/lit.cfg index 4ee12fa1e9f31..94394c3ba1830 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -319,6 +319,10 @@ lit_config.note('Using resource dir: ' + test_resource_dir) # Parse the variant triple. (run_cpu, run_vendor, run_os, run_vers) = re.match('([^-]+)-([^-]+)-([^0-9]+)(.*)', config.variant_triple).groups() +if run_os == 'ios' and run_vers.endswith('-macabi'): + run_vers = run_vers[0:-len('-macabi')] + run_os = 'maccatalyst' + run_ptrsize = '64' if ('64' in run_cpu or run_cpu == "s390x") else '32' run_endian = 'little' if run_cpu != 's390x' else 'big' @@ -602,7 +606,12 @@ if config.benchmark_o != 'Benchmark_O': config.substitutions.append(('%target-triple', config.variant_triple)) if run_vendor == 'apple': - if True: + if run_os == 'maccatalyst': + config.stable_abi_triple = '%s-%s-ios13.0-macabi' % (run_cpu, run_vendor) + config.pre_stable_abi_triple = config.stable_abi_triple + config.next_stable_abi_triple = config.stable_abi_triple + config.available_features.add('swift_stable_abi') + else: # iOS 12.2 does not support 32-bit targets, so we cannot run tests that # want to deploy to an iOS that has Swift in the OS. if run_os == 'ios' and run_ptrsize == '32': @@ -612,6 +621,7 @@ if run_vendor == 'apple': PRE_STABLE_VERSION = { 'macosx': '10.14.3', 'ios': '12.1', + 'maccatalyst': '12.1', 'tvos': '12.1', 'watchos': '5.1' } @@ -622,6 +632,7 @@ if run_vendor == 'apple': STABLE_VERSION = { 'macosx': '10.14.4', 'ios': '12.2', + 'maccatalyst': '12.2', 'tvos': '12.2', 'watchos': '5.2' } @@ -632,6 +643,7 @@ if run_vendor == 'apple': NEXT_STABLE_VERSION = { 'macosx': '10.15', 'ios': '13', + 'maccatalyst': '13', 'tvos': '13', 'watchos': '6' } @@ -668,6 +680,17 @@ config.substitutions.append(('%sanitizers-target-triple', config.variant_triple.replace("ios7", "ios8"))) config.substitutions.append(('%target-cpu', run_cpu)) + +target_os_abi = run_os +target_os_is_maccatalyst = "FALSE" +if (run_os == 'maccatalyst'): + # For purposes of ABI, treat maccatalyst as macosx since the maccatalyst ABI + # must match the macosx ABI. + target_os_abi = 'macosx' + target_os_is_maccatalyst = "TRUE" + config.available_features.add("OS=ios") +config.substitutions.append(('%target-os-abi', target_os_abi)) +config.substitutions.append(('%target-os-is-maccatalyst', target_os_is_maccatalyst)) config.substitutions.append(('%target-endian', run_endian)) config.substitutions.append(('%target-os', run_os)) config.substitutions.append(('%target-ptrsize', run_ptrsize)) @@ -703,7 +726,12 @@ if 'swift_interpreter' in config.available_features: config.target_runtime = "unknown" -swift_reflection_test_name = 'swift-reflection-test' + config.variant_suffix +if (getattr(config, 'darwin_enable_maccatalyst', False) and + config.darwin_maccatalyst_build_flavor == "ios-like"): + variant_suffix = config.darwin_osx_variant_suffix +else: + variant_suffix = config.variant_suffix +swift_reflection_test_name = 'swift-reflection-test' + variant_suffix def use_interpreter_for_simple_runs(): def make_simple_target_run(gyb=False, stdlib=False, parameterized=False): @@ -858,25 +886,49 @@ if run_vendor == 'apple': lit_config.fatal('Could not get or decode sw_vers output. ' + 'Perhaps the simulator is not working.') - elif run_os == 'macosx': + elif run_os == 'macosx' or run_os == 'maccatalyst': # OS X lit_config.note("Testing OS X " + config.variant_triple) xcrun_sdk_name = "macosx" - config.target_cc_options = ( - "-arch %s -m%s-version-min=%s %s" % - (run_cpu, run_os, run_vers, clang_mcp_opt)) + + if run_os == 'maccatalyst': + # For maccatalyst, pass the target triple to clang + # rather than arch and version separately. + config.target_cc_options = ( + "-target %s %s" % + (config.variant_triple, clang_mcp_opt)) + else: + config.target_cc_options = ( + "-arch %s -m%s-version-min=%s %s" % + (run_cpu, run_os, run_vers, clang_mcp_opt)) + + maccatalyst_frameworks_component = "" + if run_os == 'maccatalyst': + # Additional framework search paths for macCatalyst. + # These have to come before other search paths so that for + # unzippered twin frameworks the unzippered twin version + # is favored under macCatalyst. + maccatalyst_frameworks_dir = make_path(config.variant_sdk, + "System", "iOSSupport", "System", "Library", "Frameworks") + maccatalyst_frameworks_component = ( "-F %r" % maccatalyst_frameworks_dir ) + # Module triples end in ios-macabi. + target_specific_module_triple = '{}-apple-ios-macabi'.format( + { 'aarch64': 'arm64', 'amd64': 'x86_64' }.get(run_cpu, run_cpu) + ) config.target_build_swift = ( - ("%s %s %s -F %r -toolchain-stdlib-rpath " + ("%s %s %s %s -F %r -toolchain-stdlib-rpath " + "-Xlinker -rpath -Xlinker %r %s %s %s %s " + "-F %r -Xlinker -rpath -Xlinker %r") % (xcrun_prefix, config.swiftc, target_options, + maccatalyst_frameworks_component, extra_frameworks_dir, extra_frameworks_dir, sdk_overlay_linker_opt, config.swift_test_options, config.swift_driver_test_options, swift_execution_tests_extra_flags, sourcekitd_framework_dir, sourcekitd_framework_dir)) + config.target_run = "" target_future_version = "10.99" @@ -896,9 +948,13 @@ if run_vendor == 'apple': config.target_sdk_name = xcrun_sdk_name config.target_ld = "%s ld -L%r" % (xcrun_prefix, make_path(test_resource_dir, config.target_sdk_name)) + + maccatalyst_extra_frameworks = "" + if run_os == 'maccatalyst': + maccatalyst_extra_frameworks = "-F {}/System/iOSSupport/System/Library/Frameworks".format(config.variant_sdk) config.target_swift_frontend = ( - "%s -frontend %s -sdk %r %s %s" % - (config.swiftc, target_options, config.variant_sdk, + "%s -frontend %s -sdk %r %s %s %s" % + (config.swiftc, target_options, config.variant_sdk, maccatalyst_extra_frameworks, config.swift_test_options, config.swift_frontend_test_options)) subst_target_swift_frontend_mock_sdk = ( "%s -frontend %s -sdk %r %s %s" % @@ -940,6 +996,7 @@ if run_vendor == 'apple': config.target_add_rpath = r'-Xlinker -rpath -Xlinker \1' target_future = format('%s-apple-%s%s' % (run_cpu, run_os, target_future_version)) + config.otool_classic = ("%s otool-classic" % (xcrun_prefix)) elif run_os in ['windows-msvc']: lit_config.note('Testing Windows ' + config.variant_triple) @@ -1480,6 +1537,13 @@ if platform.system() != 'Darwin' or swift_test_mode == 'optimize_none_with_impli platform_module_dir = make_path(test_resource_dir, config.target_sdk_name) if run_vendor != 'apple': platform_module_dir = make_path(platform_module_dir, run_cpu) + +platform_dylib_dir = platform_module_dir +if run_os == 'maccatalyst' and config.darwin_maccatalyst_build_flavor == "ios-like": + # When using the ios-macabi triple, look for module files + # in the 'maccatalyst' compiler resource directory. + platform_module_dir = make_path(test_resource_dir, 'maccatalyst') + lit_config.note('Using platform module dir: ' + platform_module_dir) if test_sdk_overlay_dir: platform_sdk_overlay_dir = test_sdk_overlay_dir @@ -1496,10 +1560,15 @@ if os.path.exists(static_libswiftCore_path): # Set up testing with the standard libraries coming from the OS / just-built libraries # default Swift tests to use the just-built libraries -target_stdlib_path = platform_module_dir +target_stdlib_path = platform_dylib_dir if not kIsWindows: libdispatch_path = getattr(config, 'libdispatch_artifact_dir', '') if 'use_os_stdlib' not in lit_config.params: + if run_os == 'maccatalyst': + # Under macCatalyst we need to have the unzippered twin dylib dir come before + # the zippered/macosx dylib dir so that unzippered twins are picked upload_dylibs + # before the macOS variant. + target_stdlib_path = "{0}:{1}".format(platform_module_dir, target_stdlib_path) lit_config.note('Testing with the just-built libraries at ' + target_stdlib_path) config.target_run = ( "/usr/bin/env " @@ -1513,6 +1582,8 @@ if not kIsWindows: if run_vendor == 'apple': #If we get swift-in-the-OS for non-Apple platforms, add a condition here os_stdlib_path = "/usr/lib/swift" + if run_os == 'maccatalyst': + os_stdlib_path = "/System/iOSSupport/usr/lib/swift:/usr/lib/swift" all_stdlib_path = os.path.pathsep.join((os_stdlib_path, target_stdlib_path)) lit_config.note('Testing with the standard libraries coming from the OS ' + all_stdlib_path) config.target_run = ( @@ -1667,6 +1738,8 @@ config.substitutions.append(('%target-swift-emit-pcm', config.substitutions.insert(0, ('%platform-module-dir', platform_module_dir)) config.substitutions.insert(0, ('%platform-sdk-overlay-dir', platform_sdk_overlay_dir)) +config.substitutions.insert(0, ('%platform-dylib-dir', platform_dylib_dir)) +config.substitutions.insert(0, ('%test-resource-dir', test_resource_dir)) if run_vendor != 'apple': extra_frameworks_dir = '' @@ -1690,6 +1763,9 @@ config.substitutions.append(('%target-resilience-test', config.target_resilience config.substitutions.append(('%llvm-profdata', config.llvm_profdata)) config.substitutions.append(('%llvm-cov', config.llvm_cov)) +if hasattr(config, 'otool_classic'): + config.substitutions.append(('%otool-classic', config.otool_classic)) + config.substitutions.append(('%FileCheck', '%r %r --sanitize BUILD_DIR=%r --sanitize SOURCE_DIR=%r --use-filecheck %r %s' % ( sys.executable, diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in index 69a41da6cc847..69107930747b0 100644 --- a/test/lit.site.cfg.in +++ b/test/lit.site.cfg.in @@ -51,6 +51,10 @@ msvc_runtime_flags = { config.swift_stdlib_msvc_runtime = \ msvc_runtime_flags["@SWIFT_STDLIB_MSVC_RUNTIME_LIBRARY@"] +config.darwin_enable_maccatalyst = "@SWIFT_ENABLE_MACCATALYST@" == "TRUE" +config.darwin_maccatalyst_build_flavor = "@BUILD_FLAVOR@" +config.darwin_osx_variant_suffix = "@DEFAULT_OSX_VARIANT_SUFFIX@" + # Please remember to handle empty strings and/or unset variables correctly. if "@SWIFT_ASAN_BUILD@" == "TRUE": @@ -103,6 +107,9 @@ if "@CMAKE_GENERATOR@" == "Xcode": config.available_features.add("CMAKE_GENERATOR=@CMAKE_GENERATOR@") +if "@SWIFT_ENABLE_MACCATALYST@" == "TRUE": + config.available_features.add('maccatalyst_support') + if "@SWIFT_BUILD_SYNTAXPARSERLIB@" == "TRUE": config.available_features.add('syntax_parser_lib') diff --git a/utils/build-script b/utils/build-script index 5fffcd77b352b..0edc849f72d51 100755 --- a/utils/build-script +++ b/utils/build-script @@ -599,6 +599,8 @@ class BuildScriptInvocation(object): # Enable macCatalyst if args.maccatalyst: args.extra_cmake_options.append('-DSWIFT_ENABLE_MACCATALYST:BOOL=TRUE') + if args.maccatalyst_ios_tests: + impl_args += [ "--darwin-test-maccatalyst-ios-like=1" ] # If we have extra_cmake_options, combine all of them together and then # add them as one command. diff --git a/utils/build-script-impl b/utils/build-script-impl index 7ba978bc715c5..bf7d597106d4a 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -175,6 +175,7 @@ KNOWN_SETTINGS=( skip-test-linux "" "set to skip testing Swift stdlibs for Linux" skip-test-llbuild "" "set to skip testing llbuild" skip-test-lldb "" "set to skip testing lldb" + skip-test-maccatalyst "" "set to skip testing Swift stdlibs for macCatalyst" skip-test-osx "" "set to skip testing Swift stdlibs for OS X" skip-test-playgroundsupport "" "set to skip testing PlaygroundSupport" skip-test-swift "" "set to skip testing Swift" diff --git a/utils/build_swift/build_swift/driver_arguments.py b/utils/build_swift/build_swift/driver_arguments.py index 9f432a0150509..8db50a41513a1 100644 --- a/utils/build_swift/build_swift/driver_arguments.py +++ b/utils/build_swift/build_swift/driver_arguments.py @@ -338,6 +338,9 @@ def create_argument_parser(): option('--maccatalyst', toggle_true, help='Enable building Swift with macCatalyst support') + option('--maccatalyst-ios-tests', toggle_true, + help='When building for macCatalyst run tests with iOS-like target triple') + option('--android', toggle_true, help='also build for Android') diff --git a/utils/swift_build_support/swift_build_support/host_specific_configuration.py b/utils/swift_build_support/swift_build_support/host_specific_configuration.py index e5316b043eff8..9a77818cc3518 100644 --- a/utils/swift_build_support/swift_build_support/host_specific_configuration.py +++ b/utils/swift_build_support/swift_build_support/host_specific_configuration.py @@ -149,8 +149,15 @@ def __init__(self, host_target, args): subset_suffix = "-only_stress" else: subset_suffix = "" - self.swift_test_run_targets.append("check-swift{}{}-{}".format( - subset_suffix, suffix, name)) + + # Support for running the macCatalyst tests with + # the iOS-like target triple. + if name == "macosx-x86_64" and args.maccatalyst and args.maccatalyst_ios_tests: + self.swift_test_run_targets.append("check-swift{}{}-{}".format( + subset_suffix, suffix, "macosx-maccatalyst-x86_64")) + else: + self.swift_test_run_targets.append("check-swift{}{}-{}".format( + subset_suffix, suffix, name)) if args.test_optimized and not test_host_only: self.swift_test_run_targets.append( "check-swift{}-optimize-{}".format( From 655d89b14610ec5628ed14922a0e70ee9c43d3fb Mon Sep 17 00:00:00 2001 From: Devin Coughlin Date: Sun, 5 Jan 2020 21:26:06 -0800 Subject: [PATCH 3/6] [Driver/Frontend] Add Driver support for macCatalyst and library search paths Add support in the driver and frontend for macCatalyst target targets and library search paths. The compiler now adds two library search paths for overlays when compiling for macCatalyst: one for macCatalyst libraries and one for zippered macOS libraries. The macCatalyst path must take priority over the normal macOS path so that in the case of 'unzippered twins' the macCatalyst library is found instead of the macOS library. To support 'zippered' builds, also add support for a new -target-variant flag. For zippered libraries, the driver invocation takes both a -target and a -target-variant flag passes them along to the frontend. We support builds both when the target is a macOS triple and the target variant is macCatalyst and also the 'reverse zippered' configuration where the target is macCatalyst and the target-variant is macOS. --- include/swift/AST/DiagnosticsDriver.def | 4 ++ include/swift/Basic/LangOptions.h | 11 ++++ include/swift/Basic/Platform.h | 8 +++ include/swift/Driver/ToolChain.h | 8 ++- include/swift/Option/Options.td | 5 ++ lib/Basic/Platform.cpp | 34 ++++++++++ lib/Driver/DarwinToolChains.cpp | 50 ++++++++++++++- lib/Driver/Driver.cpp | 12 +++- lib/Driver/ToolChains.cpp | 45 +++++++++++++- lib/Driver/ToolChains.h | 14 ++++- lib/Frontend/CompilerInvocation.cpp | 26 +++++++- test/Driver/linker-clang_rt.swift | 2 + test/Driver/macabi-environment.swift | 83 +++++++++++++++++++++++++ 13 files changed, 290 insertions(+), 12 deletions(-) create mode 100644 test/Driver/macabi-environment.swift diff --git a/include/swift/AST/DiagnosticsDriver.def b/include/swift/AST/DiagnosticsDriver.def index e301e51f09daf..2246c54348a2e 100644 --- a/include/swift/AST/DiagnosticsDriver.def +++ b/include/swift/AST/DiagnosticsDriver.def @@ -117,6 +117,10 @@ ERROR(error_sdk_too_old,none, ERROR(error_ios_maximum_deployment_32,none, "iOS %0 does not support 32-bit programs", (unsigned)) +ERROR(error_unsupported_target_variant,none, + "unsupported '%select{-target|-target-variant}1' value '%0'; use 'ios-macabi' instead", + (StringRef, bool)) + WARNING(warn_arclite_not_found_when_link_objc_runtime,none, "unable to find Objective-C runtime support library 'arclite'; " "pass '-no-link-objc-runtime' to silence this warning", ()) diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 3d54ece63ff4f..b4ede616d1131 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -64,6 +64,17 @@ namespace swift { /// This represents the minimum deployment target. llvm::Triple Target; + /// \brief The second target for a zippered build + /// + /// This represents the target and minimum deployment version for the + /// second ('variant') target when performing a zippered build. + /// For example, if the target is x86_64-apple-macosx10.14 then + /// a target-variant of x86_64-apple-ios12.0-macabi will produce + /// a zippered binary that can be loaded into both macCatalyst and + /// macOS processes. A value of 'None' means no zippering will be + /// performed. + llvm::Optional TargetVariant; + /// /// Language features /// diff --git a/include/swift/Basic/Platform.h b/include/swift/Basic/Platform.h index cfd9abebd4a00..eb21ea7a29714 100644 --- a/include/swift/Basic/Platform.h +++ b/include/swift/Basic/Platform.h @@ -46,6 +46,14 @@ namespace swift { /// Return true if the given triple represents any simulator. bool tripleIsAnySimulator(const llvm::Triple &triple); + /// Returns true if the given triple represents a macCatalyst environment. + bool tripleIsMacCatalystEnvironment(const llvm::Triple &triple); + + /// Returns true if the given -target triple and -target-variant triple + /// can be zippered. + bool triplesAreValidForZippering(const llvm::Triple &target, + const llvm::Triple &targetVariant); + /// Returns true if the given triple represents an OS that ships with /// ABI-stable swift libraries (eg. in /usr/lib/swift). bool tripleRequiresRPathForSwiftInOS(const llvm::Triple &triple); diff --git a/include/swift/Driver/ToolChain.h b/include/swift/Driver/ToolChain.h index 921b9fb04defc..12c1b802e0716 100644 --- a/include/swift/Driver/ToolChain.h +++ b/include/swift/Driver/ToolChain.h @@ -201,6 +201,11 @@ class ToolChain { void getResourceDirPath(SmallVectorImpl &runtimeLibPath, const llvm::opt::ArgList &args, bool shared) const; + /// Get the secondary runtime library link path given the primary path. + void getSecondaryResourceDirPath( + SmallVectorImpl &secondaryResourceDirPath, + StringRef primaryPath) const; + /// Get the runtime library link paths, which typically include the resource /// dir path and the SDK. void getRuntimeLibraryPaths(SmallVectorImpl &runtimeLibPaths, @@ -310,7 +315,8 @@ class ToolChain { /// An override point for platform-specific subclasses to customize the /// validations that should be performed. virtual void validateArguments(DiagnosticEngine &diags, - const llvm::opt::ArgList &args) const {} + const llvm::opt::ArgList &args, + StringRef defaultTarget) const {} }; } // end namespace driver } // end namespace swift diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index a5a7813b4f17c..b5de606ec416c 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -919,6 +919,11 @@ def print_target_info : Flag<["-"], "print-target-info">, def target_cpu : Separate<["-"], "target-cpu">, Flags<[FrontendOption, ModuleInterfaceOption]>, HelpText<"Generate code for a particular CPU variant">; +def target_variant : Separate<["-"], "target-variant">, + Flags<[FrontendOption]>, + HelpText<"Generate 'zippered' code for macCatalyst that can run on the specified" + " variant target triple in addition to the main -target triple">; + def profile_generate : Flag<["-"], "profile-generate">, Flags<[FrontendOption, NoInteractiveOption]>, HelpText<"Generate instrumented code to collect execution counts">; diff --git a/lib/Basic/Platform.cpp b/lib/Basic/Platform.cpp index 85abc0ee97e43..9581df610fab2 100644 --- a/lib/Basic/Platform.cpp +++ b/lib/Basic/Platform.cpp @@ -21,6 +21,7 @@ using namespace swift; bool swift::tripleIsiOSSimulator(const llvm::Triple &triple) { llvm::Triple::ArchType arch = triple.getArch(); return (triple.isiOS() && + !tripleIsMacCatalystEnvironment(triple) && // FIXME: transitional, this should eventually stop testing arch, and // switch to only checking the -environment field. (triple.isSimulatorEnvironment() || @@ -54,6 +55,38 @@ bool swift::tripleIsAnySimulator(const llvm::Triple &triple) { tripleIsAppleTVSimulator(triple); } +bool swift::tripleIsMacCatalystEnvironment(const llvm::Triple &triple) { + return triple.isiOS() && !triple.isTvOS() && + triple.getEnvironment() == llvm::Triple::MacABI; +} + +bool swift::triplesAreValidForZippering(const llvm::Triple &target, + const llvm::Triple &targetVariant) { + // The arch and vendor must match. + if (target.getArchName() != targetVariant.getArchName() || + target.getArch() != targetVariant.getArch() || + target.getSubArch() != targetVariant.getSubArch() || + target.getVendor() != targetVariant.getVendor()) { + return false; + } + + // Allow a macOS target and an iOS-macabi target variant + // This is typically the case when zippering a library originally + // developed for macOS. + if (target.isMacOSX() && tripleIsMacCatalystEnvironment(targetVariant)) { + return true; + } + + // Allow an iOS-macabi target and a macOS target variant. This would + // be the case when zippering a library originally developed for + // iOS. + if (targetVariant.isMacOSX() && tripleIsMacCatalystEnvironment(target)) { + return true; + } + + return false; +} + bool swift::tripleRequiresRPathForSwiftInOS(const llvm::Triple &triple) { if (triple.isMacOSX()) { // macOS 10.14.4 contains a copy of Swift, but the linker will still use an @@ -304,6 +337,7 @@ getEnvironmentForAppleTargetSpecificModuleTriple(const llvm::Triple &triple) { .Cases("unknown", "", None) // These values are also supported, but are handled by the default case below: // .Case ("simulator", StringRef("simulator")) + // .Case ("macabi", StringRef("macabi")) .Default(tripleEnvironment); } diff --git a/lib/Driver/DarwinToolChains.cpp b/lib/Driver/DarwinToolChains.cpp index 9a8974b67e82a..71656e2fa8073 100644 --- a/lib/Driver/DarwinToolChains.cpp +++ b/lib/Driver/DarwinToolChains.cpp @@ -96,6 +96,11 @@ getDarwinLibraryNameSuffixForTriple(const llvm::Triple &triple, case DarwinPlatformKind::MacOS: return "osx"; case DarwinPlatformKind::IPhoneOS: + // Here we return "osx" under the assumption that all the + // darwin runtime libraries are zippered and so the "osx" variants + // should be used for macCatalyst targets. + if (tripleIsMacCatalystEnvironment(triple)) + return "osx"; return "ios"; case DarwinPlatformKind::IPhoneOSSimulator: return "iossim"; @@ -431,6 +436,9 @@ toolchains::Darwin::addArgsToLinkStdlib(ArgStringList &Arguments, // package isn't installed. Arguments.push_back("-rpath"); Arguments.push_back(context.Args.MakeArgString("/usr/lib/swift")); + // We don't need an rpath for /System/iOSSupport/usr/lib/swift because... + assert(!tripleIsMacCatalystEnvironment(getTriple()) + && "macCatalyst not supported without Swift-in-the-OS"); } } @@ -489,12 +497,23 @@ toolchains::Darwin::addDeploymentTargetArgs(ArgStringList &Arguments, } else { if (isiOSSimulator) Arguments.push_back("-ios_simulator_version_min"); + else if (tripleIsMacCatalystEnvironment(Triple)) + Arguments.push_back("-maccatalyst_version_min"); else Arguments.push_back("-iphoneos_version_min"); } unsigned major, minor, micro; Triple.getiOSVersion(major, minor, micro); addVersionString(context.Args, Arguments, major, minor, micro); + + if (TargetVariant) { + assert(triplesAreValidForZippering(Triple, *TargetVariant)); + assert(TargetVariant->isMacOSX()); + Arguments.push_back("-macosx_version_min"); + unsigned major, minor, micro; + TargetVariant->getMacOSXVersion(major, minor, micro); + addVersionString(context.Args, Arguments, major, minor, micro); + } } else if (Triple.isWatchOS()) { if (tripleIsWatchSimulator(Triple)) Arguments.push_back("-watchos_simulator_version_min"); @@ -508,6 +527,15 @@ toolchains::Darwin::addDeploymentTargetArgs(ArgStringList &Arguments, unsigned major, minor, micro; Triple.getMacOSXVersion(major, minor, micro); addVersionString(context.Args, Arguments, major, minor, micro); + + if (TargetVariant) { + assert(triplesAreValidForZippering(Triple, *TargetVariant)); + assert(tripleIsMacCatalystEnvironment(*TargetVariant)); + Arguments.push_back("-maccatalyst_version_min"); + unsigned major, minor, micro; + TargetVariant->getiOSVersion(major, minor, micro); + addVersionString(context.Args, Arguments, major, minor, micro); + } } } @@ -718,15 +746,33 @@ static void validateDeploymentTarget(const toolchains::Darwin &TC, } } +static void validateTargetVariant(const toolchains::Darwin &TC, + DiagnosticEngine &diags, + const llvm::opt::ArgList &args, + StringRef defaultTarget) { + if (TC.getTargetVariant().hasValue()) { + auto target = TC.getTriple(); + auto variant = *TC.getTargetVariant(); + + if (!triplesAreValidForZippering(target, variant)) { + diags.diagnose(SourceLoc(), diag::error_unsupported_target_variant, + variant.str(), + variant.isiOS()); + } + } +} + void toolchains::Darwin::validateArguments(DiagnosticEngine &diags, - const llvm::opt::ArgList &args) const { + const llvm::opt::ArgList &args, + StringRef defaultTarget) const { // Validating arclite library path when link-objc-runtime. validateLinkObjcRuntimeARCLiteLib(*this, diags, args); // Validating apple platforms deployment targets. validateDeploymentTarget(*this, diags, args); - + validateTargetVariant(*this, diags, args, defaultTarget); + // Validating darwin unsupported -static-stdlib argument. if (args.hasArg(options::OPT_static_stdlib)) { diags.diagnose(SourceLoc(), diag::error_darwin_static_stdlib_not_supported); diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 4cba95dffecbe..24aa389685474 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -22,6 +22,7 @@ #include "swift/AST/DiagnosticsFrontend.h" #include "swift/Basic/LLVM.h" #include "swift/Basic/OutputFileMap.h" +#include "swift/Basic/Platform.h" #include "swift/Basic/Range.h" #include "swift/Basic/Statistic.h" #include "swift/Basic/TaskQueue.h" @@ -252,8 +253,13 @@ Driver::buildToolChain(const llvm::opt::InputArgList &ArgList) { case llvm::Triple::MacOSX: case llvm::Triple::IOS: case llvm::Triple::TvOS: - case llvm::Triple::WatchOS: - return llvm::make_unique(*this, target); + case llvm::Triple::WatchOS: { + Optional targetVariant; + if (const Arg *A = ArgList.getLastArg(options::OPT_target_variant)) + targetVariant = llvm::Triple(llvm::Triple::normalize(A->getValue())); + + return llvm::make_unique(*this, target, targetVariant); + } case llvm::Triple::Linux: if (target.isAndroid()) return llvm::make_unique(*this, target); @@ -824,7 +830,7 @@ Driver::buildCompilation(const ToolChain &TC, validateArgs(Diags, *TranslatedArgList, TC.getTriple()); // Perform toolchain specific args validation. - TC.validateArguments(Diags, *TranslatedArgList); + TC.validateArguments(Diags, *TranslatedArgList, DefaultTargetTriple); if (Diags.hadAnyError()) return nullptr; diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 092921b03a6b5..9e65bf4f28a07 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -151,6 +151,12 @@ static void addCommonFrontendArgs(const ToolChain &TC, const OutputInfo &OI, break; } + if (const Arg *variant = inputArgs.getLastArg(options::OPT_target_variant)) { + arguments.push_back("-target-variant"); + std::string normalized = llvm::Triple::normalize(variant->getValue()); + arguments.push_back(inputArgs.MakeArgString(normalized)); + } + // Enable address top-byte ignored in the ARM64 backend. if (Triple.getArch() == llvm::Triple::aarch64) { arguments.push_back("-Xllvm"); @@ -1223,8 +1229,28 @@ void ToolChain::getResourceDirPath(SmallVectorImpl &resourceDirPath, llvm::sys::path::append(resourceDirPath, "lib", shared ? "swift" : "swift_static"); } - llvm::sys::path::append(resourceDirPath, - getPlatformNameForTriple(getTriple())); + + StringRef libSubDir = getPlatformNameForTriple(getTriple()); + if (tripleIsMacCatalystEnvironment(getTriple())) + libSubDir = "maccatalyst"; + llvm::sys::path::append(resourceDirPath, libSubDir); +} + +// Get the secondary runtime library link path given the primary path. +// The compiler will look for runtime libraries in the secondary path if they +// can't be found in the primary path. +void ToolChain::getSecondaryResourceDirPath( + SmallVectorImpl &secondaryResourceDirPath, + StringRef primaryPath) const { + if (!tripleIsMacCatalystEnvironment(getTriple())) + return; + + // For macCatalyst, the secondary runtime library path is the macOS library + // path. The compiler will find zippered libraries here. + secondaryResourceDirPath.append(primaryPath.begin(), primaryPath.end()); + // Remove '/maccatalyst' and replace with 'macosx'. + llvm::sys::path::remove_filename(secondaryResourceDirPath); + llvm::sys::path::append(secondaryResourceDirPath, "macosx"); } void ToolChain::getRuntimeLibraryPaths(SmallVectorImpl &runtimeLibPaths, @@ -1234,7 +1260,22 @@ void ToolChain::getRuntimeLibraryPaths(SmallVectorImpl &runtimeLibP getResourceDirPath(scratchPath, args, shared); runtimeLibPaths.push_back(scratchPath.str()); + // If there's a secondary resource dir, add it too. + scratchPath.clear(); + getSecondaryResourceDirPath(scratchPath, runtimeLibPaths[0]); + if (!scratchPath.empty()) + runtimeLibPaths.push_back(scratchPath.str()); + if (!SDKPath.empty()) { + if (!scratchPath.empty()) { + // If we added the secondary resource dir, we also need the iOSSupport + // directory. + scratchPath = SDKPath; + llvm::sys::path::append(scratchPath, "System", "iOSSupport"); + llvm::sys::path::append(scratchPath, "usr", "lib", "swift"); + runtimeLibPaths.push_back(scratchPath.str()); + } + scratchPath = SDKPath; llvm::sys::path::append(scratchPath, "usr", "lib", "swift"); runtimeLibPaths.push_back(scratchPath.str()); diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 936599c4cf36d..addeeba50f52c 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -55,17 +55,27 @@ class LLVM_LIBRARY_VISIBILITY Darwin : public ToolChain { const JobContext &context) const override; void validateArguments(DiagnosticEngine &diags, - const llvm::opt::ArgList &args) const override; + const llvm::opt::ArgList &args, + StringRef defaultTarget) const override; std::string findProgramRelativeToSwiftImpl(StringRef name) const override; bool shouldStoreInvocationInDebugInfo() const override; + const Optional TargetVariant; + public: - Darwin(const Driver &D, const llvm::Triple &Triple) : ToolChain(D, Triple) {} + Darwin(const Driver &D, const llvm::Triple &Triple, + const Optional &TargetVariant) : + ToolChain(D, Triple), TargetVariant(TargetVariant) {} + ~Darwin() = default; std::string sanitizerRuntimeLibName(StringRef Sanitizer, bool shared = true) const override; + + Optional getTargetVariant() const { + return TargetVariant; + } }; class LLVM_LIBRARY_VISIBILITY Windows : public ToolChain { diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index dbe9733e670ab..6d2c5636cf797 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -73,7 +73,14 @@ static void setDefaultPrebuiltCacheIfNecessary( return; SmallString<64> defaultPrebuiltPath{searchPathOpts.RuntimeResourcePath}; - StringRef platform = getPlatformNameForTriple(triple); + StringRef platform; + if (tripleIsMacCatalystEnvironment(triple)) { + // The prebuilt cache for macCatalyst is the same as the one for macOS, not iOS + // or a separate location of its own. + platform = "macosx"; + } else { + platform = getPlatformNameForTriple(triple); + } llvm::sys::path::append(defaultPrebuiltPath, platform, "prebuilt-modules"); frontendOpts.PrebuiltModuleCachePath = defaultPrebuiltPath.str(); } @@ -82,7 +89,11 @@ static void updateRuntimeLibraryPaths(SearchPathOptions &SearchPathOpts, llvm::Triple &Triple) { llvm::SmallString<128> LibPath(SearchPathOpts.RuntimeResourcePath); - llvm::sys::path::append(LibPath, getPlatformNameForTriple(Triple)); + StringRef LibSubDir = getPlatformNameForTriple(Triple); + if (tripleIsMacCatalystEnvironment(Triple)) + LibSubDir = "maccatalyst"; + + llvm::sys::path::append(LibPath, LibSubDir); SearchPathOpts.RuntimeLibraryPaths.clear(); SearchPathOpts.RuntimeLibraryPaths.push_back(LibPath.str()); if (Triple.isOSDarwin()) @@ -101,6 +112,13 @@ static void updateRuntimeLibraryPaths(SearchPathOptions &SearchPathOpts, SearchPathOpts.RuntimeLibraryImportPaths.push_back(LibPath.str()); if (!SearchPathOpts.SDKPath.empty()) { + if (tripleIsMacCatalystEnvironment(Triple)) { + LibPath = SearchPathOpts.SDKPath; + llvm::sys::path::append(LibPath, "System", "iOSSupport"); + llvm::sys::path::append(LibPath, "usr", "lib", "swift"); + SearchPathOpts.RuntimeLibraryImportPaths.push_back(LibPath.str()); + } + LibPath = SearchPathOpts.SDKPath; llvm::sys::path::append(LibPath, "usr", "lib", "swift"); if (!Triple.isOSDarwin()) { @@ -520,6 +538,10 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, TargetArg = A->getValue(); } + if (const Arg *A = Args.getLastArg(OPT_target_variant)) { + Opts.TargetVariant = llvm::Triple(A->getValue()); + } + Opts.EnableCXXInterop |= Args.hasArg(OPT_enable_cxx_interop); Opts.EnableObjCInterop = Args.hasFlag(OPT_enable_objc_interop, OPT_disable_objc_interop, diff --git a/test/Driver/linker-clang_rt.swift b/test/Driver/linker-clang_rt.swift index 6e1a37e03f6d2..7c8ad36805a54 100644 --- a/test/Driver/linker-clang_rt.swift +++ b/test/Driver/linker-clang_rt.swift @@ -14,6 +14,7 @@ // RUN: touch %t/lib/swift/clang/lib/darwin/libclang_rt.osx.a %t/lib/swift/clang/lib/darwin/libclang_rt.ios.a %t/lib/swift/clang/lib/darwin/libclang_rt.tvos.a %t/lib/swift/clang/lib/darwin/libclang_rt.watchos.a // RUN: %t/bin/swiftc -driver-print-jobs -target x86_64-apple-macosx10.9 %S/../Inputs/empty.swift | %FileCheck -check-prefix CHECK -check-prefix CHECK-MACOS %s +// RUN: %t/bin/swiftc -driver-print-jobs -target x86_64-apple-ios13.0-macabi %S/../Inputs/empty.swift | %FileCheck -check-prefix CHECK -check-prefix CHECK-MACCATALYST %s // RUN: %t/bin/swiftc -driver-print-jobs -target i386-apple-ios7 %S/../Inputs/empty.swift | %FileCheck -check-prefix CHECK -check-prefix CHECK-IOS %s // RUN: %t/bin/swiftc -driver-print-jobs -target x86_64-apple-ios7 %S/../Inputs/empty.swift | %FileCheck -check-prefix CHECK -check-prefix CHECK-IOS %s @@ -31,6 +32,7 @@ // CHECK: {{(bin/)?}}ld{{(.exe)?"? }} // CHECK-NO-RUNTIME-NOT: libclang_rt +// CHECK-MACCATALYST-SAME: {{[^ ]+(/|\\\\)lib(/|\\\\)swift(/|\\\\)clang(/|\\\\)lib(/|\\\\)darwin(/|\\\\)libclang_rt.osx.a}} // CHECK-MACOS-SAME: {{[^ ]+(/|\\\\)lib(/|\\\\)swift(/|\\\\)clang(/|\\\\)lib(/|\\\\)darwin(/|\\\\)libclang_rt.osx.a}} // CHECK-IOS-SAME: {{[^ ]+(/|\\\\)lib(/|\\\\)swift(/|\\\\)clang(/|\\\\)lib(/|\\\\)darwin(/|\\\\)libclang_rt.ios.a}} // CHECK-TVOS-SAME: {{[^ ]+(/|\\\\)lib(/|\\\\)swift(/|\\\\)clang(/|\\\\)lib(/|\\\\)darwin(/|\\\\)libclang_rt.tvos.a}} diff --git a/test/Driver/macabi-environment.swift b/test/Driver/macabi-environment.swift new file mode 100644 index 0000000000000..516d90fba6140 --- /dev/null +++ b/test/Driver/macabi-environment.swift @@ -0,0 +1,83 @@ +// Tests to check that the driver finds standard library in the macabi environment. + +// UNSUPPORTED: windows + +// RUN: %swiftc_driver -driver-print-jobs -target x86_64-apple-ios13.0-macabi -sdk %S/../Inputs/clang-importer-sdk %s | %FileCheck -check-prefix=IOS13-MACABI %s +// IOS13-MACABI: bin/swift +// IOS13-MACABI: -target x86_64-apple-ios13.0-macabi + +// IOS13-MACABI: bin/ld +// IOS13-MACABI-DAG: -L [[MACCATALYST_STDLIB_PATH:[^ ]+/lib/swift/maccatalyst]] +// IOS13-MACABI-DAG: -L [[MACOSX_STDLIB_PATH:[^ ]+/lib/swift/macosx]] +// IOS13-MACABI-DAG: -L [[MACCATALYST_SDK_STDLIB_PATH:[^ ]+/clang-importer-sdk/System/iOSSupport/usr/lib/swift]] +// IOS13-MACABI-DAG: -L [[MACOSX_SDK_STDLIB_PATH:[^ ]+/clang-importer-sdk/usr/lib/swift]] +// IOS13-MACABI-DAG: -rpath [[MACCATALYST_STDLIB_PATH]] +// IOS13-MACABI-DAG: -rpath [[MACOSX_STDLIB_PATH]] +// IOS13-MACABI-DAG: -rpath [[MACCATALYST_SDK_STDLIB_PATH]] +// IOS13-MACABI-DAG: -rpath [[MACOSX_SDK_STDLIB_PATH]] +// IOS13-MACABI-DAG: -maccatalyst_version_min 13.0.0 + + +// Test using target-variant to build zippered outputs + +// RUN: %swiftc_driver -driver-print-jobs -c -target x86_64-apple-macosx10.14 -target-variant x86_64-apple-ios13.0-macabi %s | %FileCheck -check-prefix=ZIPPERED-VARIANT-OBJECT %s +// ZIPPERED-VARIANT-OBJECT: bin/swift +// ZIPPERED-VARIANT-OBJECT: -target x86_64-apple-macosx10.14 -target-variant x86_64-apple-ios13.0-macabi + +// RUN: %swiftc_driver -driver-print-jobs -emit-library -target x86_64-apple-macosx10.14 -target-variant x86_64-apple-ios13.0-macabi -module-name foo %s | %FileCheck -check-prefix=ZIPPERED-VARIANT-LIBRARY %s +// ZIPPERED-VARIANT-LIBRARY: bin/swift +// ZIPPERED-VARIANT-LIBRARY: -target x86_64-apple-macosx10.14 -target-variant x86_64-apple-ios13.0-macabi + +// ZIPPERED-VARIANT-LIBRARY: bin/ld +// ZIPPERED-VARIANT-LIBRARY: -macosx_version_min 10.14.0 -maccatalyst_version_min 13.0.0 + +// Make sure we pass the -target-variant when creating the pre-compiled header. +// RUN: %swiftc_driver -driver-print-jobs -target x86_64-apple-macosx10.14 -target-variant x86_64-apple-ios13.0-macabi -enable-bridging-pch -import-objc-header %S/Inputs/bridging-header.h %s | %FileCheck -check-prefix=ZIPPERED-VARIANT-PCH %s +// ZIPPERED-VARIANT-PCH: bin/swift +// ZIPPERED-VARIANT-PCH: -target x86_64-apple-macosx10.14 -target-variant x86_64-apple-ios13.0-macabi +// ZIPPERED_VARIANT-PCH -emit-pch +// ZIPPERED-VARIANT-PCH: bin/swift +// ZIPPERED-VARIANT-PCH: -target x86_64-apple-macosx10.14 -target-variant x86_64-apple-ios13.0-macabi +// ZIPPERED-VARIANT-PCH: bin/ld +// ZIPPERED-VARIANT-PCH: -macosx_version_min 10.14.0 -maccatalyst_version_min 13.0.0 + +// Test using 'reverse' target-variant to build zippered outputs when the primary +// target is ios-macabi + +// RUN: %swiftc_driver -driver-print-jobs -c -target x86_64-apple-ios13.0-macabi -target-variant x86_64-apple-macosx10.14 %s | %FileCheck -check-prefix=REVERSE-ZIPPERED-VARIANT-OBJECT %s +// REVERSE-ZIPPERED-VARIANT-OBJECT: bin/swift +// REVERSE-ZIPPERED-VARIANT-OBJECT: -target x86_64-apple-ios13.0-macabi -target-variant x86_64-apple-macosx10.14 + +// RUN: %swiftc_driver -driver-print-jobs -emit-library -target x86_64-apple-ios13.0-macabi -target-variant x86_64-apple-macosx10.14 -module-name foo %s | %FileCheck -check-prefix=REVERSE-ZIPPERED-VARIANT-LIBRARY %s +// REVERSE-ZIPPERED-VARIANT-LIBRARY: bin/swift +// REVERSE-ZIPPERED-VARIANT-LIBRARY: -target x86_64-apple-ios13.0-macabi -target-variant x86_64-apple-macosx10.14 + +// REVERSE-ZIPPERED-VARIANT-LIBRARY: bin/ld +// REVERSE-ZIPPERED-VARIANT-LIBRARY: -maccatalyst_version_min 13.0.0 -macosx_version_min 10.14.0 + +// Make sure we pass the -target-variant when creating the pre-compiled header. +// RUN: %swiftc_driver -driver-print-jobs -target x86_64-apple-ios13.0-macabi -target-variant x86_64-apple-macosx10.14 -enable-bridging-pch -import-objc-header %S/Inputs/bridging-header.h %s | %FileCheck -check-prefix=REVERSE-ZIPPERED-VARIANT-PCH %s +// REVERSE-ZIPPERED-VARIANT-PCH: bin/swift +// REVERSE-ZIPPERED-VARIANT-PCH: -target x86_64-apple-ios13.0-macabi -target-variant x86_64-apple-macosx10.14 +// REVERSE-ZIPPERED_VARIANT-PCH -emit-pch +// REVERSE-ZIPPERED-VARIANT-PCH: bin/swift +// REVERSE-ZIPPERED-VARIANT-PCH: -target x86_64-apple-ios13.0-macabi -target-variant x86_64-apple-macosx10.14 +// REVERSE-ZIPPERED-VARIANT-PCH: bin/ld +// REVERSE-ZIPPERED-VARIANT-PCH: -maccatalyst_version_min 13.0.0 -macosx_version_min 10.14.0 + +// RUN: not %swiftc_driver -target x86_64-apple-macosx10.14 -target-variant x86_64-apple-ios13.0 %s 2>&1 | %FileCheck --check-prefix=UNSUPPORTED-TARGET-VARIANT %s +// RUN: not %swiftc_driver -target x86_64-apple-ios13.0 -target-variant x86_64-apple-macosx10.14 %s 2>&1 | %FileCheck --check-prefix=UNSUPPORTED-TARGET %s + +// UNSUPPORTED-TARGET-VARIANT: error: unsupported '-target-variant' value {{.*}}; use 'ios-macabi' instead +// UNSUPPORTED-TARGET: error: unsupported '-target' value {{.*}}; use 'ios-macabi' instead + +// When compiling for iOS, pass iphoneos_version_min to the linker, not maccatalyst_version_min. + +// RUN: %swiftc_driver -driver-print-jobs -target arm64-apple-ios13.0 -sdk %S/../Inputs/clang-importer-sdk %s | %FileCheck -check-prefix=IOS13-NO-MACABI -implicit-check-not=maccatalyst_version_min %s +// IOS13-NO-MACABI: bin/swift +// IOS13-NO-MACABI: -target arm64-apple-ios13.0 + +// IOS13-NO-MACABI: bin/ld +// IOS13-NO-MACABI-DAG: -L {{[^ ]+/lib/swift/iphoneos}} +// IOS13-NO-MACABI-DAG: -L {{[^ ]+/clang-importer-sdk/usr/lib/swift}} +// IOS13-NO-MACABI-DAG: -iphoneos_version_min 13.0.0 From 8c5c5ec80261d2acc9aef03ffe5c8be0a745094d Mon Sep 17 00:00:00 2001 From: Devin Coughlin Date: Sun, 5 Jan 2020 21:26:14 -0800 Subject: [PATCH 4/6] [Parse] Support macCatalyst conditional compilation Add support for conditional compilation under macCatalyst Developers can now detect whether they are compiling for macCatalyst at compile time with: #if targetEnvironment(macCatalyst) // Code only compiled under macCatalyst. #end --- include/swift/AST/DiagnosticsParse.def | 2 + include/swift/Basic/LangOptions.h | 3 +- lib/Basic/LangOptions.cpp | 57 ++++++++++++++----- lib/Parse/ParseIfConfig.cpp | 10 ++++ .../basicParseErrors.swift | 2 +- .../macabiTargetEnv.swift | 36 ++++++++++++ 6 files changed, 94 insertions(+), 16 deletions(-) create mode 100644 test/Parse/ConditionalCompilation/macabiTargetEnv.swift diff --git a/include/swift/AST/DiagnosticsParse.def b/include/swift/AST/DiagnosticsParse.def index afda5761bce67..1cbb3766c86ee 100644 --- a/include/swift/AST/DiagnosticsParse.def +++ b/include/swift/AST/DiagnosticsParse.def @@ -1651,6 +1651,8 @@ ERROR(empty_version_string,none, WARNING(unknown_platform_condition_argument,none, "unknown %0 for build configuration '%1'", (StringRef, StringRef)) +WARNING(renamed_platform_condition_argument,none, + "'%0' has been renamed to '%1'", (StringRef, StringRef)) WARNING(likely_simulator_platform_condition,none, "platform condition appears to be testing for simulator environment; " "use 'targetEnvironment(simulator)' instead", diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index b4ede616d1131..28602e9b3890c 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -413,7 +413,8 @@ namespace swift { /// /// \param suggestedKind Populated with suggested replacement platform condition /// \param suggestedValues Populated with suggested replacement values - /// if a match is not found. + /// if a match is not found, or if the value has been deprecated + /// in favor of a newer one. static bool checkPlatformConditionSupported( PlatformConditionKind Kind, StringRef Value, PlatformConditionKind &suggestedKind, diff --git a/lib/Basic/LangOptions.cpp b/lib/Basic/LangOptions.cpp index 95c937cbd2f43..def6143af764f 100644 --- a/lib/Basic/LangOptions.cpp +++ b/lib/Basic/LangOptions.cpp @@ -26,7 +26,18 @@ using namespace swift; -static const StringRef SupportedConditionalCompilationOSs[] = { +struct SupportedConditionalValue { + StringRef value; + + /// If the value has been deprecated, the new value to replace it with. + StringRef replacement = ""; + + SupportedConditionalValue(const char *value) : value(value) {} + SupportedConditionalValue(const char *value, const char *replacement) + : value(value), replacement(replacement) {} +}; + +static const SupportedConditionalValue SupportedConditionalCompilationOSs[] = { "OSX", "macOS", "tvOS", @@ -42,7 +53,7 @@ static const StringRef SupportedConditionalCompilationOSs[] = { "WASI", }; -static const StringRef SupportedConditionalCompilationArches[] = { +static const SupportedConditionalValue SupportedConditionalCompilationArches[] = { "arm", "arm64", "i386", @@ -53,18 +64,20 @@ static const StringRef SupportedConditionalCompilationArches[] = { "wasm32", }; -static const StringRef SupportedConditionalCompilationEndianness[] = { +static const SupportedConditionalValue SupportedConditionalCompilationEndianness[] = { "little", "big" }; -static const StringRef SupportedConditionalCompilationRuntimes[] = { +static const SupportedConditionalValue SupportedConditionalCompilationRuntimes[] = { "_ObjC", "_Native", }; -static const StringRef SupportedConditionalCompilationTargetEnvironments[] = { +static const SupportedConditionalValue SupportedConditionalCompilationTargetEnvironments[] = { "simulator", + { "macabi", "macCatalyst" }, + "macCatalyst", // A synonym for "macabi" when compiling for iOS }; static const PlatformConditionKind AllPublicPlatformConditionKinds[] = { @@ -73,7 +86,7 @@ static const PlatformConditionKind AllPublicPlatformConditionKinds[] = { #include "swift/AST/PlatformConditionKinds.def" }; -ArrayRef getSupportedConditionalCompilationValues(const PlatformConditionKind &Kind) { +ArrayRef getSupportedConditionalCompilationValues(const PlatformConditionKind &Kind) { switch (Kind) { case PlatformConditionKind::OS: return SupportedConditionalCompilationOSs; @@ -97,11 +110,11 @@ PlatformConditionKind suggestedPlatformConditionKind(PlatformConditionKind Kind, for (const PlatformConditionKind& candidateKind : AllPublicPlatformConditionKinds) { if (candidateKind != Kind) { auto supportedValues = getSupportedConditionalCompilationValues(candidateKind); - for (const StringRef& candidateValue : supportedValues) { - if (candidateValue.lower() == lower) { + for (const SupportedConditionalValue& candidateValue : supportedValues) { + if (candidateValue.value.lower() == lower) { suggestedValues.clear(); - if (candidateValue != V) { - suggestedValues.emplace_back(candidateValue); + if (candidateValue.value != V) { + suggestedValues.emplace_back(candidateValue.value); } return candidateKind; } @@ -118,19 +131,21 @@ bool isMatching(PlatformConditionKind Kind, const StringRef &V, unsigned minDistance = std::numeric_limits::max(); std::string lower = V.lower(); auto supportedValues = getSupportedConditionalCompilationValues(Kind); - for (const StringRef& candidate : supportedValues) { - if (candidate == V) { + for (const SupportedConditionalValue& candidate : supportedValues) { + if (candidate.value == V) { suggestedKind = Kind; suggestions.clear(); + if (!candidate.replacement.empty()) + suggestions.push_back(candidate.replacement); return true; } - unsigned distance = StringRef(lower).edit_distance(candidate.lower()); + unsigned distance = StringRef(lower).edit_distance(candidate.value.lower()); if (distance < minDistance) { suggestions.clear(); minDistance = distance; } if (distance == minDistance) - suggestions.emplace_back(candidate); + suggestions.emplace_back(candidate.value); } suggestedKind = suggestedPlatformConditionKind(Kind, V, suggestions); return false; @@ -171,6 +186,16 @@ checkPlatformCondition(PlatformConditionKind Kind, StringRef Value) const { if (Kind == PlatformConditionKind::OS && Value == "macOS") return checkPlatformCondition(Kind, "OSX"); + // When compiling for iOS we consider "macCatalyst" to be a + // synonym of "macabi". This enables the use of + // #if targetEnvironment(macCatalyst) as a compilation + // condition for macCatalyst. + + if (Kind == PlatformConditionKind::TargetEnvironment && + Value == "macCatalyst" && Target.isiOS()) { + return checkPlatformCondition(Kind, "macabi"); + } + for (auto &Opt : llvm::reverse(PlatformConditionValues)) { if (Opt.first == Kind) if (Opt.second == Value) @@ -321,6 +346,10 @@ std::pair LangOptions::setTarget(llvm::Triple triple) { addPlatformConditionValue(PlatformConditionKind::TargetEnvironment, "simulator"); + if (tripleIsMacCatalystEnvironment(Target)) + addPlatformConditionValue(PlatformConditionKind::TargetEnvironment, + "macabi"); + // If you add anything to this list, change the default size of // PlatformConditionValues to not require an extra allocation // in the common case. diff --git a/lib/Parse/ParseIfConfig.cpp b/lib/Parse/ParseIfConfig.cpp index 2b5d67bb2e4e1..aa7acdbfbadea 100644 --- a/lib/Parse/ParseIfConfig.cpp +++ b/lib/Parse/ParseIfConfig.cpp @@ -311,6 +311,16 @@ class ValidateIfConfigCondition : D.diagnose(Loc, diag::note_typo_candidate, suggestion) .fixItReplace(Arg->getSourceRange(), suggestion); } + else if (!suggestedValues.empty()) { + // The value the user gave has been replaced by something newer. + assert(suggestedValues.size() == 1 && "only support one replacement"); + auto replacement = suggestedValues.front(); + + auto Loc = Arg->getLoc(); + D.diagnose(Loc, diag::renamed_platform_condition_argument, + *ArgStr, replacement) + .fixItReplace(Arg->getSourceRange(), replacement); + } return E; } diff --git a/test/Parse/ConditionalCompilation/basicParseErrors.swift b/test/Parse/ConditionalCompilation/basicParseErrors.swift index f68a7c9849d65..9d0616bb0b925 100644 --- a/test/Parse/ConditionalCompilation/basicParseErrors.swift +++ b/test/Parse/ConditionalCompilation/basicParseErrors.swift @@ -148,7 +148,7 @@ undefinedFunc() // expected-error {{use of unresolved identifier 'undefinedFunc' #if _endian(arm64) // expected-warning {{unknown endianness for build configuration '_endian'}} expected-note {{did you mean 'arch'}} {{5-12=arch}} #endif -#if targetEnvironment(_ObjC) // expected-warning {{unknown target environment for build configuration 'targetEnvironment'}} expected-note {{did you mean 'simulator'}} {{23-28=simulator}} +#if targetEnvironment(_ObjC) // expected-warning {{unknown target environment for build configuration 'targetEnvironment'}} expected-note {{did you mean 'macabi'}} {{23-28=macabi}} #endif #if os(iOS) || os(simulator) // expected-warning {{unknown operating system for build configuration 'os'}} expected-note {{did you mean 'targetEnvironment'}} {{16-18=targetEnvironment}} diff --git a/test/Parse/ConditionalCompilation/macabiTargetEnv.swift b/test/Parse/ConditionalCompilation/macabiTargetEnv.swift new file mode 100644 index 0000000000000..f1990b3eb633f --- /dev/null +++ b/test/Parse/ConditionalCompilation/macabiTargetEnv.swift @@ -0,0 +1,36 @@ +// RUN: %swift -swift-version 4 -typecheck %s -verify -target x86_64-apple-ios12.0-macabi -parse-stdlib +// RUN: %swift-ide-test -swift-version 4 -test-input-complete -source-filename=%s -target x86_64-apple-ios12.0-macabi + +// REQUIRES: OS=maccatalyst + +#if targetEnvironment(macabi) // expected-warning {{'macabi' has been renamed to 'macCatalyst'}} {{23-29=macCatalyst}} +func underMacABI() { + foo() // expected-error {{use of unresolved identifier 'foo'}} +} +#endif + +#if !targetEnvironment(macabi) // expected-warning {{'macabi' has been renamed to 'macCatalyst'}} {{24-30=macCatalyst}} +// This block does not typecheck but the #if prevents it from +// from being a compiler error. +let i: SomeType = "SomeString" // no-error +#endif + +#if targetEnvironment(macCatalyst) +func underTargetEnvironmentMacCatalyst() { + foo() // expected-error {{use of unresolved identifier 'foo'}} +} +#endif + +// Make sure we don't treat the macabi environment as a simulator. +#if targetEnvironment(simulator) +// This block does not typecheck but the #if prevents it from +// from being a compiler error. +let i: SomeType = "SomeString" // no-error +#endif + +#if os(macCatalyst) +// expected-warning@-1 {{unknown operating system for build configuration 'os'}} +// expected-note@-2 *{{did you mean}} +func underOSMacCatalyst() { +} +#endif From 082421048a2c6d5c91495d5a083c09b3c6e970a5 Mon Sep 17 00:00:00 2001 From: Devin Coughlin Date: Sun, 5 Jan 2020 21:26:17 -0800 Subject: [PATCH 5/6] [AST/Sema] Add availability attributes for macCatalyst Add a platform kind and availability attributes for macCatalyst. macCatalyst uses iOS version numbers and inherits availability from iOS attributes unless a macCatalyst attribute is explicitly provided. --- include/swift/AST/Attr.h | 5 + include/swift/AST/PlatformKind.h | 15 ++- include/swift/AST/PlatformKinds.def | 2 + include/swift/AST/Stmt.h | 20 ++- lib/AST/Attr.cpp | 67 ++++++++++ lib/AST/PlatformKind.cpp | 39 +++++- lib/ClangImporter/ClangImporter.cpp | 12 ++ lib/PrintAsObjC/DeclAndTypePrinter.cpp | 6 + lib/Sema/TypeCheckAttr.cpp | 10 ++ lib/Sema/TypeCheckAvailability.cpp | 40 +++++- lib/SymbolGraphGen/Symbol.cpp | 4 + lib/TBDGen/TBDGen.cpp | 3 + test/IDE/complete_decl_attribute.swift | 2 + test/attr/attr_availability_maccatalyst.swift | 125 ++++++++++++++++++ .../lib/SwiftLang/SwiftDocSupport.cpp | 6 + 15 files changed, 345 insertions(+), 11 deletions(-) create mode 100644 test/attr/attr_availability_maccatalyst.swift diff --git a/include/swift/AST/Attr.h b/include/swift/AST/Attr.h index 146404a438fa6..476b46e6a1483 100644 --- a/include/swift/AST/Attr.h +++ b/include/swift/AST/Attr.h @@ -1997,6 +1997,11 @@ class DeclAttributes { bool isUnavailableInSwiftVersion(const version::Version &effectiveVersion) const; + /// Finds the most-specific platform-specific attribute that is + /// active for the current platform. + const AvailableAttr * + findMostSpecificActivePlatform(const ASTContext &ctx) const; + /// Returns the first @available attribute that indicates /// a declaration is unavailable, or the first one that indicates it's /// potentially unavailable, or null otherwise. diff --git a/include/swift/AST/PlatformKind.h b/include/swift/AST/PlatformKind.h index 37e171ef41652..b4bc373bd68cb 100644 --- a/include/swift/AST/PlatformKind.h +++ b/include/swift/AST/PlatformKind.h @@ -51,11 +51,20 @@ StringRef prettyPlatformString(PlatformKind platform); /// restrictions are enabled, but OSXApplicationExtension is not considered /// active when the target platform is OS X and app extension restrictions are /// disabled. PlatformKind::none is always considered active. -bool isPlatformActive(PlatformKind Platform, LangOptions &LangOpts); - +/// If ForTargetVariant is true then for zippered builds the target-variant +/// triple will be used rather than the target to determine whether the +/// platform is active. +bool isPlatformActive(PlatformKind Platform, LangOptions &LangOpts, + bool ForTargetVariant = false); + /// Returns the target platform for the given language options. PlatformKind targetPlatform(LangOptions &LangOpts); - + +/// Returns true when availability attributes from the "parent" platform +/// should also apply to the "child" platform for declarations without +/// an explicit attribute for the child. +bool inheritsAvailabilityFromPlatform(PlatformKind Child, PlatformKind Parent); + } // end namespace swift #endif diff --git a/include/swift/AST/PlatformKinds.def b/include/swift/AST/PlatformKinds.def index 9192450f15236..cc9b9ede0eae8 100644 --- a/include/swift/AST/PlatformKinds.def +++ b/include/swift/AST/PlatformKinds.def @@ -30,5 +30,7 @@ AVAILABILITY_PLATFORM(iOSApplicationExtension, "application extensions for iOS") AVAILABILITY_PLATFORM(tvOSApplicationExtension, "application extensions for tvOS") AVAILABILITY_PLATFORM(watchOSApplicationExtension, "application extensions for watchOS") AVAILABILITY_PLATFORM(OSXApplicationExtension, "application extensions for macOS") +AVAILABILITY_PLATFORM(macCatalyst, "Mac Catalyst") +AVAILABILITY_PLATFORM(macCatalystApplicationExtension, "application extensions for Mac Catalyst") #undef AVAILABILITY_PLATFORM diff --git a/include/swift/AST/Stmt.h b/include/swift/AST/Stmt.h index 9a762df4f6de2..6b6f7164fc22a 100644 --- a/include/swift/AST/Stmt.h +++ b/include/swift/AST/Stmt.h @@ -329,11 +329,20 @@ class alignas(8) PoundAvailableInfo final : /// The version range when this query will return true. This value is /// filled in by Sema. VersionRange AvailableRange; - + + /// For zippered builds, this is the version range for the target variant + /// that must hold for the query to return true. For example, when + /// compiling with target x86_64-macosx10.15 and target-variant + /// x86_64-ios13.0 a query of #available(macOS 10.22, iOS 20.0, *) will + /// have a variant range of [20.0, +inf). + /// This is filled in by Sema. + VersionRange VariantAvailableRange; + PoundAvailableInfo(SourceLoc PoundLoc, ArrayRef queries, SourceLoc RParenLoc) : PoundLoc(PoundLoc), RParenLoc(RParenLoc), NumQueries(queries.size()), - AvailableRange(VersionRange::empty()) { + AvailableRange(VersionRange::empty()), + VariantAvailableRange(VersionRange::empty()) { std::uninitialized_copy(queries.begin(), queries.end(), getTrailingObjects()); } @@ -356,6 +365,13 @@ class alignas(8) PoundAvailableInfo final : const VersionRange &getAvailableRange() const { return AvailableRange; } void setAvailableRange(const VersionRange &Range) { AvailableRange = Range; } + + const VersionRange &getVariantAvailableRange() const { + return VariantAvailableRange; + } + void setVariantAvailableRange(const VersionRange &Range) { + VariantAvailableRange = Range; + } }; diff --git a/lib/AST/Attr.cpp b/lib/AST/Attr.cpp index 7e09cc69accb3..bf2ec20779d8d 100644 --- a/lib/AST/Attr.cpp +++ b/lib/AST/Attr.cpp @@ -172,6 +172,35 @@ DeclAttributes::isUnavailableInSwiftVersion( return false; } +const AvailableAttr * +DeclAttributes::findMostSpecificActivePlatform(const ASTContext &ctx) const{ + const AvailableAttr *bestAttr = nullptr; + + for (auto attr : *this) { + auto *avAttr = dyn_cast(attr); + if (!avAttr) + continue; + + if (avAttr->isInvalid()) + continue; + + if (!avAttr->hasPlatform()) + continue; + + if (!avAttr->isActivePlatform(ctx)) + continue; + + // We have an attribute that is active for the platform, but + // is it more specific than our curent best? + if (!bestAttr || inheritsAvailabilityFromPlatform(avAttr->Platform, + bestAttr->Platform)) { + bestAttr = avAttr; + } + } + + return bestAttr; +} + const AvailableAttr * DeclAttributes::getPotentiallyUnavailable(const ASTContext &ctx) const { const AvailableAttr *potential = nullptr; @@ -217,12 +246,19 @@ DeclAttributes::getPotentiallyUnavailable(const ASTContext &ctx) const { const AvailableAttr *DeclAttributes::getUnavailable( const ASTContext &ctx) const { const AvailableAttr *conditional = nullptr; + const AvailableAttr *bestActive = findMostSpecificActivePlatform(ctx); for (auto Attr : *this) if (auto AvAttr = dyn_cast(Attr)) { if (AvAttr->isInvalid()) continue; + // If this is a platform-specific attribute and it isn't the most + // specific attribute for the current platform, we're done. + if (AvAttr->hasPlatform() && + (!bestActive || AvAttr != bestActive)) + continue; + // If this attribute doesn't apply to the active platform, we're done. if (!AvAttr->isActivePlatform(ctx) && !AvAttr->isLanguageVersionSpecific() && @@ -250,11 +286,16 @@ const AvailableAttr *DeclAttributes::getUnavailable( const AvailableAttr * DeclAttributes::getDeprecated(const ASTContext &ctx) const { const AvailableAttr *conditional = nullptr; + const AvailableAttr *bestActive = findMostSpecificActivePlatform(ctx); for (auto Attr : *this) { if (auto AvAttr = dyn_cast(Attr)) { if (AvAttr->isInvalid()) continue; + if (AvAttr->hasPlatform() && + (!bestActive || AvAttr != bestActive)) + continue; + if (!AvAttr->isActivePlatform(ctx) && !AvAttr->isLanguageVersionSpecific() && !AvAttr->isPackageDescriptionVersionSpecific()) @@ -329,6 +370,30 @@ static bool isShortAvailable(const DeclAttribute *DA) { return true; } +/// Return true when another availability attribute implies the same availability as this +/// attribute and so printing the attribute can be skipped to de-clutter the declaration +/// when printing the short form. +/// For example, iOS availability implies macCatalyst availability so if attributes for +/// both are present and they have the same 'introduced' version, we can skip printing an +/// explicit availability for macCatalyst. +static bool isShortFormAvailabilityImpliedByOther(const AvailableAttr *Attr, + ArrayRef Others) { + assert(isShortAvailable(Attr)); + + for (auto *DA : Others) { + auto *Other = cast(DA); + if (Attr->Platform == Other->Platform) + continue; + + if (!inheritsAvailabilityFromPlatform(Attr->Platform, Other->Platform)) + continue; + + if (Attr->Introduced == Other->Introduced) + return true; + } + return false; +} + /// Print the short-form @available() attribute for an array of long-form /// AvailableAttrs that can be represented in the short form. /// For example, for: @@ -359,6 +424,8 @@ static void printShortFormAvailable(ArrayRef Attrs, for (auto *DA : Attrs) { auto *AvailAttr = cast(DA); assert(AvailAttr->Introduced.hasValue()); + if (isShortFormAvailabilityImpliedByOther(AvailAttr, Attrs)) + continue; Printer << platformString(AvailAttr->Platform) << " " << AvailAttr->Introduced.getValue().getAsString() << ", "; } diff --git a/lib/AST/PlatformKind.cpp b/lib/AST/PlatformKind.cpp index c62460b05b97a..1119601d458c1 100644 --- a/lib/AST/PlatformKind.cpp +++ b/lib/AST/PlatformKind.cpp @@ -16,6 +16,7 @@ #include "swift/AST/PlatformKind.h" #include "swift/Basic/LangOptions.h" +#include "swift/Basic/Platform.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" @@ -63,7 +64,8 @@ static bool isPlatformActiveForTarget(PlatformKind Platform, return true; if (Platform == PlatformKind::OSXApplicationExtension || - Platform == PlatformKind::iOSApplicationExtension) + Platform == PlatformKind::iOSApplicationExtension || + Platform == PlatformKind::macCatalystApplicationExtension) if (!EnableAppExtensionRestrictions) return false; @@ -75,6 +77,9 @@ static bool isPlatformActiveForTarget(PlatformKind Platform, case PlatformKind::iOS: case PlatformKind::iOSApplicationExtension: return Target.isiOS() && !Target.isTvOS(); + case PlatformKind::macCatalyst: + case PlatformKind::macCatalystApplicationExtension: + return tripleIsMacCatalystEnvironment(Target); case PlatformKind::tvOS: case PlatformKind::tvOSApplicationExtension: return Target.isTvOS(); @@ -87,8 +92,15 @@ static bool isPlatformActiveForTarget(PlatformKind Platform, llvm_unreachable("bad PlatformKind"); } -bool swift::isPlatformActive(PlatformKind Platform, LangOptions &LangOpts) { +bool swift::isPlatformActive(PlatformKind Platform, LangOptions &LangOpts, + bool ForTargetVariant) { llvm::Triple TT = LangOpts.Target; + + if (ForTargetVariant) { + assert(LangOpts.TargetVariant && "Must have target variant triple"); + TT = *LangOpts.TargetVariant; + } + return isPlatformActiveForTarget(Platform, TT, LangOpts.EnableAppExtensionRestrictions); } @@ -113,6 +125,10 @@ PlatformKind swift::targetPlatform(LangOptions &LangOpts) { } if (LangOpts.Target.isiOS()) { + if (tripleIsMacCatalystEnvironment(LangOpts.Target)) + return (LangOpts.EnableAppExtensionRestrictions + ? PlatformKind::macCatalystApplicationExtension + : PlatformKind::macCatalyst); return (LangOpts.EnableAppExtensionRestrictions ? PlatformKind::iOSApplicationExtension : PlatformKind::iOS); @@ -120,3 +136,22 @@ PlatformKind swift::targetPlatform(LangOptions &LangOpts) { return PlatformKind::none; } + +bool swift::inheritsAvailabilityFromPlatform(PlatformKind Child, + PlatformKind Parent) { + if (Child == PlatformKind::macCatalyst && Parent == PlatformKind::iOS) + return true; + + if (Child == PlatformKind::macCatalystApplicationExtension) { + if (Parent == PlatformKind::iOS || + Parent == PlatformKind::iOSApplicationExtension || + Parent == PlatformKind::macCatalyst) { + return true; + } + } + + // Ideally we would have all ApplicationExtension platforms + // inherit from their non-extension platform. + + return false; +} diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index f36a626a7debd..e60015f6530df 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -1859,6 +1859,8 @@ PlatformAvailability::PlatformAvailability(LangOptions &langOpts) switch (platformKind) { case PlatformKind::iOS: case PlatformKind::iOSApplicationExtension: + case PlatformKind::macCatalyst: + case PlatformKind::macCatalystApplicationExtension: case PlatformKind::tvOS: case PlatformKind::tvOSApplicationExtension: deprecatedAsUnavailableMessage = @@ -1893,6 +1895,11 @@ bool PlatformAvailability::isPlatformRelevant(StringRef name) const { case PlatformKind::iOSApplicationExtension: return name == "ios" || name == "ios_app_extension"; + case PlatformKind::macCatalyst: + case PlatformKind::macCatalystApplicationExtension: + // ClangImporter does not yet support macCatalyst. + return false; + case PlatformKind::tvOS: return name == "tvos"; case PlatformKind::tvOSApplicationExtension: @@ -1933,6 +1940,11 @@ bool PlatformAvailability::treatDeprecatedAsUnavailable( // Anything deprecated in iOS 7.x and earlier is unavailable in Swift. return major <= 7; + case PlatformKind::macCatalyst: + case PlatformKind::macCatalystApplicationExtension: + // ClangImporter does not yet support macCatalyst. + return false; + case PlatformKind::watchOS: case PlatformKind::watchOSApplicationExtension: // No deprecation filter on watchOS diff --git a/lib/PrintAsObjC/DeclAndTypePrinter.cpp b/lib/PrintAsObjC/DeclAndTypePrinter.cpp index 0ed1c2c1999c5..0b609510f66c7 100644 --- a/lib/PrintAsObjC/DeclAndTypePrinter.cpp +++ b/lib/PrintAsObjC/DeclAndTypePrinter.cpp @@ -827,6 +827,9 @@ class DeclAndTypePrinter::Implementation case PlatformKind::iOS: plat = "ios"; break; + case PlatformKind::macCatalyst: + plat = "maccatalyst"; + break; case PlatformKind::tvOS: plat = "tvos"; break; @@ -839,6 +842,9 @@ class DeclAndTypePrinter::Implementation case PlatformKind::iOSApplicationExtension: plat = "ios_app_extension"; break; + case PlatformKind::macCatalystApplicationExtension: + plat = "maccatalyst_app_extension"; + break; case PlatformKind::tvOSApplicationExtension: plat = "tvos_app_extension"; break; diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 537723f19c71b..24c68f8b68d0e 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -1351,6 +1351,16 @@ void AttributeChecker::visitAvailableAttr(AvailableAttr *attr) { return; } + // Make sure there isn't a more specific attribute we should be using instead. + // findMostSpecificActivePlatform() is O(N), so only do this if we're checking + // an iOS attribute while building for macCatalyst. + if (attr->Platform == PlatformKind::iOS && + isPlatformActive(PlatformKind::macCatalyst, Ctx.LangOpts)) { + if (attr != D->getAttrs().findMostSpecificActivePlatform(Ctx)) { + return; + } + } + SourceLoc attrLoc = attr->getLocation(); Optional> MaybeNotAllowed = diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index 0f6812903c459..ecbebda7e831a 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -456,6 +456,18 @@ class TypeRefinementContextBuilder : private ASTWalker { AvailabilityContext NewConstraint = contextForSpec(Spec); Query->setAvailableRange(NewConstraint.getOSVersion()); + // When compiling zippered for macCatalyst, we need to collect both + // a macOS version (the target version) and an iOS/macCatalyst version + // (the target-variant). These versions will both be passed to a runtime + // entrypoint that will check either the macOS version or the iOS + // version depending on the kind of process this code is loaded into. + if (Context.LangOpts.TargetVariant) { + AvailabilitySpec *VariantSpec = + bestActiveSpecForQuery(Query, /*ForTargetVariant*/ true); + VersionRange VariantRange = contextForSpec(VariantSpec).getOSVersion(); + Query->setVariantAvailableRange(VariantRange); + } + if (Spec->getKind() == AvailabilitySpecKind::OtherPlatform) { // The wildcard spec '*' represents the minimum deployment target, so // there is no need to create a refinement context for this query. @@ -480,9 +492,18 @@ class TypeRefinementContextBuilder : private ASTWalker { // required compatibility version is different than the deployment // target). if (CurrentTRC->getReason() != TypeRefinementContext::Reason::Root) { + PlatformKind BestPlatform = targetPlatform(Context.LangOpts); + auto *PlatformSpec = + dyn_cast(Spec); + // If possible, try to report the diagnostic in terms for the + // platform the user uttered in the '#available()'. For a platform + // that inherits availability from another platform it may be + // different from the platform specified in the target triple. + if (PlatformSpec) + BestPlatform = PlatformSpec->getPlatform(); Diags.diagnose(Query->getLoc(), diag::availability_query_useless_enclosing_scope, - platformString(targetPlatform(Context.LangOpts))); + platformString(BestPlatform)); Diags.diagnose(CurrentTRC->getIntroductionLoc(), diag::availability_query_useless_enclosing_scope_here); } @@ -535,8 +556,11 @@ class TypeRefinementContextBuilder : private ASTWalker { /// Return the best active spec for the target platform or nullptr if no /// such spec exists. - AvailabilitySpec *bestActiveSpecForQuery(PoundAvailableInfo *available) { + AvailabilitySpec *bestActiveSpecForQuery(PoundAvailableInfo *available, + bool forTargetVariant = false) { OtherPlatformAvailabilitySpec *FoundOtherSpec = nullptr; + PlatformVersionConstraintAvailabilitySpec *BestSpec = nullptr; + for (auto *Spec : available->getQueries()) { if (auto *OtherSpec = dyn_cast(Spec)) { FoundOtherSpec = OtherSpec; @@ -551,11 +575,19 @@ class TypeRefinementContextBuilder : private ASTWalker { // properly. For example, on the OSXApplicationExtension platform // we want to chose the OS X spec unless there is an explicit // OSXApplicationExtension spec. - if (isPlatformActive(VersionSpec->getPlatform(), Context.LangOpts)) { - return VersionSpec; + if (isPlatformActive(VersionSpec->getPlatform(), Context.LangOpts, + forTargetVariant)) { + if (!BestSpec || + inheritsAvailabilityFromPlatform(VersionSpec->getPlatform(), + BestSpec->getPlatform())) { + BestSpec = VersionSpec; + } } } + if (BestSpec) + return BestSpec; + // If we have reached this point, we found no spec for our target, so // we return the other spec ('*'), if we found it, or nullptr, if not. return FoundOtherSpec; diff --git a/lib/SymbolGraphGen/Symbol.cpp b/lib/SymbolGraphGen/Symbol.cpp index 441a636454051..c30210d75a1e1 100644 --- a/lib/SymbolGraphGen/Symbol.cpp +++ b/lib/SymbolGraphGen/Symbol.cpp @@ -292,6 +292,8 @@ Symbol::getDomain(PlatformAgnosticAvailabilityKind AgnosticKind, switch (Kind) { case swift::PlatformKind::iOS: return { "iOS" }; + case swift::PlatformKind::macCatalyst: + return { "macCatalyst" }; case swift::PlatformKind::OSX: return { "macOS" }; case swift::PlatformKind::tvOS: @@ -300,6 +302,8 @@ Symbol::getDomain(PlatformAgnosticAvailabilityKind AgnosticKind, return { "watchOS" }; case swift::PlatformKind::iOSApplicationExtension: return { "iOSAppExtension" }; + case swift::PlatformKind::macCatalystApplicationExtension: + return { "macCatalystAppExtension" }; case swift::PlatformKind::OSXApplicationExtension: return { "macOSAppExtension" }; case swift::PlatformKind::tvOSApplicationExtension: diff --git a/lib/TBDGen/TBDGen.cpp b/lib/TBDGen/TBDGen.cpp index 8f351d4ee1dff..675c9d2a3faea 100644 --- a/lib/TBDGen/TBDGen.cpp +++ b/lib/TBDGen/TBDGen.cpp @@ -253,6 +253,9 @@ getLinkerPlatformId(OriginallyDefinedInAttr::ActiveVersion Ver) { case swift::PlatformKind::OSX: case swift::PlatformKind::OSXApplicationExtension: return LinkerPlatformId::macOS; + case swift::PlatformKind::macCatalyst: + case swift::PlatformKind::macCatalystApplicationExtension: + return LinkerPlatformId::macCatalyst; } } diff --git a/test/IDE/complete_decl_attribute.swift b/test/IDE/complete_decl_attribute.swift index e6528dbb15489..9ab5063a1707b 100644 --- a/test/IDE/complete_decl_attribute.swift +++ b/test/IDE/complete_decl_attribute.swift @@ -37,6 +37,8 @@ struct MyStruct {} // AVAILABILITY1-NEXT: Keyword/None: tvOSApplicationExtension[#Platform#]; name=tvOSApplicationExtension{{$}} // AVAILABILITY1-NEXT: Keyword/None: watchOSApplicationExtension[#Platform#]; name=watchOSApplicationExtension{{$}} // AVAILABILITY1-NEXT: Keyword/None: OSXApplicationExtension[#Platform#]; name=OSXApplicationExtension{{$}} +// AVAILABILITY1-NEXT: Keyword/None: macCatalyst[#Platform#]; name=macCatalyst +// AVAILABILITY1-NEXT: Keyword/None: macCatalystApplicationExtension[#Platform#]; name=macCatalystApplicationExtension // AVAILABILITY1-NEXT: End completions @available(*, #^AVAILABILITY2^#) diff --git a/test/attr/attr_availability_maccatalyst.swift b/test/attr/attr_availability_maccatalyst.swift new file mode 100644 index 0000000000000..3c3bf676f1c8b --- /dev/null +++ b/test/attr/attr_availability_maccatalyst.swift @@ -0,0 +1,125 @@ +// RUN: %swift -typecheck -verify -parse-stdlib -target x86_64-apple-ios51.0-macabi %s + +// REQUIRES: OS=maccatalyst + +@available(macCatalyst, introduced: 1.0, deprecated: 2.0, obsoleted: 9.0, + message: "you don't want to do that anyway") +func obsoletedOnMacCatalyst() { } +// expected-note @-1{{'obsoletedOnMacCatalyst()' was obsoleted in Mac Catalyst 9.0}} + +obsoletedOnMacCatalyst() // expected-error{{'obsoletedOnMacCatalyst()' is unavailable in Mac Catalyst: you don't want to do that anyway}} + +@available(iOS, introduced: 1.0, deprecated: 2.0, obsoleted: 9.0, + message: "you don't want to do that anyway") +func obsoletedOnIOS() { } +// expected-note @-1{{'obsoletedOnIOS()' was obsoleted in iOS 9.0}} + +obsoletedOnIOS() // expected-error{{'obsoletedOnIOS()' is unavailable in iOS: you don't want to do that anyway}} + + +@available(iOS, introduced: 1.0) +@available(macCatalyst, introduced: 1.0, obsoleted: 12.0) +func obsoletedOnMacCatalystButNotIOS() { } +// expected-note @-1{{'obsoletedOnMacCatalystButNotIOS()' was obsoleted in Mac Catalyst 12.0}} + +obsoletedOnMacCatalystButNotIOS() // expected-error {{'obsoletedOnMacCatalystButNotIOS()' is unavailable}} + + +@available(iOS, introduced: 12.0, obsoleted: 12.0) +@available(macCatalyst, introduced: 12.0) +func obsoletedOnIOSButNotMacCatalyst() { } +obsoletedOnIOSButNotMacCatalyst() // no-error + + + +@available(iOS, introduced: 1.0) +@available(macCatalyst, introduced: 1.0, deprecated: 12.0) +func deprecatedOnMacCatalystButNotIOS() { } + +deprecatedOnMacCatalystButNotIOS() // expected-warning {{deprecatedOnMacCatalystButNotIOS()' was deprecated in Mac Catalyst 12.0}} + +@available(iOS, introduced: 12.0, deprecated: 13.0) +@available(macCatalyst, introduced: 12.0) +func deprecatedOnIOSButNotMacCatalyst() { } +deprecatedOnIOSButNotMacCatalyst() // no-warning + + +@available(iOS 55.0, macCatalyst 56.0, *) +func introducedLaterOnMacCatalyst() { +} + +// expected-note@+1 *{{add @available attribute to enclosing global function}} +func testPoundAvailable() { + + if #available(macCatalyst 55.0, *) { + introducedLaterOnMacCatalyst() // expected-error {{'introducedLaterOnMacCatalyst()' is only available in Mac Catalyst 56.0 or newer}} + // expected-note@-1 {{add 'if #available' version check}} + } + + // macCatalyst should win over iOS when present + + if #available(iOS 56.0, macCatalyst 55.0, *) { + introducedLaterOnMacCatalyst() // expected-error {{'introducedLaterOnMacCatalyst()' is only available in Mac Catalyst 56.0 or newer}} + // expected-note@-1 {{add 'if #available' version check}} + } + + if #available(iOS 55.0, macCatalyst 56.0, *) { + introducedLaterOnMacCatalyst() // no-warning + } + + // iOS availability should be inherited when macCatalyst is not present + + if #available(iOS 55.0, *) { + introducedLaterOnMacCatalyst() // expected-error {{'introducedLaterOnMacCatalyst()' is only available in Mac Catalyst 56.0 or newer}} + // expected-note@-1 {{add 'if #available' version check}} + } + + if #available(iOS 56.0, *) { + introducedLaterOnMacCatalyst() // no-warning + } + + // macOS availability doesn't count on macCatalyst for Swift. + if #available(macOS 9999.0, *) { + introducedLaterOnMacCatalyst() // expected-error {{'introducedLaterOnMacCatalyst()' is only available in Mac Catalyst 56.0 or newer}} + // expected-note@-1 {{add 'if #available' version check}} + } +} + +@available(iOS 55.0, *) +func testUnnecessaryPoundAvailable() { // expected-note*{{enclosing scope here}} + + // Even though we're compiling for macCatalyst, the #available is expressed in terms of + // 'iOS', so we should use that to report to the user in the diagnostic. + if #available(iOS 54.0, *) { + // expected-warning@-1 {{unnecessary check for 'iOS'; enclosing scope ensures guard will always be true}} + } + + if #available(macCatalyst 54.0, *) { + // expected-warning@-1 {{unnecessary check for 'macCatalyst'; enclosing scope ensures guard will always be true}} + } + + if #available(macCatalyst 54.0, iOS 53.0, *) { + // expected-warning@-1 {{unnecessary check for 'macCatalyst'; enclosing scope ensures guard will always be true}} + } + + if #available(iOS 53.0, macCatalyst 54.0, *) { + // expected-warning@-1 {{unnecessary check for 'macCatalyst'; enclosing scope ensures guard will always be true}} + } +} + +// Test that we don't accidentally try to validate @available(iOS, ...) attrs +// on accessors against the property's @available(macCatalyst, ...) attr. +// (rdar://problem/50067784) +class X { + @available(iOS 3.2, macCatalyst 13, *) + var x: X { + get { return self } + set { } + } +} + +protocol P: Builtin.AnyObject { + var x: X { get set } +} + +extension X: P {} diff --git a/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp b/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp index 9ed275a1d1a87..9e7616216ddab 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftDocSupport.cpp @@ -584,10 +584,12 @@ static void reportAttributes(ASTContext &Ctx, DocInfoConsumer &Consumer) { static UIdent AvailableAttrKind("source.lang.swift.attribute.availability"); static UIdent PlatformIOS("source.availability.platform.ios"); + static UIdent PlatformMacCatalyst("source.availability.platform.maccatalyst"); static UIdent PlatformOSX("source.availability.platform.osx"); static UIdent PlatformtvOS("source.availability.platform.tvos"); static UIdent PlatformWatchOS("source.availability.platform.watchos"); static UIdent PlatformIOSAppExt("source.availability.platform.ios_app_extension"); + static UIdent PlatformMacCatalystAppExt("source.availability.platform.maccatalyst_app_extension"); static UIdent PlatformOSXAppExt("source.availability.platform.osx_app_extension"); static UIdent PlatformtvOSAppExt("source.availability.platform.tvos_app_extension"); static UIdent PlatformWatchOSAppExt("source.availability.platform.watchos_app_extension"); @@ -601,6 +603,8 @@ static void reportAttributes(ASTContext &Ctx, PlatformUID = UIdent(); break; case PlatformKind::iOS: PlatformUID = PlatformIOS; break; + case PlatformKind::macCatalyst: + PlatformUID = PlatformIOS; break; case PlatformKind::OSX: PlatformUID = PlatformOSX; break; case PlatformKind::tvOS: @@ -609,6 +613,8 @@ static void reportAttributes(ASTContext &Ctx, PlatformUID = PlatformWatchOS; break; case PlatformKind::iOSApplicationExtension: PlatformUID = PlatformIOSAppExt; break; + case PlatformKind::macCatalystApplicationExtension: + PlatformUID = PlatformMacCatalystAppExt; break; case PlatformKind::OSXApplicationExtension: PlatformUID = PlatformOSXAppExt; break; case PlatformKind::tvOSApplicationExtension: From 9b4a89026234aa21f91b05685203df7832bd7104 Mon Sep 17 00:00:00 2001 From: Devin Coughlin Date: Tue, 7 Jan 2020 21:14:00 -0800 Subject: [PATCH 6/6] [Utils] Attempt to appease python_lint --- utils/build-script | 5 +++-- utils/build_swift/build_swift/driver_arguments.py | 3 ++- .../host_specific_configuration.py | 13 ++++++++----- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/utils/build-script b/utils/build-script index 0edc849f72d51..1ee9d8c455d09 100755 --- a/utils/build-script +++ b/utils/build-script @@ -598,9 +598,10 @@ class BuildScriptInvocation(object): # Enable macCatalyst if args.maccatalyst: - args.extra_cmake_options.append('-DSWIFT_ENABLE_MACCATALYST:BOOL=TRUE') + (args.extra_cmake_options + .append('-DSWIFT_ENABLE_MACCATALYST:BOOL=TRUE')) if args.maccatalyst_ios_tests: - impl_args += [ "--darwin-test-maccatalyst-ios-like=1" ] + impl_args += ["--darwin-test-maccatalyst-ios-like=1"] # If we have extra_cmake_options, combine all of them together and then # add them as one command. diff --git a/utils/build_swift/build_swift/driver_arguments.py b/utils/build_swift/build_swift/driver_arguments.py index 8db50a41513a1..1f1587c5b20d0 100644 --- a/utils/build_swift/build_swift/driver_arguments.py +++ b/utils/build_swift/build_swift/driver_arguments.py @@ -339,7 +339,8 @@ def create_argument_parser(): help='Enable building Swift with macCatalyst support') option('--maccatalyst-ios-tests', toggle_true, - help='When building for macCatalyst run tests with iOS-like target triple') + help='When building for macCatalyst run tests with iOS-like ' + 'target triple') option('--android', toggle_true, help='also build for Android') diff --git a/utils/swift_build_support/swift_build_support/host_specific_configuration.py b/utils/swift_build_support/swift_build_support/host_specific_configuration.py index 9a77818cc3518..ecdb437113321 100644 --- a/utils/swift_build_support/swift_build_support/host_specific_configuration.py +++ b/utils/swift_build_support/swift_build_support/host_specific_configuration.py @@ -152,12 +152,15 @@ def __init__(self, host_target, args): # Support for running the macCatalyst tests with # the iOS-like target triple. - if name == "macosx-x86_64" and args.maccatalyst and args.maccatalyst_ios_tests: - self.swift_test_run_targets.append("check-swift{}{}-{}".format( - subset_suffix, suffix, "macosx-maccatalyst-x86_64")) + if name == "macosx-x86_64" and args.maccatalyst \ + and args.maccatalyst_ios_tests: + (self.swift_test_run_targets + .append("check-swift{}{}-{}".format( + subset_suffix, suffix, "macosx-maccatalyst-x86_64"))) else: - self.swift_test_run_targets.append("check-swift{}{}-{}".format( - subset_suffix, suffix, name)) + (self.swift_test_run_targets + .append("check-swift{}{}-{}".format( + subset_suffix, suffix, name))) if args.test_optimized and not test_host_only: self.swift_test_run_targets.append( "check-swift{}-optimize-{}".format(