diff --git a/CMakeLists.txt b/CMakeLists.txt index 15fe3c1f0..ef465083a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,8 @@ endif() project(SwiftTesting LANGUAGES CXX Swift) +include(GNUInstallDirs) + list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules ${PROJECT_SOURCE_DIR}/cmake/modules/shared) @@ -28,4 +30,12 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_Swift_LANGUAGE_VERSION 6) set(CMAKE_Swift_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/swift) +if(NOT SWIFT_SYSTEM_NAME) + if(CMAKE_SYSTEM_NAME STREQUAL Darwin) + set(SWIFT_SYSTEM_NAME macosx) + else() + set(SWIFT_SYSTEM_NAME "$") + endif() +endif() + add_subdirectory(Sources) diff --git a/Sources/CMakeLists.txt b/Sources/CMakeLists.txt index b9828e5da..6b55259bf 100644 --- a/Sources/CMakeLists.txt +++ b/Sources/CMakeLists.txt @@ -6,28 +6,100 @@ # See http://swift.org/LICENSE.txt for license information # See http://swift.org/CONTRIBUTORS.txt for Swift project authors -# Macros must be built for the build machine, not the host. -include(ExternalProject) -if(NOT SwiftTesting_MACRO_MAKE_PROGRAM) - set(SwiftTesting_MACRO_MAKE_PROGRAM ${CMAKE_MAKE_PROGRAM}) -endif() +set(SwiftTesting_MACRO "" CACHE STRING + "Path to SwiftTesting macro plugin, or '' for automatically building it") + +if(SwiftTesting_MACRO STREQUAL "") + # Macros must be built for the build machine, not the host. + include(ExternalProject) + if(NOT SwiftTesting_MACRO_MAKE_PROGRAM) + set(SwiftTesting_MACRO_MAKE_PROGRAM ${CMAKE_MAKE_PROGRAM}) + endif() + if(NOT SwiftTesting_MACRO_Swift_COMPILER) + set(SwiftTesting_MACRO_Swift_COMPILER ${CMAKE_Swift_COMPILER}) + endif() + if(NOT SwiftTesting_MACRO_Swift_FLAGS) + set(SwiftTesting_MACRO_Swift_FLAGS ${CMAKE_Swift_FLAGS}) + set(SwiftTesting_MACRO_SWIFT_FLAGS_RELEASE ${CMAKE_Swift_FLAGS_RELEASE}) + set(SwiftTesting_MACRO_SWIFT_FLAGS_RELWITHDEBINFO ${CMAKE_Swift_FLAGS_RELWITHDEBINFO}) + endif() + if(NOT SwiftTesting_MACRO_AR) + set(SwiftTesting_MACRO_AR ${CMAKE_AR}) + endif() + if(NOT SwiftTesting_MACRO_RANLIB) + set(SwiftTesting_MACRO_RANLIB ${CMAKE_RANLIB}) + endif() + if(NOT SwiftTesting_MACRO_BUILD_TYPE) + set(SwiftTesting_MACRO_BUILD_TYPE ${CMAKE_BUILD_TYPE}) + endif() + + find_package(SwiftSyntax CONFIG GLOBAL) + if(SwiftSyntax_FOUND) + set(SwiftTesting_BuildMacrosAsExecutables NO) + else() + set(SwiftTesting_BuildMacrosAsExecutables YES) + endif() -find_package(SwiftSyntax CONFIG GLOBAL) -if(SwiftSyntax_FOUND) - set(SwiftTesting_BuildMacrosAsExecutables NO) + # Build and install the plugin into the current build directry. + set(SwiftTesting_MACRO_INSTALL_PREFIX "${CMAKE_BINARY_DIR}") + + ExternalProject_Add(TestingMacros + PREFIX "tm" + SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/TestingMacros" + BUILD_ALWAYS ON + CMAKE_ARGS + -DCMAKE_MAKE_PROGRAM=${SwiftTesting_MACRO_MAKE_PROGRAM} + -DCMAKE_Swift_COMPILER=${SwiftTesting_MACRO_Swift_COMPILER} + -DCMAKE_Swift_FLAGS=${SwiftTesting_MACRO_Swift_FLAGS} + -DCMAKE_Swift_FLAGS_RELEASE=${SwiftTesting_MACRO_Swift_FLAGS_RELEASE} + -DCMAKE_Swift_FLAGS_RELWITHDEBINFO=${SwiftTesting_MACRO_Swift_FLAGS_RELWITHDEBINFO} + -DCMAKE_AR=${SwiftTesting_MACRO_AR} + -DCMAKE_RANLIB=${SwiftTesting_MACRO_RANLIB} + -DCMAKE_BUILD_TYPE=${CSwiftTesting_MACRO_BUILD_TYPE} + -DSwiftTesting_BuildMacrosAsExecutables=${SwiftTesting_BuildMacrosAsExecutables} + -DSwiftSyntax_DIR=${SwiftSyntax_DIR} + -DCMAKE_INSTALL_PREFIX=${SwiftTesting_MACRO_INSTALL_PREFIX}) + + # Hardcode the known file names based on system name as a workaround since + # TestingMacros uses `ExternalProject` and we cannot directly query the + # properties of its targets here. + if(NOT SwiftTesting_BuildMacrosAsExecutables) + if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") + set(SwiftTesting_MACRO_PATH "${SwiftTesting_MACRO_INSTALL_PREFIX}/lib/swift/host/plugins/testing/libTestingMacros.dylib") + elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") + set(SwiftTesting_MACRO_PATH "${SwiftTesting_MACRO_INSTALL_PREFIX}/lib/swift/host/plugins/libTestingMacros.so") + elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") + set(SwiftTesting_MACRO_PATH "${SwiftTesting_MACRO_INSTALL_PREFIX}/bin/TestingMacros.dll") + else() + message(FATAL_ERROR "Unable to determine the library name for TestingMacros based on system name: ${CMAKE_HOST_SYSTEM_NAME}") + endif() + else() + if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") + set(SwiftTesting_MACRO_PATH "${SwiftTesting_MACRO_INSTALL_PREFIX}/bin/TestingMacros.exe") + else() + set(SwiftTesting_MACRO_PATH "${SwiftTesting_MACRO_INSTALL_PREFIX}/bin/TestingMacros") + endif() + endif() +elseif(SwiftTesting_MACRO) + # Use the passed-in plugin path. + set(SwiftTesting_MACRO_PATH "${SwiftTesting_MACRO}") + add_custom_target(TestingMacros DEPENDS "${SwiftTesting_MACRO_PATH}") else() - set(SwiftTesting_BuildMacrosAsExecutables YES) + # If it's explicitly "NO", do not compile the library with macros. + add_custom_target(TestingMacros) endif() -ExternalProject_Add(TestingMacros - PREFIX "tm" - SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/TestingMacros" - CMAKE_ARGS - -DCMAKE_MAKE_PROGRAM=${SwiftTesting_MACRO_MAKE_PROGRAM} - -DSwiftTesting_BuildMacrosAsExecutables=${SwiftTesting_BuildMacrosAsExecutables} - -DSwiftSyntax_DIR=${SwiftSyntax_DIR} - INSTALL_COMMAND "") -ExternalProject_Get_Property(TestingMacros BINARY_DIR) +if(NOT SwiftTesting_MACRO_PATH) + message(STATUS "TestingMacros: (none)") +elseif(SwiftTesting_MACRO_PATH) + if(SwiftTesting_MACRO_PATH MATCHES [[\.(dylib|so|dll)$]]) + message(STATUS "TestingMacros: ${SwiftTesting_MACRO_PATH} (shared library)") + add_compile_options("$<$:SHELL:-load-plugin-library ${SwiftTesting_MACRO_PATH}>") + else() + message(STATUS "TestingMacros: ${SwiftTesting_MACRO_PATH} (executable)") + add_compile_options("$<$:SHELL:-load-plugin-exectuable ${SwiftTesting_MACRO_PATH}#TestingMacros>") + endif() +endif() include(AvailabilityDefinitions) include(CompilerSettings) diff --git a/Sources/Testing/CMakeLists.txt b/Sources/Testing/CMakeLists.txt index 2a0c4014b..573f198a9 100644 --- a/Sources/Testing/CMakeLists.txt +++ b/Sources/Testing/CMakeLists.txt @@ -97,16 +97,8 @@ target_link_libraries(Testing PRIVATE add_dependencies(Testing TestingMacros) target_compile_options(Testing PRIVATE - -enable-library-evolution) + -enable-library-evolution + -emit-module-interface -emit-module-interface-path $/Testing.swiftinterface) -if(SwiftTesting_BuildMacrosAsExecutables) - if(CMAKE_HOST_WIN32) - set(_TestingMacros_ExecutableSuffix ".exe") - endif() - - target_compile_options(Testing PUBLIC - "SHELL:$<$:-load-plugin-executable ${BINARY_DIR}/TestingMacros${_TestingMacros_ExecutableSuffix}#TestingMacros>") -else() - target_compile_options(Testing PUBLIC - "SHELL:$<$:-plugin-path ${BINARY_DIR}>") -endif() +include(SwiftModuleInstallation) +_swift_testing_install_target(Testing) diff --git a/Sources/TestingMacros/CMakeLists.txt b/Sources/TestingMacros/CMakeLists.txt index d4a40a886..616a5c3f3 100644 --- a/Sources/TestingMacros/CMakeLists.txt +++ b/Sources/TestingMacros/CMakeLists.txt @@ -58,6 +58,22 @@ if(SwiftTesting_BuildMacrosAsExecutables) target_compile_definitions(TestingMacros PRIVATE SWT_NO_LIBRARY_MACRO_PLUGINS) else() add_library(TestingMacros SHARED) + + target_link_options(TestingMacros PRIVATE "-no-toolchain-stdlib-rpath") + # Not setting RPATH means it requires all the dependencies are already loaded + # in the process, because 'plugin' directory wouldn't contain any dependencies. + set_property(TARGET TestingMacros PROPERTY INSTALL_RPATH) + set_property(TARGET TestingMacros PROPERTY BUILD_WITH_INSTALL_RPATH YES) + + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + set(plugin_destination_dir "lib/swift/host/plugins/testing") + else() + set(plugin_destination_dir "lib/swift/host/plugins") + endif() + + install(TARGETS TestingMacros + LIBRARY DESTINATION "${plugin_destination_dir}" + RUNTIME DESTINATION bin) endif() target_sources(TestingMacros PRIVATE diff --git a/Sources/_TestingInternals/CMakeLists.txt b/Sources/_TestingInternals/CMakeLists.txt index 148e89fa4..42c27932e 100644 --- a/Sources/_TestingInternals/CMakeLists.txt +++ b/Sources/_TestingInternals/CMakeLists.txt @@ -6,6 +6,8 @@ # See http://swift.org/LICENSE.txt for license information # See http://swift.org/CONTRIBUTORS.txt for Swift project authors +set(CMAKE_CXX_SCAN_FOR_MODULES 0) + include(LibraryVersion) add_library(_TestingInternals STATIC Discovery.cpp diff --git a/cmake/modules/SwiftModuleInstallation.cmake b/cmake/modules/SwiftModuleInstallation.cmake new file mode 100644 index 000000000..65c9f3c14 --- /dev/null +++ b/cmake/modules/SwiftModuleInstallation.cmake @@ -0,0 +1,80 @@ +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2024 Apple Inc. and the Swift project authors +# Licensed under Apache License v2.0 with Runtime Library Exception +# +# See http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for Swift project authors + +# Returns the os name in a variable +# +# Usage: +# get_swift_host_os(result_var_name) +# +# +# Sets ${result_var_name} with the converted OS name derived from +# CMAKE_SYSTEM_NAME. +function(get_swift_host_os result_var_name) + set(${result_var_name} ${SWIFT_SYSTEM_NAME} PARENT_SCOPE) +endfunction() + +function(_swift_testing_install_target module) + get_swift_host_os(swift_os) + get_target_property(type ${module} TYPE) + + if(type STREQUAL STATIC_LIBRARY) + set(swift swift_static) + else() + set(swift swift) + endif() + + target_compile_options(Testing PRIVATE "-no-toolchain-stdlib-rpath") + + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + set(lib_destination_dir "lib/${swift}/${swift_os}/testing") + set_property(TARGET ${module} PROPERTY + INSTALL_RPATH "@loader_path/..") + else() + set(lib_destination_dir "lib/${swift}/${swift_os}") + set_property(TARGET ${module} PROPERTY + INSTALL_RPATH "$ORIGIN") + endif() + + install(TARGETS ${module} + ARCHIVE DESTINATION "${lib_destination_dir}" + LIBRARY DESTINATION "${lib_destination_dir}" + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + if(type STREQUAL EXECUTABLE) + return() + endif() + + get_target_property(module_name ${module} Swift_MODULE_NAME) + if(NOT module_name) + set(module_name ${module}) + endif() + + if(NOT SwiftTesting_MODULE_TRIPLE) + set(module_triple_command "${CMAKE_Swift_COMPILER}" -print-target-info) + if(CMAKE_Swift_COMPILER_TARGET) + list(APPEND module_triple_command -target ${CMAKE_Swift_COMPILER_TARGET}) + endif() + execute_process(COMMAND ${module_triple_command} OUTPUT_VARIABLE target_info_json) + string(JSON module_triple GET "${target_info_json}" "target" "moduleTriple") + set(SwiftTesting_MODULE_TRIPLE "${module_triple}" CACHE STRING "swift module triple used for installed swiftmodule and swiftinterface files") + mark_as_advanced(SwiftTesting_MODULE_TRIPLE) + endif() + + set(module_dir "${lib_destination_dir}/${module_name}.swiftmodule") + install(FILES $/${module_name}.swiftdoc + DESTINATION "${module_dir}" + RENAME ${SwiftTesting_MODULE_TRIPLE}.swiftdoc) + install(FILES $/${module_name}.swiftmodule + DESTINATION "${module_dir}" + RENAME ${SwiftTesting_MODULE_TRIPLE}.swiftmodule) + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + # Only Darwin has stable ABI. + install(FILES $/${module_name}.swiftinterface + DESTINATION "${module_dir}" + RENAME ${SwiftTesting_MODULE_TRIPLE}.swiftinterface) + endif() +endfunction()