cmake_minimum_required(VERSION 3.29)
# TODO before requiring CMake 4.1 or later
# and/or enforcing CMP0195, please check/update
# the implementation  of `emit_swift_interface`
# in `EmitSwiftInterface.cmake`
# to ensure it keeps laying down nested swiftmodule folders

list(APPEND CMAKE_MODULE_PATH
  "${CMAKE_SOURCE_DIR}/../cmake/modules"
  "${CMAKE_SOURCE_DIR}/../../cmake/modules")

include(LanguageVersions)
include(SwiftProjectVersion)
project(SwiftSynchronization
  LANGUAGES Swift
  VERSION ${SWIFT_RUNTIME_VERSION})

# FIXME(compnerd) this is a workaround for `GNUInstallDirs` which cannot be used
# with a pure Swift project.
enable_language(C)

# FIXME(compnerd) this is a compatibility shim for CMake <3.31.
if(CMAKE_VERSION VERSION_LESS 3.31)
  if(CMAKE_SYSTEM_NAME STREQUAL "Generic" AND CMAKE_SYSTEM_PROCESSOR MATCHES "wasm32")
    set(CMAKE_SYSTEM_NAME WASI)
    set(WASI 1)
  endif()
endif()

if(NOT PROJECT_IS_TOP_LEVEL)
  message(SEND_ERROR "Swift Synchronization must build as a standalone project")
endif()

set(CMAKE_POSITION_INDEPENDENT_CODE YES)

set(${PROJECT_NAME}_SWIFTC_SOURCE_DIR
  "${PROJECT_SOURCE_DIR}/../../../"
  CACHE FILEPATH "Path to the root source directory of the Swift compiler")

# Hook point for vendor-specific extensions to the build system
# Allowed extension points:
#   - DefaultSettings.cmake
#   - Settings.cmake
set(${PROJECT_NAME}_VENDOR_MODULE_DIR "${CMAKE_SOURCE_DIR}/../cmake/modules/vendor"
  CACHE FILEPATH "Location for private build system extension")

find_package(SwiftCore REQUIRED)
find_package(SwiftOverlay)

include(GNUInstallDirs)

include(AvailabilityMacros)
include(EmitSwiftInterface)
include(InstallSwiftInterface)
include(PlatformInfo)
include(gyb)
include(ResourceEmbedding)
include(CatalystSupport)

option(${PROJECT_NAME}_INSTALL_NESTED_SUBDIR "Install libraries under a platform and architecture subdirectory" ON)
set(${PROJECT_NAME}_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}/swift$<$<NOT:$<BOOL:${BUILD_SHARED_LIBS}>>:_static>$<$<BOOL:${${PROJECT_NAME}_INSTALL_NESTED_SUBDIR}>:/${${PROJECT_NAME}_PLATFORM_SUBDIR}/${${PROJECT_NAME}_ARCH_SUBDIR}>" CACHE STRING "")
set(${PROJECT_NAME}_INSTALL_SWIFTMODULEDIR "${CMAKE_INSTALL_LIBDIR}/swift$<$<NOT:$<BOOL:${BUILD_SHARED_LIBS}>>:_static>$<$<BOOL:${${PROJECT_NAME}_INSTALL_NESTED_SUBDIR}>:/${${PROJECT_NAME}_PLATFORM_SUBDIR}>" CACHE STRING "")

include("${${PROJECT_NAME}_VENDOR_MODULE_DIR}/Settings.cmake" OPTIONAL)

option(${PROJECT_NAME}_ENABLE_LIBRARY_EVOLUTION "Generate ABI resilient runtime libraries"
  ${SwiftCore_ENABLE_LIBRARY_EVOLUTION})

option(${PROJECT_NAME}_ENABLE_PRESPECIALIZATION "Enable generic metadata prespecialization"
  ${SwiftCore_ENABLE_PRESPECIALIZATION})

option(${PROJECT_NAME}_SINGLE_THREADED_MODE "Build Synchronization assuming it will be used in an environment with only a single thread" OFF)

