Skip to content

Commit

Permalink
CMake: Fixing cross-compiling Swift-Foundation
Browse files Browse the repository at this point in the history
The macros must build for the local machine running the build, not the
machine that Swift-Foundation will run on, in order for the build to be
able to use the macros.

To do this, the macro build must use ExternalProject, which treats the
child project as an entirely independent project. One cannot introspect
into the external project since it is configured at build time, rather
than at configure time. This is what allows the external project to
build for another platform.

The expectation is that the calling project will pull the built products
of the ExternalProject from the install location. EPs have an internal
implicit install prefix where they can install stuff to without dirtying
the building machine or installed products, so we can make use of that.
In order for that to work, the products must actually get installed
though, so we have to install the FoundationMacros, even when built as
an executable. To support that, I've exposed an option to tell the
macro build to build the macros as an executable.

On the library side, I've exposed the Foundation macros as an interface
library that only exposes the `-load-plugin-path` option needed for
picking up the macro. Linking against this interface library will load
the plugin as desired.

This results in a build that
   - can use macros, even when cross-compiling.
   - does not install the macros into the installed library, only to the
     build directory.
  • Loading branch information
etcwilde committed Aug 20, 2024
1 parent fd4788a commit fbd845a
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 32 deletions.
30 changes: 30 additions & 0 deletions Sources/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,36 @@
##
##===----------------------------------------------------------------------===##

add_library(FoundationBuildMacros INTERFACE)
export(TARGETS FoundationBuildMacros FILE FoundationBuildMacros.cmake)
if(SwiftFoudation_MACRO)
message(STATUS "SwiftFoundation_MACRO provided, using macros in ${SwiftFoundation_MACRO}")
target_compile_options(FoundationBuildMacros INTERFACE
"SHELL:$<BUILD_INTERFACE:$<$<COMPILE_LANGUAGE:Swift>:-plugin-path ${SwiftFoudation_MACRO}>>")
else()
message(STATUS "NO SwiftFoundation_MACRO, building macros from scratch")
include(ExternalProject)
# The macros are required for building Swift-Foundation. Build them for the
# build machine.
ExternalProject_Add(FoundationMacros
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/FoundationMacros"
INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/FoundationMacros"
CMAKE_ARGS
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_Swift_COMPILER=${CMAKE_Swift_COMPILER}
-DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
-DSwiftFoundation_BUILD_EXECUTABLE_MACROS=YES)
ExternalProject_Get_Property(FoundationMacros INSTALL_DIR)
add_dependencies(FoundationBuildMacros FoundationMacros)
if(CMAKE_HOST_WIN32)
set(_SwiftFoundation_HOST_EXECUTABLE_SUFFIX .exe)
endif()

target_compile_options(FoundationBuildMacros INTERFACE
"SHELL:$<BUILD_INTERFACE:$<$<COMPILE_LANGUAGE:Swift>:-load-plugin-executable ${INSTALL_DIR}/bin/FoundationMacros${_SwiftFoundation_HOST_EXECUTABLE_SUFFIX}#FoundationMacros>>")
unset(_SwiftFoundation_HOST_EXECUTABLE_SUFFIX)
endif()

add_subdirectory(_FoundationCShims)
add_subdirectory(FoundationEssentials)
add_subdirectory(FoundationInternationalization)
24 changes: 1 addition & 23 deletions Sources/FoundationEssentials/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,29 +49,6 @@ add_subdirectory(String)
add_subdirectory(TimeZone)
add_subdirectory(URL)

if(SwiftFoundation_MACRO)
message(STATUS "SwiftFoundation_MACRO provided, using macros in ${SwiftFoundation_MACRO}")
# A path to Foundation macros was provided, so we use that path
target_compile_options(FoundationEssentials PRIVATE
"SHELL:-plugin-path ${SwiftFoundation_MACRO}")
else()
message(STATUS "SwiftFoundation_MACRO not provided, building Foundation macros locally for host")
# No path to Foundation macros was provided, so we must build it ourselves
set(FoundationMacros_BuildLocalExecutable YES)
FetchContent_Declare(FoundationMacros
SOURCE_DIR ${CMAKE_SOURCE_DIR}/Sources/FoundationMacros)
FetchContent_MakeAvailable(FoundationMacros)
add_dependencies(FoundationEssentials FoundationMacros)
get_target_property(MacroDIR FoundationMacros RUNTIME_OUTPUT_DIRECTORY)
if(CMAKE_SYSTEM_NAME STREQUAL Windows)
set(MacroExecutable "${MacroDIR}/FoundationMacros.exe#FoundationMacros")
else()
set(MacroExecutable "${MacroDIR}/FoundationMacros#FoundationMacros")
endif()
target_compile_options(FoundationEssentials PUBLIC
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-load-plugin-executable ${MacroExecutable}>")
endif()

if(CMAKE_SYSTEM_NAME STREQUAL Linux OR CMAKE_SYSTEM_NAME STREQUAL Android)
target_compile_options(FoundationEssentials PRIVATE
"SHELL:$<$<COMPILE_LANGUAGE:Swift>:-Xfrontend -Xcc -Xfrontend -D_GNU_SOURCE>")
Expand All @@ -88,6 +65,7 @@ target_compile_options(FoundationEssentials PRIVATE ${_SwiftFoundation_wasi_libc
target_compile_options(FoundationEssentials PRIVATE -package-name "SwiftFoundation")

target_link_libraries(FoundationEssentials PUBLIC
FoundationBuildMacros
_FoundationCShims
_FoundationCollections)
target_link_libraries(FoundationEssentials PUBLIC ${_SwiftFoundation_wasi_libc_libraries})
Expand Down
19 changes: 10 additions & 9 deletions Sources/FoundationMacros/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ endif()
project(FoundationMacros
LANGUAGES Swift)

option(SwiftFoundation_BUILD_EXECUTABLE_MACROS
"Build the FoundationMacros as an executable" NO)

# SwiftSyntax Dependency
find_package(SwiftSyntax QUIET)
if(NOT SwiftSyntax_FOUND)
Expand All @@ -41,13 +44,13 @@ else()
message(STATUS "SwiftSyntax_DIR provided, using swift-syntax from ${SwiftSyntax_DIR}")
endif()

if(NOT FoundationMacros_BuildLocalExecutable)
add_library(FoundationMacros SHARED)
target_compile_definitions(FoundationMacros PRIVATE FOUNDATION_MACROS_LIBRARY)
else()
if(SwiftFoundation_BUILD_EXECUTABLE_MACROS)
add_executable(FoundationMacros)
target_link_libraries(FoundationMacros PUBLIC
SwiftSyntax::SwiftCompilerPlugin)
else()
add_library(FoundationMacros SHARED)
target_compile_definitions(FoundationMacros PRIVATE FOUNDATION_MACROS_LIBRARY)
endif()

# Parse the module as a library, even if it's an executable, because it uses an `@main` type to define its entry point.
Expand Down Expand Up @@ -82,8 +85,6 @@ set_target_properties(FoundationMacros PROPERTIES
INSTALL_RPATH "$ORIGIN/../../../swift/${SWIFT_SYSTEM_NAME}:$ORIGIN/.."
INSTALL_REMOVE_ENVIRONMENT_RPATH ON)

if(NOT FoundationMacros_BuildLocalExecutable)
install(TARGETS FoundationMacros
LIBRARY DESTINATION lib/swift/host/plugins
RUNTIME DESTINATION bin)
endif()
install(TARGETS FoundationMacros
LIBRARY DESTINATION lib/swift/host/plugins
RUNTIME DESTINATION bin)

0 comments on commit fbd845a

Please sign in to comment.