From 18ed861715b034ed4f8bcb51b23496d4432b26ce Mon Sep 17 00:00:00 2001 From: Evan Wilde Date: Tue, 20 Aug 2024 10:11:36 -0700 Subject: [PATCH] CMake: Fixing cross-compiling Swift-Foundation 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. --- Sources/CMakeLists.txt | 32 ++++++++++++++++++++ Sources/FoundationEssentials/CMakeLists.txt | 24 +-------------- Sources/FoundationMacros/CMakeLists.txt | 19 ++++++------ cmake/modules/CMakeLists.txt | 1 + cmake/modules/SwiftFoundationConfig.cmake.in | 1 + 5 files changed, 45 insertions(+), 32 deletions(-) diff --git a/Sources/CMakeLists.txt b/Sources/CMakeLists.txt index ef235c43f..0c7af685c 100644 --- a/Sources/CMakeLists.txt +++ b/Sources/CMakeLists.txt @@ -12,6 +12,38 @@ ## ##===----------------------------------------------------------------------===## +add_library(FoundationBuildMacros INTERFACE) +export(TARGETS FoundationBuildMacros + FILE + ${SwiftFoundation_BINARY_DIR}/cmake/modules/FoundationBuildMacros.cmake) +if(SwiftFoundation_MACRO) + message(STATUS "SwiftFoundation_MACRO provided, using macros in ${SwiftFoundation_MACRO}") + target_compile_options(FoundationBuildMacros INTERFACE + "SHELL:$:-plugin-path ${SwiftFoundation_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= + -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:$:-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) diff --git a/Sources/FoundationEssentials/CMakeLists.txt b/Sources/FoundationEssentials/CMakeLists.txt index 9c1f5b462..1fc475380 100644 --- a/Sources/FoundationEssentials/CMakeLists.txt +++ b/Sources/FoundationEssentials/CMakeLists.txt @@ -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 ${SwiftFoundation_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:$<$:-load-plugin-executable ${MacroExecutable}>") -endif() - if(CMAKE_SYSTEM_NAME STREQUAL Linux OR CMAKE_SYSTEM_NAME STREQUAL Android) target_compile_options(FoundationEssentials PRIVATE "SHELL:$<$:-Xfrontend -Xcc -Xfrontend -D_GNU_SOURCE>") @@ -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}) diff --git a/Sources/FoundationMacros/CMakeLists.txt b/Sources/FoundationMacros/CMakeLists.txt index 98b90c0df..0815b5884 100644 --- a/Sources/FoundationMacros/CMakeLists.txt +++ b/Sources/FoundationMacros/CMakeLists.txt @@ -26,6 +26,9 @@ endif() project(FoundationMacros LANGUAGES Swift) +option(SwiftFoundation_BUILD_EXECUTABLE_MACROS + "Build the FoundationMacros as an executable" NO) + if(NOT SWIFT_SYSTEM_NAME) if(CMAKE_SYSTEM_NAME STREQUAL Darwin) set(SWIFT_SYSTEM_NAME macosx) @@ -49,13 +52,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. @@ -90,8 +93,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) diff --git a/cmake/modules/CMakeLists.txt b/cmake/modules/CMakeLists.txt index 996788612..2c498378e 100644 --- a/cmake/modules/CMakeLists.txt +++ b/cmake/modules/CMakeLists.txt @@ -12,6 +12,7 @@ ## ##===----------------------------------------------------------------------===## +set(SWIFT_FOUNDATION_BUILD_MACROS_FILE ${CMAKE_CURRENT_BINARY_DIR}/FoundationBuildMacros.cmake) set(SWIFT_FOUNDATION_EXPORTS_FILE ${CMAKE_CURRENT_BINARY_DIR}/SwiftFoundationExports.cmake) set(SWIFT_FOUNDATION_ICU_EXPORTS_FILE ${SwiftFoundationICU_BINARY_DIR}/cmake/modules/SwiftFoundationICUExports.cmake) set(SWIFT_COLLECTIONS_EXPORTS_FILE ${SwiftCollections_BINARY_DIR}/cmake/modules/SwiftCollectionsExports.cmake) diff --git a/cmake/modules/SwiftFoundationConfig.cmake.in b/cmake/modules/SwiftFoundationConfig.cmake.in index 1692f34ca..ad5bff33d 100644 --- a/cmake/modules/SwiftFoundationConfig.cmake.in +++ b/cmake/modules/SwiftFoundationConfig.cmake.in @@ -13,6 +13,7 @@ ##===----------------------------------------------------------------------===## if(NOT TARGET SwiftFoundation) + include(@SWIFT_FOUNDATION_BUILD_MACROS_FILE@) include(@SWIFT_FOUNDATION_ICU_EXPORTS_FILE@) include(@SWIFT_COLLECTIONS_EXPORTS_FILE@) include(@SWIFT_FOUNDATION_EXPORTS_FILE@)