add_compile_options(
  $<$<COMPILE_LANGUAGE:Swift>:-explicit-module-build>
  $<$<COMPILE_LANGUAGE:Swift>:-nostdlibimport>
  $<$<COMPILE_LANGUAGE:Swift>:-enable-builtin-module>
  $<$<COMPILE_LANGUAGE:Swift>:-strict-memory-safety>
  "$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Werror StrictMemorySafety>"
  "$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-experimental-feature SuppressedAssociatedTypesWithDefaults>"
  "$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-experimental-feature NonescapableTypes>"
  "$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-experimental-feature LifetimeDependence>"
  "$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-experimental-feature InoutLifetimeDependence>"
  "$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-experimental-feature LifetimeDependenceMutableAccessors>"
  "$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-upcoming-feature MemberImportVisibility>"
  "$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-experimental-feature RawLayout>"
  "$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-experimental-feature StaticExclusiveOnly>"
  "$<$<COMPILE_LANGUAGE:Swift>:SHELL:-enable-experimental-feature Extern>"
  "$<$<COMPILE_LANGUAGE:Swift>:SHELL:-runtime-compatibility-version none>"
  "$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xfrontend -disable-autolinking-runtime-compatibility-dynamic-replacements>"
  "$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xfrontend -disable-autolinking-runtime-compatibility-concurrency>"
  "$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xfrontend -disable-implicit-concurrency-module-import>"
  "$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xfrontend -disable-implicit-string-processing-module-import>"
  "$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xfrontend -enforce-exclusivity=unchecked>"
  "$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xfrontend -target-min-inlining-version -Xfrontend min>"
  "$<$<COMPILE_LANGUAGE:Swift>:SHELL:-Xfrontend -enable-lexical-lifetimes=false>"
  "$<$<COMPILE_LANGUAGE:Swift>:-warn-implicit-overrides>"
  "$<$<AND:$<BOOL:${${PROJECT_NAME}_ENABLE_LIBRARY_EVOLUTION}>,$<COMPILE_LANGUAGE:Swift>>:-enable-library-evolution>"
  "$<$<AND:$<BOOL:${${PROJECT_NAME}_ENABLE_PRESPECIALIZATION}>,$<COMPILE_LANGUAGE:Swift>>:SHELL:-Xfrontend -prespecialize-generic-metadata>")

find_package(SwiftSwiftDirectRuntime)

# LNK4049: symbol 'symbol' defined in 'filename.obj' is imported
# LNK4286: symbol 'symbol' defined in 'filename_1.obj' is imported by 'filename_2.obj'
# LNK4217: symbol 'symbol' defined in 'filename_1.obj' is imported by 'filename_2.obj' in function 'function'
#
# We cannot selectively filter the linker warnings as we do not use the MSVC
# frontned and `clang-cl` (and `clang`) currently do not support `/WX:nnnn`. As
# a compromise, treat all linker warnings as errors.
add_link_options($<$<PLATFORM_ID:Windows>:LINKER:/WX>)
# Ensure all symbols are fully resolved on Linux
add_link_options($<$<PLATFORM_ID:Android,Linux>:LINKER:-z,defs>)

gyb_expand(Atomics/AtomicIntegers.swift.gyb
  Atomics/AtomicIntegers.swift
  DEPENDS "${SwiftSynchronization_SWIFTC_SOURCE_DIR}/utils/SwiftAtomics.py"
)
gyb_expand(Atomics/AtomicStorage.swift.gyb
  Atomics/AtomicStorage.swift
  DEPENDS "${SwiftSynchronization_SWIFTC_SOURCE_DIR}/utils/SwiftAtomics.py"
)

add_library(swiftSynchronization
  Atomics/Atomic.swift
  Atomics/AtomicBool.swift
  Atomics/AtomicFloats.swift
  Atomics/AtomicLazyReference.swift
  Atomics/AtomicMemoryOrderings.swift
  Atomics/AtomicOptional.swift
  Atomics/AtomicPointers.swift
  Atomics/AtomicRepresentable.swift
  Atomics/WordPair.swift
  Atomics/AtomicStorage.swift
  Atomics/AtomicIntegers.swift
  Cell.swift)

# Determine Mutex definition
if(${PROJECT_NAME}_SINGLE_THREADED_MODE)
  target_sources(swiftSynchronization PRIVATE
    Mutex/MutexUnavailable.swift)
