Skip to content

Configure CMake build to install content into toolchain #581

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Aug 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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 "$<LOWER_CASE:${CMAKE_SYSTEM_NAME}>")
endif()
endif()

add_subdirectory(Sources)
108 changes: 90 additions & 18 deletions Sources/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 "<auto>" CACHE STRING
"Path to SwiftTesting macro plugin, or '<auto>' for automatically building it")

if(SwiftTesting_MACRO STREQUAL "<auto>")
# 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})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What flags are you hoping to pull here?
This seems risky given that these flags might be for an entirely different machine than the one the macros will build for/run on.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually a leftover from when I was trying around. Let me remove this as a followup.

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("$<$<COMPILE_LANGUAGE:Swift>:SHELL:-load-plugin-library ${SwiftTesting_MACRO_PATH}>")
else()
message(STATUS "TestingMacros: ${SwiftTesting_MACRO_PATH} (executable)")
add_compile_options("$<$<COMPILE_LANGUAGE:Swift>:SHELL:-load-plugin-exectuable ${SwiftTesting_MACRO_PATH}#TestingMacros>")
endif()
endif()

include(AvailabilityDefinitions)
include(CompilerSettings)
Expand Down
16 changes: 4 additions & 12 deletions Sources/Testing/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 $<TARGET_PROPERTY:Testing,Swift_MODULE_DIRECTORY>/Testing.swiftinterface)
Copy link
Member Author

@rintaro rintaro Aug 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to stop emitting .swiftinterface unless it's macOS because .swiftinterface is not installed and useless.

(Should we stop -enable-library-evolution too?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need -enable-library-evolution to avoid folks directly linking our C++ module?


if(SwiftTesting_BuildMacrosAsExecutables)
if(CMAKE_HOST_WIN32)
set(_TestingMacros_ExecutableSuffix ".exe")
endif()

target_compile_options(Testing PUBLIC
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-load-plugin-executable ${BINARY_DIR}/TestingMacros${_TestingMacros_ExecutableSuffix}#TestingMacros>")
else()
target_compile_options(Testing PUBLIC
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-plugin-path ${BINARY_DIR}>")
endif()
include(SwiftModuleInstallation)
_swift_testing_install_target(Testing)
16 changes: 16 additions & 0 deletions Sources/TestingMacros/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should use set_target_properties to avoid calling the function twice.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know how to unset a property using set_target_properties.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it critical to change it? Or just an efficiency thing?

Copy link
Member Author

@rintaro rintaro Aug 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Efficiency and stylistic thing I think. I believe this also work,

set_target_properties(TestingMacros PROPERTIES
  INSTALL_RPATH ""
  BUILD_WITH_INSTALL_RPATH YES)

but I just wanted to clear the property. tbh, I'm not sure which is more correct. Explicit empty list ("") or clearing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you can do both with set_property

set_property(TARGET TestingMacros
    PROPERTY INSTALL_RPATH
    PROPERTY BUILD_WITH_INSTALL_RPATH YES)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Expand Down
2 changes: 2 additions & 0 deletions Sources/_TestingInternals/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
80 changes: 80 additions & 0 deletions cmake/modules/SwiftModuleInstallation.cmake
Original file line number Diff line number Diff line change
@@ -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 $<TARGET_PROPERTY:${module},Swift_MODULE_DIRECTORY>/${module_name}.swiftdoc
DESTINATION "${module_dir}"
RENAME ${SwiftTesting_MODULE_TRIPLE}.swiftdoc)
install(FILES $<TARGET_PROPERTY:${module},Swift_MODULE_DIRECTORY>/${module_name}.swiftmodule
DESTINATION "${module_dir}"
RENAME ${SwiftTesting_MODULE_TRIPLE}.swiftmodule)
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
# Only Darwin has stable ABI.
install(FILES $<TARGET_PROPERTY:${module},Swift_MODULE_DIRECTORY>/${module_name}.swiftinterface
DESTINATION "${module_dir}"
RENAME ${SwiftTesting_MODULE_TRIPLE}.swiftinterface)
endif()
endfunction()