else()
  target_sources(swiftSynchronization PRIVATE
    Mutex/Mutex.swift
    # Apple Sources
    $<$<PLATFORM_ID:Darwin>:Mutex/DarwinImpl.swift>
    # Android and Linux Sources
    $<$<PLATFORM_ID:Android,Linux>:Mutex/LinuxImpl.swift>
    $<$<PLATFORM_ID:Android,Linux>:Mutex/SpinLoopHint.swift>
    # FreeBSD Sources
    $<$<PLATFORM_ID:FreeBSD>:Mutex/FreeBSDImpl.swift>
    # OpenBSD Sources
    $<$<PLATFORM_ID:OpenBSD>:Mutex/OpenBSDImpl.swift>
    # Wasm Sources
    $<$<PLATFORM_ID:WASI>:Mutex/WasmImpl.swift>
    # Windows Sources
    $<$<PLATFORM_ID:Windows>:Mutex/WindowsImpl.swift>)
endif()

set_target_properties(swiftSynchronization PROPERTIES
  Swift_MODULE_NAME Synchronization)

# FIXME: Why is this not implicitly in the interface flags?
target_include_directories(swiftSynchronization INTERFACE
  "$<$<COMPILE_LANGUAGE:Swift>:$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>$<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${SwiftCore_INSTALL_SWIFTMODULEDIR}>>")

target_link_libraries(swiftSynchronization PRIVATE
  swiftCore
  $<$<PLATFORM_ID:Android>:swiftAndroid>
  $<$<PLATFORM_ID:Darwin>:swiftDarwin>
  $<$<PLATFORM_ID:Windows>:ClangModules>
  $<$<BOOL:${SwiftSwiftDirectRuntime_FOUND}>:swiftSwiftDirectRuntime>)

if(WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL i686)
  # FIXME(#83765) `-whole-module-optimization` should not be needed. However,
  # without this, we will not properly optimize. On Windows i686 in particular,
  # we observe the formation of `__atomic_load` calls rather than the expected
  # native sequence.
  cmake_policy(GET CMP0157 _PolicyCMP0157)
  if(_PolicyCMP0157 STREQUAL NEW)
    set_target_properties(swiftSynchronization PROPERTIES
      Swift_COMPILATION_MODE wholemodule)
  else()
    target_compile_options(swiftSynchronization PRIVATE
      $<$<COMPILE_LANGUAGE:Swift>:-whole-module-optimization>)
  endif()
endif()

install(TARGETS swiftSynchronization
  EXPORT SwiftSynchronizationTargets
  COMPONENT ${PROJECT_NAME}_runtime
  ARCHIVE DESTINATION "${${PROJECT_NAME}_INSTALL_LIBDIR}"
  LIBRARY DESTINATION "${${PROJECT_NAME}_INSTALL_LIBDIR}"
  RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
emit_swift_interface(swiftSynchronization)
install_swift_interface(swiftSynchronization)

# Inter-project install info
export(EXPORT SwiftSynchronizationTargets
  FILE "cmake/SwiftSynchronization/SwiftSynchronizationTargets.cmake")
install(EXPORT SwiftSynchronizationTargets
  DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/SwiftSynchronization"
  FILE "SwiftSynchronizationTargets.cmake"
  COMPONENT SwiftSynchronizationCMake)
include(CMakePackageConfigHelpers)
configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/interface/SwiftSynchronizationConfig.cmake.in"
  "${CMAKE_CURRENT_BINARY_DIR}/cmake/SwiftSynchronization/SwiftSynchronizationConfig.cmake"
  INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/SwiftSynchronization")
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/cmake/SwiftSynchronization/SwiftSynchronizationConfigVersion.cmake"
  VERSION "${PROJECT_VERSION}"
  COMPATIBILITY ExactVersion)
install(FILES
  "${CMAKE_CURRENT_BINARY_DIR}/cmake/SwiftSynchronization/SwiftSynchronizationConfig.cmake"
  "${CMAKE_CURRENT_BINARY_DIR}/cmake/SwiftSynchronization/SwiftSynchronizationConfigVersion.cmake"
  DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/SwiftSynchronization")

# Configure plist creation for Darwin platforms.
generate_plist(swiftSynchronization "${CMAKE_PROJECT_VERSION}" swiftSynchronization)
embed_manifest(swiftSynchronization)

include("${${PROJECT_NAME}_VENDOR_MODULE_DIR}/swiftSynchronization.cmake" OPTIONAL)
